From 22eae947bf76e236ba972f2f11cfd1b083b736ad Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 10 Nov 2005 22:16:34 +1100 Subject: drm: rename driver hooks more understandably Rename the driver hooks in the DRM to something a little more understandable: preinit -> load postinit -> (removed) presetup -> firstopen postsetup -> (removed) open_helper -> open prerelease -> preclose free_filp_priv -> postclose pretakedown -> lastclose postcleanup -> unload release -> reclaim_buffers_locked version -> (removed) postinit and version were replaced with generic code in the Linux DRM (drivers now set their version numbers and description in the driver structure, like on BSD). postsetup wasn't used at all. Fixes the savage hooks for initializing and tearing down mappings at the right times. Testing involved at least starting X, running glxgears, killing glxgears, exiting X, and repeating. Tested on: FreeBSD (g200, g400, r200, r128) Linux (r200, savage4) From: Eric Anholt Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 31 +++++++++++++--------- drivers/char/drm/drm_drv.c | 29 +++++++++++--------- drivers/char/drm/drm_fops.c | 35 +++++++++++------------- drivers/char/drm/drm_ioctl.c | 12 +++------ drivers/char/drm/drm_stub.c | 15 +++++------ drivers/char/drm/i810_dma.c | 18 ++++++++++--- drivers/char/drm/i810_drv.c | 59 +++++++++++------------------------------ drivers/char/drm/i810_drv.h | 10 ++++--- drivers/char/drm/i830_dma.c | 18 ++++++++++--- drivers/char/drm/i830_drv.c | 56 +++++++++++--------------------------- drivers/char/drm/i830_drv.h | 8 +++--- drivers/char/drm/i915_dma.c | 16 +++++++++-- drivers/char/drm/i915_drv.c | 54 +++++++++++-------------------------- drivers/char/drm/i915_drv.h | 5 ++-- drivers/char/drm/mga_dma.c | 14 +++++++--- drivers/char/drm/mga_drv.c | 56 +++++++++----------------------------- drivers/char/drm/mga_drv.h | 6 ++--- drivers/char/drm/r128_drv.c | 48 ++++++++++----------------------- drivers/char/drm/r128_drv.h | 4 +-- drivers/char/drm/r128_state.c | 4 +-- drivers/char/drm/radeon_cp.c | 9 ++++--- drivers/char/drm/radeon_drv.c | 57 +++++++++++++-------------------------- drivers/char/drm/radeon_drv.h | 17 +++++------- drivers/char/drm/radeon_state.c | 8 +++--- drivers/char/drm/savage_bci.c | 44 +++++++++++++++++++----------- drivers/char/drm/savage_drv.c | 50 +++++++++++----------------------- drivers/char/drm/savage_drv.h | 6 +++-- drivers/char/drm/sis_drv.c | 42 ++++++++--------------------- drivers/char/drm/tdfx_drv.c | 42 ++++++++--------------------- drivers/char/drm/via_drv.c | 41 ++++++++-------------------- 30 files changed, 330 insertions(+), 484 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 3dc3c9d79ae4..d842cce11448 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -544,16 +544,14 @@ typedef struct ati_pcigart_info { struct drm_device; struct drm_driver { - int (*preinit) (struct drm_device *, unsigned long flags); - void (*prerelease) (struct drm_device *, struct file * filp); - void (*pretakedown) (struct drm_device *); - int (*postcleanup) (struct drm_device *); - int (*presetup) (struct drm_device *); - int (*postsetup) (struct drm_device *); + int (*load) (struct drm_device *, unsigned long flags); + int (*firstopen) (struct drm_device *); + int (*open) (struct drm_device *, drm_file_t *); + void (*preclose) (struct drm_device *, struct file * filp); + void (*postclose) (struct drm_device *, drm_file_t *); + void (*lastclose) (struct drm_device *); + int (*unload) (struct drm_device *); int (*dma_ioctl) (DRM_IOCTL_ARGS); - int (*open_helper) (struct drm_device *, drm_file_t *); - void (*free_filp_priv) (struct drm_device *, drm_file_t *); - void (*release) (struct drm_device *, struct file * filp); void (*dma_ready) (struct drm_device *); int (*dma_quiescent) (struct drm_device *); int (*context_ctor) (struct drm_device * dev, int context); @@ -579,16 +577,25 @@ struct drm_driver { /* these have to be filled in */ - int (*postinit) (struct drm_device *, unsigned long flags); - irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); + irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); void (*irq_preinstall) (struct drm_device * dev); void (*irq_postinstall) (struct drm_device * dev); void (*irq_uninstall) (struct drm_device * dev); void (*reclaim_buffers) (struct drm_device * dev, struct file * filp); + void (*reclaim_buffers_locked) (struct drm_device *drv, + struct file *filp); unsigned long (*get_map_ofs) (drm_map_t * map); unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); int (*version) (drm_version_t * version); + + int major; + int minor; + int patchlevel; + char *name; + char *desc; + char *date; + u32 driver_features; int dev_priv_size; drm_ioctl_desc_t *ioctls; @@ -772,7 +779,7 @@ extern int drm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_takedown(drm_device_t * dev); +extern int drm_lastclose(drm_device_t *dev); /* Device support (drm_fops.h) */ extern int drm_open(struct inode *inode, struct file *filp); diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 4dff7554eb08..d8ff84bdc3e7 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -129,7 +129,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { * * \sa drm_device */ -int drm_takedown(drm_device_t * dev) +int drm_lastclose(drm_device_t * dev) { drm_magic_entry_t *pt, *next; drm_map_list_t *r_list; @@ -138,9 +138,9 @@ int drm_takedown(drm_device_t * dev) DRM_DEBUG("\n"); - if (dev->driver->pretakedown) - dev->driver->pretakedown(dev); - DRM_DEBUG("driver pretakedown completed\n"); + if (dev->driver->lastclose) + dev->driver->lastclose(dev); + DRM_DEBUG("driver lastclose completed\n"); if (dev->unique) { drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); @@ -233,7 +233,7 @@ int drm_takedown(drm_device_t * dev) } up(&dev->struct_sem); - DRM_DEBUG("takedown completed\n"); + DRM_DEBUG("lastclose completed\n"); return 0; } @@ -281,7 +281,7 @@ EXPORT_SYMBOL(drm_init); /** * Called via cleanup_module() at module unload time. * - * Cleans up all DRM device, calling takedown(). + * Cleans up all DRM device, calling drm_lastclose(). * * \sa drm_init */ @@ -294,7 +294,7 @@ static void drm_cleanup(drm_device_t * dev) return; } - drm_takedown(dev); + drm_lastclose(dev); if (dev->maplist) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); @@ -317,8 +317,8 @@ static void drm_cleanup(drm_device_t * dev) dev->agp = NULL; } - if (dev->driver->postcleanup) - dev->driver->postcleanup(dev); + if (dev->driver->unload) + dev->driver->unload(dev); drm_put_head(&dev->primary); if (drm_put_dev(dev)) @@ -432,14 +432,17 @@ static int drm_version(struct inode *inode, struct file *filp, drm_device_t *dev = priv->head->dev; drm_version_t __user *argp = (void __user *)arg; drm_version_t version; - int ret; + int len; if (copy_from_user(&version, argp, sizeof(version))) return -EFAULT; - /* version is a required function to return the personality module version */ - if ((ret = dev->driver->version(&version))) - return ret; + version.version_major = dev->driver->major; + version.version_minor = dev->driver->minor; + version.version_patchlevel = dev->driver->patchlevel; + DRM_COPY(version.name, dev->driver->name); + DRM_COPY(version.date, dev->driver->date); + DRM_COPY(version.desc, dev->driver->desc); if (copy_to_user(argp, &version, sizeof(version))) return -EFAULT; diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index bf0a740122bf..f57f7d1a281e 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -45,8 +45,8 @@ static int drm_setup(drm_device_t * dev) int i; int ret; - if (dev->driver->presetup) { - ret = dev->driver->presetup(dev); + if (dev->driver->firstopen) { + ret = dev->driver->firstopen(dev); if (ret != 0) return ret; } @@ -109,8 +109,6 @@ static int drm_setup(drm_device_t * dev) * drm_select_queue fails between the time the interrupt is * initialized and the time the queues are initialized. */ - if (dev->driver->postsetup) - dev->driver->postsetup(dev); return 0; } @@ -167,7 +165,7 @@ EXPORT_SYMBOL(drm_open); * If the hardware lock is held then free it, and take it again for the kernel * context since it's necessary to reclaim buffers. Unlink the file private * data from its list and free it. Decreases the open count and if it reaches - * zero calls takedown(). + * zero calls drm_lastclose(). */ int drm_release(struct inode *inode, struct file *filp) { @@ -180,8 +178,8 @@ int drm_release(struct inode *inode, struct file *filp) DRM_DEBUG("open_count = %d\n", dev->open_count); - if (dev->driver->prerelease) - dev->driver->prerelease(dev, filp); + if (dev->driver->preclose) + dev->driver->preclose(dev, filp); /* ======================================================== * Begin inline drm_release @@ -197,8 +195,8 @@ int drm_release(struct inode *inode, struct file *filp) DRM_DEBUG("File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - if (dev->driver->release) - dev->driver->release(dev, filp); + if (dev->driver->reclaim_buffers_locked) + dev->driver->reclaim_buffers_locked(dev, filp); drm_lock_free(dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); @@ -207,7 +205,7 @@ int drm_release(struct inode *inode, struct file *filp) hardware at this point, possibly processed via a callback to the X server. */ - } else if (dev->driver->release && priv->lock_count + } else if (dev->driver->reclaim_buffers_locked && priv->lock_count && dev->lock.hw_lock) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE(entry, current); @@ -237,15 +235,14 @@ int drm_release(struct inode *inode, struct file *filp) __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); if (!retcode) { - if (dev->driver->release) - dev->driver->release(dev, filp); + dev->driver->reclaim_buffers_locked(dev, filp); drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); } } - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) - && !dev->driver->release) { + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && + !dev->driver->reclaim_buffers_locked) { dev->driver->reclaim_buffers(dev, filp); } @@ -292,8 +289,8 @@ int drm_release(struct inode *inode, struct file *filp) } up(&dev->struct_sem); - if (dev->driver->free_filp_priv) - dev->driver->free_filp_priv(dev, priv); + if (dev->driver->postclose) + dev->driver->postclose(dev, priv); drm_free(priv, sizeof(*priv), DRM_MEM_FILES); @@ -313,7 +310,7 @@ int drm_release(struct inode *inode, struct file *filp) } spin_unlock(&dev->count_lock); unlock_kernel(); - return drm_takedown(dev); + return drm_lastclose(dev); } spin_unlock(&dev->count_lock); @@ -363,8 +360,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->authenticated = capable(CAP_SYS_ADMIN); priv->lock_count = 0; - if (dev->driver->open_helper) { - ret = dev->driver->open_helper(dev, priv); + if (dev->driver->open) { + ret = dev->driver->open(dev, priv); if (ret < 0) goto out_free; } diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c index 9b0feba6b063..a654ac17a900 100644 --- a/drivers/char/drm/drm_ioctl.c +++ b/drivers/char/drm/drm_ioctl.c @@ -325,17 +325,13 @@ int drm_setversion(DRM_IOCTL_ARGS) drm_set_version_t retv; int if_version; drm_set_version_t __user *argp = (void __user *)data; - drm_version_t version; DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv)); - memset(&version, 0, sizeof(version)); - - dev->driver->version(&version); retv.drm_di_major = DRM_IF_MAJOR; retv.drm_di_minor = DRM_IF_MINOR; - retv.drm_dd_major = version.version_major; - retv.drm_dd_minor = version.version_minor; + retv.drm_dd_major = dev->driver->major; + retv.drm_dd_minor = dev->driver->minor; DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv)); @@ -354,9 +350,9 @@ int drm_setversion(DRM_IOCTL_ARGS) } if (sv.drm_dd_major != -1) { - if (sv.drm_dd_major != version.version_major || + if (sv.drm_dd_major != dev->driver->major || sv.drm_dd_minor < 0 - || sv.drm_dd_minor > version.version_minor) + || sv.drm_dd_minor > dev->driver->minor) return EINVAL; if (dev->driver->set_version) diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 60b6f8e8bf69..8568a6b373a0 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -93,8 +93,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, dev->driver = driver; - if (dev->driver->preinit) - if ((retcode = dev->driver->preinit(dev, ent->driver_data))) + if (dev->driver->load) + if ((retcode = dev->driver->load(dev, ent->driver_data))) goto error_out_unreg; if (drm_core_has_AGP(dev)) { @@ -124,7 +124,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, return 0; error_out_unreg: - drm_takedown(dev); + drm_lastclose(dev); return retcode; } @@ -258,11 +258,10 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, } if ((ret = drm_get_head(dev, &dev->primary))) goto err_g1; - - /* postinit is a required function to display the signon banner */ - /* drivers add secondary heads here if needed */ - if ((ret = dev->driver->postinit(dev, ent->driver_data))) - goto err_g1; + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + driver->name, driver->major, driver->minor, driver->patchlevel, + driver->date, dev->primary.minor); return 0; diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index dba502373da1..c3178a89615d 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -1319,12 +1319,24 @@ static int i810_flip_bufs(struct inode *inode, struct file *filp, return 0; } -void i810_driver_pretakedown(drm_device_t * dev) +int i810_driver_load(drm_device_t *dev, unsigned long flags) +{ + /* i810 has 4 more counters */ + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + return 0; +} + +void i810_driver_lastclose(drm_device_t * dev) { i810_dma_cleanup(dev); } -void i810_driver_prerelease(drm_device_t * dev, DRMFILE filp) +void i810_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -1334,7 +1346,7 @@ void i810_driver_prerelease(drm_device_t * dev, DRMFILE filp) } } -void i810_driver_release(drm_device_t * dev, struct file *filp) +void i810_driver_reclaim_buffers_locked(drm_device_t * dev, struct file *filp) { i810_reclaim_buffers(dev, filp); } diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c index 070cef6c2b46..e73b731c3be9 100644 --- a/drivers/char/drm/i810_drv.c +++ b/drivers/char/drm/i810_drv.c @@ -38,38 +38,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - /* i810 has 4 more counters */ - dev->counters += 4; - dev->types[6] = _DRM_STAT_IRQ; - dev->types[7] = _DRM_STAT_PRIMARY; - dev->types[8] = _DRM_STAT_SECONDARY; - dev->types[9] = _DRM_STAT_DMA; - - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { i810_PCI_IDS }; @@ -79,16 +47,15 @@ static struct drm_driver driver = { DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE, .dev_priv_size = sizeof(drm_i810_buf_priv_t), - .pretakedown = i810_driver_pretakedown, - .prerelease = i810_driver_prerelease, + .load = i810_driver_load, + .lastclose = i810_driver_lastclose, + .preclose = i810_driver_preclose, .device_is_agp = i810_driver_device_is_agp, - .release = i810_driver_release, + .reclaim_buffers_locked = i810_driver_reclaim_buffers_locked, .dma_quiescent = i810_driver_dma_quiescent, .reclaim_buffers = i810_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = i810_ioctls, .fops = { .owner = THIS_MODULE, @@ -98,13 +65,19 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, - } - , + }, + .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } - , + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init i810_init(void) diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index c78f36aaa2f0..a18b80d91920 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -116,9 +116,13 @@ typedef struct drm_i810_private { extern void i810_reclaim_buffers(drm_device_t * dev, struct file *filp); extern int i810_driver_dma_quiescent(drm_device_t * dev); -extern void i810_driver_release(drm_device_t * dev, struct file *filp); -extern void i810_driver_pretakedown(drm_device_t * dev); -extern void i810_driver_prerelease(drm_device_t * dev, DRMFILE filp); +extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev, + struct file *filp); +extern int i810_driver_load(struct drm_device *, unsigned long flags); +extern void i810_driver_lastclose(drm_device_t * dev); +extern void i810_driver_preclose(drm_device_t * dev, DRMFILE filp); +extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev, + struct file *filp); extern int i810_driver_device_is_agp(drm_device_t * dev); extern drm_ioctl_desc_t i810_ioctls[]; diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index dc94f1914425..01dfdb944e1f 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -1517,12 +1517,24 @@ static int i830_setparam(struct inode *inode, struct file *filp, return 0; } -void i830_driver_pretakedown(drm_device_t * dev) +int i830_driver_load(drm_device_t *dev, unsigned long flags) +{ + /* i830 has 4 more counters */ + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + return 0; +} + +void i830_driver_lastclose(drm_device_t * dev) { i830_dma_cleanup(dev); } -void i830_driver_prerelease(drm_device_t * dev, DRMFILE filp) +void i830_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -1532,7 +1544,7 @@ void i830_driver_prerelease(drm_device_t * dev, DRMFILE filp) } } -void i830_driver_release(drm_device_t * dev, struct file *filp) +void i830_driver_reclaim_buffers_locked(drm_device_t * dev, struct file *filp) { i830_reclaim_buffers(dev, filp); } diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c index acd821e8fe4d..49fd2816de95 100644 --- a/drivers/char/drm/i830_drv.c +++ b/drivers/char/drm/i830_drv.c @@ -40,37 +40,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - dev->counters += 4; - dev->types[6] = _DRM_STAT_IRQ; - dev->types[7] = _DRM_STAT_PRIMARY; - dev->types[8] = _DRM_STAT_SECONDARY; - dev->types[9] = _DRM_STAT_DMA; - - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { i830_PCI_IDS }; @@ -83,10 +52,11 @@ static struct drm_driver driver = { .driver_features |= DRIVER_HAVE_IRQ | DRIVER_SHARED_IRQ, #endif .dev_priv_size = sizeof(drm_i830_buf_priv_t), - .pretakedown = i830_driver_pretakedown, - .prerelease = i830_driver_prerelease, + .load = i830_driver_load, + .lastclose = i830_driver_lastclose, + .preclose = i830_driver_preclose, .device_is_agp = i830_driver_device_is_agp, - .release = i830_driver_release, + .reclaim_buffers_locked = i830_driver_reclaim_buffers_locked, .dma_quiescent = i830_driver_dma_quiescent, .reclaim_buffers = i830_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, @@ -97,8 +67,6 @@ static struct drm_driver driver = { .irq_uninstall = i830_driver_irq_uninstall, .irq_handler = i830_driver_irq_handler, #endif - .postinit = postinit, - .version = version, .ioctls = i830_ioctls, .fops = { .owner = THIS_MODULE, @@ -108,13 +76,19 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, - } - , + }, + .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init i830_init(void) diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index bc4bd49fb0cc..bf9075b576bd 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -136,10 +136,12 @@ extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS); extern void i830_driver_irq_preinstall(drm_device_t * dev); extern void i830_driver_irq_postinstall(drm_device_t * dev); extern void i830_driver_irq_uninstall(drm_device_t * dev); -extern void i830_driver_pretakedown(drm_device_t * dev); -extern void i830_driver_release(drm_device_t * dev, struct file *filp); +extern int i830_driver_load(struct drm_device *, unsigned long flags); +extern void i830_driver_preclose(drm_device_t * dev, DRMFILE filp); +extern void i830_driver_lastclose(drm_device_t * dev); +extern void i830_driver_reclaim_buffers_locked(drm_device_t * dev, + struct file *filp); extern int i830_driver_dma_quiescent(drm_device_t * dev); -extern void i830_driver_prerelease(drm_device_t * dev, DRMFILE filp); extern int i830_driver_device_is_agp(drm_device_t * dev); #define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index f3aa0c370127..9ef3be31a812 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -699,7 +699,19 @@ static int i915_setparam(DRM_IOCTL_ARGS) return 0; } -void i915_driver_pretakedown(drm_device_t * dev) +int i915_driver_load(drm_device_t *dev, unsigned long flags) +{ + /* i915 has 4 more counters */ + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + return 0; +} + +void i915_driver_lastclose(drm_device_t * dev) { if (dev->dev_private) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -708,7 +720,7 @@ void i915_driver_pretakedown(drm_device_t * dev) i915_dma_cleanup(dev); } -void i915_driver_prerelease(drm_device_t * dev, DRMFILE filp) +void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_i915_private_t *dev_priv = dev->dev_private; diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 0508240f4e3b..32b7f8bb420d 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -34,37 +34,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - dev->counters += 4; - dev->types[6] = _DRM_STAT_IRQ; - dev->types[7] = _DRM_STAT_PRIMARY; - dev->types[8] = _DRM_STAT_SECONDARY; - dev->types[9] = _DRM_STAT_DMA; - - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { i915_PCI_IDS }; @@ -73,8 +42,9 @@ static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, - .pretakedown = i915_driver_pretakedown, - .prerelease = i915_driver_prerelease, + .load = i915_driver_load, + .lastclose = i915_driver_lastclose, + .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, @@ -83,8 +53,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = i915_ioctls, .fops = { .owner = THIS_MODULE, @@ -97,11 +65,19 @@ static struct drm_driver driver = { #ifdef CONFIG_COMPAT .compat_ioctl = i915_compat_ioctl, #endif - }, + }, + .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init i915_init(void) diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index 17e457c73dc7..cd4f5227d0ea 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -104,8 +104,9 @@ extern int i915_max_ioctl; /* i915_dma.c */ extern void i915_kernel_lost_context(drm_device_t * dev); -extern void i915_driver_pretakedown(drm_device_t * dev); -extern void i915_driver_prerelease(drm_device_t * dev, DRMFILE filp); +extern int i915_driver_load(struct drm_device *, unsigned long flags); +extern void i915_driver_lastclose(drm_device_t * dev); +extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); /* i915_irq.c */ diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 70dc7f64b7b9..9b09d786b158 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -391,7 +391,7 @@ int mga_freelist_put(drm_device_t * dev, drm_buf_t * buf) * DMA initialization, cleanup */ -int mga_driver_preinit(drm_device_t * dev, unsigned long flags) +int mga_driver_load(drm_device_t * dev, unsigned long flags) { drm_mga_private_t *dev_priv; @@ -405,6 +405,14 @@ int mga_driver_preinit(drm_device_t * dev, unsigned long flags) dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; dev_priv->chipset = flags; + dev_priv->mmio_base = drm_get_resource_start(dev, 1); + dev_priv->mmio_size = drm_get_resource_len(dev, 1); + + dev->counters += 3; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + return 0; } @@ -1118,7 +1126,7 @@ int mga_dma_buffers(DRM_IOCTL_ARGS) /** * Called just before the module is unloaded. */ -int mga_driver_postcleanup(drm_device_t * dev) +int mga_driver_unload(drm_device_t * dev) { drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); dev->dev_private = NULL; @@ -1129,7 +1137,7 @@ int mga_driver_postcleanup(drm_device_t * dev) /** * Called when the last opener of the device is closed. */ -void mga_driver_pretakedown(drm_device_t * dev) +void mga_driver_lastclose(drm_device_t * dev) { mga_do_cleanup_dma(dev); } diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 0cc7c305a7f6..eae2f91994ec 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -38,41 +38,6 @@ #include "drm_pciids.h" static int mga_driver_device_is_agp(drm_device_t * dev); -static int postinit(struct drm_device *dev, unsigned long flags) -{ - drm_mga_private_t *const dev_priv = - (drm_mga_private_t *) dev->dev_private; - - dev_priv->mmio_base = pci_resource_start(dev->pdev, 1); - dev_priv->mmio_size = pci_resource_len(dev->pdev, 1); - - dev->counters += 3; - dev->types[6] = _DRM_STAT_IRQ; - dev->types[7] = _DRM_STAT_PRIMARY; - dev->types[8] = _DRM_STAT_SECONDARY; - - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} static struct pci_device_id pciidlist[] = { mga_PCI_IDS @@ -83,9 +48,9 @@ static struct drm_driver driver = { DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, - .preinit = mga_driver_preinit, - .postcleanup = mga_driver_postcleanup, - .pretakedown = mga_driver_pretakedown, + .load = mga_driver_load, + .unload = mga_driver_unload, + .lastclose = mga_driver_lastclose, .dma_quiescent = mga_driver_dma_quiescent, .device_is_agp = mga_driver_device_is_agp, .vblank_wait = mga_driver_vblank_wait, @@ -96,8 +61,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = mga_ioctls, .dma_ioctl = mga_dma_buffers, .fops = { @@ -113,9 +76,16 @@ static struct drm_driver driver = { #endif }, .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init mga_init(void) diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 461728e6a58a..137bfdd5e92b 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -152,14 +152,14 @@ extern drm_ioctl_desc_t mga_ioctls[]; extern int mga_max_ioctl; /* mga_dma.c */ -extern int mga_driver_preinit(drm_device_t * dev, unsigned long flags); extern int mga_dma_bootstrap(DRM_IOCTL_ARGS); extern int mga_dma_init(DRM_IOCTL_ARGS); extern int mga_dma_flush(DRM_IOCTL_ARGS); extern int mga_dma_reset(DRM_IOCTL_ARGS); extern int mga_dma_buffers(DRM_IOCTL_ARGS); -extern int mga_driver_postcleanup(drm_device_t * dev); -extern void mga_driver_pretakedown(drm_device_t * dev); +extern int mga_driver_load(drm_device_t *dev, unsigned long flags); +extern int mga_driver_unload(drm_device_t * dev); +extern void mga_driver_lastclose(drm_device_t * dev); extern int mga_driver_dma_quiescent(drm_device_t * dev); extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv); diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index 1661e7351402..e20450ae220e 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c @@ -37,31 +37,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { r128_PCI_IDS }; @@ -72,8 +47,8 @@ static struct drm_driver driver = { DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, .dev_priv_size = sizeof(drm_r128_buf_priv_t), - .prerelease = r128_driver_prerelease, - .pretakedown = r128_driver_pretakedown, + .preclose = r128_driver_preclose, + .lastclose = r128_driver_lastclose, .vblank_wait = r128_driver_vblank_wait, .irq_preinstall = r128_driver_irq_preinstall, .irq_postinstall = r128_driver_irq_postinstall, @@ -82,8 +57,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = r128_ioctls, .dma_ioctl = r128_cce_buffers, .fops = { @@ -97,12 +70,19 @@ static struct drm_driver driver = { #ifdef CONFIG_COMPAT .compat_ioctl = r128_compat_ioctl, #endif - } - , + }, + .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init r128_init(void) diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 5c79e40eb88f..9a779bad3da3 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -154,8 +154,8 @@ extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); extern void r128_driver_irq_preinstall(drm_device_t * dev); extern void r128_driver_irq_postinstall(drm_device_t * dev); extern void r128_driver_irq_uninstall(drm_device_t * dev); -extern void r128_driver_pretakedown(drm_device_t * dev); -extern void r128_driver_prerelease(drm_device_t * dev, DRMFILE filp); +extern void r128_driver_lastclose(drm_device_t * dev); +extern void r128_driver_preclose(drm_device_t * dev, DRMFILE filp); extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 14479cc08a57..1f04e3372206 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -1674,7 +1674,7 @@ static int r128_getparam(DRM_IOCTL_ARGS) return 0; } -void r128_driver_prerelease(drm_device_t * dev, DRMFILE filp) +void r128_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -1684,7 +1684,7 @@ void r128_driver_prerelease(drm_device_t * dev, DRMFILE filp) } } -void r128_driver_pretakedown(drm_device_t * dev) +void r128_driver_lastclose(drm_device_t * dev) { r128_do_cleanup_cce(dev); } diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 03839ea31092..dc3a15a1819a 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -2103,7 +2103,7 @@ int radeon_cp_buffers(DRM_IOCTL_ARGS) return ret; } -int radeon_driver_preinit(struct drm_device *dev, unsigned long flags) +int radeon_driver_load(struct drm_device *dev, unsigned long flags) { drm_radeon_private_t *dev_priv; int ret = 0; @@ -2140,7 +2140,10 @@ int radeon_driver_preinit(struct drm_device *dev, unsigned long flags) return ret; } -int radeon_presetup(struct drm_device *dev) +/* Create mappings for registers and framebuffer so userland doesn't necessarily + * have to find them. + */ +int radeon_driver_firstopen(struct drm_device *dev) { int ret; drm_local_map_t *map; @@ -2161,7 +2164,7 @@ int radeon_presetup(struct drm_device *dev) return 0; } -int radeon_driver_postcleanup(struct drm_device *dev) +int radeon_driver_unload(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index ee49670d8162..999d74512362 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c @@ -42,30 +42,6 @@ int radeon_no_wb; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); module_param_named(no_wb, radeon_no_wb, int, 0444); -static int postinit(struct drm_device *dev, unsigned long flags) -{ - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} static struct pci_device_id pciidlist[] = { radeon_PCI_IDS @@ -77,23 +53,21 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, .dev_priv_size = sizeof(drm_radeon_buf_priv_t), - .preinit = radeon_driver_preinit, - .presetup = radeon_presetup, - .postcleanup = radeon_driver_postcleanup, - .prerelease = radeon_driver_prerelease, - .pretakedown = radeon_driver_pretakedown, - .open_helper = radeon_driver_open_helper, + .load = radeon_driver_load, + .firstopen = radeon_driver_firstopen, + .open = radeon_driver_open, + .preclose = radeon_driver_preclose, + .postclose = radeon_driver_postclose, + .lastclose = radeon_driver_lastclose, + .unload = radeon_driver_unload, .vblank_wait = radeon_driver_vblank_wait, .irq_preinstall = radeon_driver_irq_preinstall, .irq_postinstall = radeon_driver_irq_postinstall, .irq_uninstall = radeon_driver_irq_uninstall, .irq_handler = radeon_driver_irq_handler, - .free_filp_priv = radeon_driver_free_filp_priv, .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = radeon_ioctls, .dma_ioctl = radeon_cp_buffers, .fops = { @@ -107,12 +81,19 @@ static struct drm_driver driver = { #ifdef CONFIG_COMPAT .compat_ioctl = radeon_compat_ioctl, #endif - } - , + }, + .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init radeon_init(void) diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 120ee5a8ebcc..3a91d5fc597e 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -331,17 +331,14 @@ extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS); extern void radeon_driver_irq_preinstall(drm_device_t * dev); extern void radeon_driver_irq_postinstall(drm_device_t * dev); extern void radeon_driver_irq_uninstall(drm_device_t * dev); -extern void radeon_driver_prerelease(drm_device_t * dev, DRMFILE filp); -extern void radeon_driver_pretakedown(drm_device_t * dev); -extern int radeon_driver_open_helper(drm_device_t * dev, - drm_file_t * filp_priv); -extern void radeon_driver_free_filp_priv(drm_device_t * dev, - drm_file_t * filp_priv); - -extern int radeon_preinit(struct drm_device *dev, unsigned long flags); -extern int radeon_postinit(struct drm_device *dev, unsigned long flags); -extern int radeon_postcleanup(struct drm_device *dev); +extern int radeon_driver_load(struct drm_device *dev, unsigned long flags); +extern int radeon_driver_unload(struct drm_device *dev); +extern int radeon_driver_firstopen(struct drm_device *dev); +extern void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp); +extern void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp); +extern void radeon_driver_lastclose(drm_device_t * dev); +extern int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv); extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 231ac1438c69..717f546cc448 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -3069,7 +3069,7 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) * * DRM infrastructure takes care of reclaiming dma buffers. */ -void radeon_driver_prerelease(drm_device_t * dev, DRMFILE filp) +void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp) { if (dev->dev_private) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -3082,12 +3082,12 @@ void radeon_driver_prerelease(drm_device_t * dev, DRMFILE filp) } } -void radeon_driver_pretakedown(drm_device_t * dev) +void radeon_driver_lastclose(drm_device_t * dev) { radeon_do_release(dev); } -int radeon_driver_open_helper(drm_device_t * dev, drm_file_t * filp_priv) +int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_radeon_driver_file_fields *radeon_priv; @@ -3107,7 +3107,7 @@ int radeon_driver_open_helper(drm_device_t * dev, drm_file_t * filp_priv) return 0; } -void radeon_driver_free_filp_priv(drm_device_t * dev, drm_file_t * filp_priv) +void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv) { struct drm_radeon_driver_file_fields *radeon_priv = filp_priv->driver_priv; diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index 6d10515795cc..c3101702a1fe 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -533,16 +533,32 @@ static void savage_fake_dma_flush(drm_savage_private_t * dev_priv) dev_priv->first_dma_page = dev_priv->current_dma_page = 0; } +int savage_driver_load(drm_device_t *dev, unsigned long chipset) +{ + drm_savage_private_t *dev_priv; + + dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return DRM_ERR(ENOMEM); + + memset(dev_priv, 0, sizeof(drm_savage_private_t)); + dev->dev_private = (void *)dev_priv; + + dev_priv->chipset = (enum savage_family)chipset; + + return 0; +} + + /* * Initalize mappings. On Savage4 and SavageIX the alignment * and size of the aperture is not suitable for automatic MTRR setup - * in drm_addmap. Therefore we do it manually before the maps are - * initialized. We also need to take care of deleting the MTRRs in - * postcleanup. + * in drm_addmap. Therefore we add them manually before the maps are + * initialized, and tear them down on last close. */ -int savage_preinit(drm_device_t * dev, unsigned long chipset) +int savage_driver_firstopen(drm_device_t *dev) { - drm_savage_private_t *dev_priv; + drm_savage_private_t *dev_priv = dev->dev_private; unsigned long mmio_base, fb_base, fb_size, aperture_base; /* fb_rsrc and aper_rsrc aren't really used currently, but still exist * in case we decide we need information on the BAR for BSD in the @@ -551,14 +567,6 @@ int savage_preinit(drm_device_t * dev, unsigned long chipset) unsigned int fb_rsrc, aper_rsrc; int ret = 0; - dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) - return DRM_ERR(ENOMEM); - - memset(dev_priv, 0, sizeof(drm_savage_private_t)); - dev->dev_private = (void *)dev_priv; - dev_priv->chipset = (enum savage_family)chipset; - dev_priv->mtrr[0].handle = -1; dev_priv->mtrr[1].handle = -1; dev_priv->mtrr[2].handle = -1; @@ -595,7 +603,8 @@ int savage_preinit(drm_device_t * dev, unsigned long chipset) DRM_ERROR("strange pci_resource_len %08lx\n", drm_get_resource_len(dev, 0)); } - } else if (chipset != S3_SUPERSAVAGE && chipset != S3_SAVAGE2000) { + } else if (dev_priv->chipset != S3_SUPERSAVAGE && + dev_priv->chipset != S3_SAVAGE2000) { mmio_base = drm_get_resource_start(dev, 0); fb_rsrc = 1; fb_base = drm_get_resource_start(dev, 1); @@ -648,7 +657,7 @@ int savage_preinit(drm_device_t * dev, unsigned long chipset) /* * Delete MTRRs and free device-private data. */ -int savage_postcleanup(drm_device_t * dev) +void savage_driver_lastclose(drm_device_t *dev) { drm_savage_private_t *dev_priv = dev->dev_private; int i; @@ -658,6 +667,11 @@ int savage_postcleanup(drm_device_t * dev) mtrr_del(dev_priv->mtrr[i].handle, dev_priv->mtrr[i].base, dev_priv->mtrr[i].size); +} + +int savage_driver_unload(drm_device_t *dev) +{ + drm_savage_private_t *dev_priv = dev->dev_private; drm_free(dev_priv, sizeof(drm_savage_private_t), DRM_MEM_DRIVER); diff --git a/drivers/char/drm/savage_drv.c b/drivers/char/drm/savage_drv.c index 22d799cde41c..aa6c0d1a82f8 100644 --- a/drivers/char/drm/savage_drv.c +++ b/drivers/char/drm/savage_drv.c @@ -30,31 +30,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { savage_PCI_IDS }; @@ -63,13 +38,13 @@ static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_PCI_DMA, .dev_priv_size = sizeof(drm_savage_buf_priv_t), - .preinit = savage_preinit, - .postinit = postinit, - .postcleanup = savage_postcleanup, + .load = savage_driver_load, + .firstopen = savage_driver_firstopen, + .lastclose = savage_driver_lastclose, + .unload = savage_driver_unload, .reclaim_buffers = savage_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .version = version, .ioctls = savage_ioctls, .dma_ioctl = savage_bci_buffers, .fops = { @@ -80,12 +55,19 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, - } - , + }, + .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init savage_init(void) diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h index a4b0fa998a95..2f73558fb9cf 100644 --- a/drivers/char/drm/savage_drv.h +++ b/drivers/char/drm/savage_drv.h @@ -208,8 +208,10 @@ extern void savage_dma_reset(drm_savage_private_t * dev_priv); extern void savage_dma_wait(drm_savage_private_t * dev_priv, unsigned int page); extern uint32_t *savage_dma_alloc(drm_savage_private_t * dev_priv, unsigned int n); -extern int savage_preinit(drm_device_t * dev, unsigned long chipset); -extern int savage_postcleanup(drm_device_t * dev); +extern int savage_driver_load(drm_device_t *dev, unsigned long chipset); +extern int savage_driver_firstopen(drm_device_t *dev); +extern void savage_driver_lastclose(drm_device_t *dev); +extern int savage_driver_unload(drm_device_t *dev); extern int savage_do_cleanup_bci(drm_device_t * dev); extern void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp); diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c index 3cef10643a8f..6f6d7d613ede 100644 --- a/drivers/char/drm/sis_drv.c +++ b/drivers/char/drm/sis_drv.c @@ -32,31 +32,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { sisdrv_PCI_IDS }; @@ -68,8 +43,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = sis_ioctls, .fops = { .owner = THIS_MODULE, @@ -79,11 +52,18 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, - }, + }, .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init sis_init(void) diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c index c275cbb6e9ce..baa4416032a8 100644 --- a/drivers/char/drm/tdfx_drv.c +++ b/drivers/char/drm/tdfx_drv.c @@ -36,31 +36,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} - static struct pci_device_id pciidlist[] = { tdfx_PCI_IDS }; @@ -70,8 +45,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .fops = { .owner = THIS_MODULE, .open = drm_open, @@ -80,11 +53,18 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, - }, + }, .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init tdfx_init(void) diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index 016665e0c69f..6f3e6b32fa81 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c @@ -29,30 +29,6 @@ #include "drm_pciids.h" -static int postinit(struct drm_device *dev, unsigned long flags) -{ - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", - DRIVER_NAME, - DRIVER_MAJOR, - DRIVER_MINOR, - DRIVER_PATCHLEVEL, - DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) - ); - return 0; -} - -static int version(drm_version_t * version) -{ - int len; - - version->version_major = DRIVER_MAJOR; - version->version_minor = DRIVER_MINOR; - version->version_patchlevel = DRIVER_PATCHLEVEL; - DRM_COPY(version->name, DRIVER_NAME); - DRM_COPY(version->date, DRIVER_DATE); - DRM_COPY(version->desc, DRIVER_DESC); - return 0; -} static struct pci_device_id pciidlist[] = { viadrv_PCI_IDS @@ -88,8 +64,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .postinit = postinit, - .version = version, .ioctls = ioctls, .num_ioctls = DRM_ARRAY_SIZE(ioctls), .fops = { @@ -100,11 +74,18 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, - }, + }, .pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, - } + .name = DRIVER_NAME, + .id_table = pciidlist, + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, }; static int __init via_init(void) -- cgit v1.2.3 From 3f9df54d6386bb632ffc00665489bb3bb3bf6ff2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 10 Nov 2005 22:28:56 +1100 Subject: drm: remove drm_init.c it is no longer needed Move drm_cpu_valid into drm_fops.c Signed-off-by: Dave Airlie --- drivers/char/drm/Makefile | 2 +- drivers/char/drm/drmP.h | 1 - drivers/char/drm/drm_fops.c | 17 +++++++++++++++ drivers/char/drm/drm_init.c | 53 --------------------------------------------- 4 files changed, 18 insertions(+), 55 deletions(-) delete mode 100644 drivers/char/drm/drm_init.c diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index e41060c76226..f1898cd96597 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ - drm_drv.o drm_fops.o drm_init.o drm_ioctl.o drm_irq.o \ + drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ drm_sysfs.o diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index d842cce11448..3593f609241a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -770,7 +770,6 @@ static inline int drm_core_has_MTRR(struct drm_device *dev) /* Misc. support (drm_init.h) */ extern int drm_flags; extern void drm_parse_options(char *s); -extern int drm_cpu_valid(void); /* Driver support (drm_drv.h) */ extern int drm_init(struct drm_driver *driver); diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index f57f7d1a281e..28f01305377f 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -321,6 +321,23 @@ int drm_release(struct inode *inode, struct file *filp) EXPORT_SYMBOL(drm_release); +/** + * Check whether DRI will run on this CPU. + * + * \return non-zero if the DRI will run on this CPU, or zero otherwise. + */ +static int drm_cpu_valid(void) +{ +#if defined(__i386__) + if (boot_cpu_data.x86 == 3) + return 0; /* No cmpxchg on a 386 */ +#endif +#if defined(__sparc__) && !defined(__sparc_v9__) + return 0; /* No cmpxchg before v9 sparc. */ +#endif + return 1; +} + /** * Called whenever a process opens /dev/drm. * diff --git a/drivers/char/drm/drm_init.c b/drivers/char/drm/drm_init.c deleted file mode 100644 index 754b934715c4..000000000000 --- a/drivers/char/drm/drm_init.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * \file drm_init.c - * Setup/Cleanup for DRM - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * 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 - * VA LINUX SYSTEMS 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. - */ - -#include "drmP.h" - -/** - * Check whether DRI will run on this CPU. - * - * \return non-zero if the DRI will run on this CPU, or zero otherwise. - */ -int drm_cpu_valid(void) -{ -#if defined(__i386__) - if (boot_cpu_data.x86 == 3) - return 0; /* No cmpxchg on a 386 */ -#endif -#if defined(__sparc__) && !defined(__sparc_v9__) - return 0; /* No cmpxchg before v9 sparc. */ -#endif - return 1; -} -- cgit v1.2.3 From 9d6160137a8ef8bd25266ccc0f97d55863708fc6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 19:34:10 +1100 Subject: drm: remove remnamt of old DRM code from tdfx Signed-off-by: Dave Airlie --- drivers/char/drm/tdfx_drv.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/char/drm/tdfx_drv.h b/drivers/char/drm/tdfx_drv.h index a582a3db4c75..857be434379f 100644 --- a/drivers/char/drm/tdfx_drv.h +++ b/drivers/char/drm/tdfx_drv.h @@ -30,10 +30,6 @@ #ifndef __TDFX_H__ #define __TDFX_H__ -/* This remains constant for all DRM template files. - */ -#define DRM(x) tdfx_##x - /* General customization: */ -- cgit v1.2.3 From 7052cff984ba575926bb7d2ae5454cce531a97e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 19:34:47 +1100 Subject: drm: cleanup via_ds.c includes Remove the linux includes from via_ds.c Signed-off-by: Dave Airlie --- drivers/char/drm/via_ds.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c index 5c71e089246c..9429736b3b96 100644 --- a/drivers/char/drm/via_ds.c +++ b/drivers/char/drm/via_ds.c @@ -22,14 +22,7 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include +#include "drmP.h" #include "via_ds.h" extern unsigned int VIA_DEBUG; -- cgit v1.2.3 From 8f5f39f77f5a6053ae287d4673028e7a69335f5e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 19:40:52 +1100 Subject: drm: remove drm_flush drm_flush is no longer needed remove. Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 1 - drivers/char/drm/drm_fops.c | 14 -------------- drivers/char/drm/i810_dma.c | 1 - drivers/char/drm/i830_dma.c | 1 - 4 files changed, 17 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 3593f609241a..6c35879bbe3a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -783,7 +783,6 @@ extern int drm_lastclose(drm_device_t *dev); /* Device support (drm_fops.h) */ extern int drm_open(struct inode *inode, struct file *filp); extern int drm_stub_open(struct inode *inode, struct file *filp); -extern int drm_flush(struct file *filp); extern int drm_fasync(int fd, struct file *filp, int on); extern int drm_release(struct inode *inode, struct file *filp); diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 28f01305377f..b73543c694a9 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -423,20 +423,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp, return ret; } -/** No-op. */ -int drm_flush(struct file *filp) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - - DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", - current->pid, (long)old_encode_dev(priv->head->device), - dev->open_count); - return 0; -} - -EXPORT_SYMBOL(drm_flush); - /** No-op. */ int drm_fasync(int fd, struct file *filp, int on) { diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index c3178a89615d..a7df6147091c 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -114,7 +114,6 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) static struct file_operations i810_buffer_fops = { .open = drm_open, - .flush = drm_flush, .release = drm_release, .ioctl = drm_ioctl, .mmap = i810_mmap_buffers, diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 01dfdb944e1f..f1e048f10ce8 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -116,7 +116,6 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) static struct file_operations i830_buffer_fops = { .open = drm_open, - .flush = drm_flush, .release = drm_release, .ioctl = drm_ioctl, .mmap = i830_mmap_buffers, -- cgit v1.2.3 From 61d04160ff89514919ef95b0d10bee706f569925 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 19:52:22 +1100 Subject: drm: remove old backwards compatibilty stuff Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 6c35879bbe3a..7fe516160b63 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -144,20 +144,6 @@ /** \name Backward compatibility section */ /*@{*/ -#ifndef MODULE_LICENSE -#define MODULE_LICENSE(x) -#endif - -#ifndef preempt_disable -#define preempt_disable() -#define preempt_enable() -#endif - -#ifndef pte_offset_map -#define pte_offset_map pte_offset -#define pte_unmap(pte) -#endif - #define DRM_RPR_ARG(vma) vma, #define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT) -- cgit v1.2.3 From e96e33eeb8b876c7ec009c557ca5269328eceda0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 20:27:35 +1100 Subject: drm: fixup drm_proc.c struct table Signed-off-by: Dave Airlie --- drivers/char/drm/drm_proc.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 3f452f763f0f..6f943e3309ef 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c @@ -61,16 +61,14 @@ static struct drm_proc_list { const char *name; /**< file name */ int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ } drm_proc_list[] = { - { - "name", drm_name_info}, { - "mem", drm_mem_info}, { - "vm", drm_vm_info}, { - "clients", drm_clients_info}, { - "queues", drm_queues_info}, { - "bufs", drm_bufs_info}, + {"name", drm_name_info}, + {"mem", drm_mem_info}, + {"vm", drm_vm_info}, + {"clients", drm_clients_info}, + {"queues", drm_queues_info}, + {"bufs", drm_bufs_info}, #if DRM_DEBUG_CODE - { - "vma", drm_vma_info}, + {"vma", drm_vma_info}, #endif }; -- cgit v1.2.3 From 732052ed3e7539d87136dd833be523747af3fb3e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 22:07:35 +1100 Subject: drm: simplify sysfs code for drm This simplifies the sysfs code for the drm and add a dri_library_name attribute which can be used by a userspace app to figure out which library to load. From: Jon Smirl Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 7 ++--- drivers/char/drm/drm_stub.c | 11 ++----- drivers/char/drm/drm_sysfs.c | 68 ++++++++++++++++++------------------------- drivers/char/drm/radeon_drv.c | 11 +++++++ drivers/char/drm/radeon_drv.h | 2 +- drivers/char/drm/via_drv.c | 5 ++++ 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 7fe516160b63..e9ede8d69e20 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -547,6 +547,7 @@ struct drm_driver { void (*kernel_context_switch_unlock) (struct drm_device * dev, drm_lock_t * lock); int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); + int (*dri_library_name) (struct drm_device *dev, char *buf); /** * Called by \c drm_device_is_agp. Typically used to determine if a @@ -982,10 +983,8 @@ extern struct drm_sysfs_class *drm_sysfs_create(struct module *owner, char *name); extern void drm_sysfs_destroy(struct drm_sysfs_class *cs); extern struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs, - dev_t dev, - struct device *device, - const char *fmt, ...); -extern void drm_sysfs_device_remove(dev_t dev); + drm_head_t *head); +extern void drm_sysfs_device_remove(struct class_device *class_dev); /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 8568a6b373a0..b7f2a851f45c 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -200,11 +200,7 @@ static int drm_get_head(drm_device_t * dev, drm_head_t * head) goto err_g1; } - head->dev_class = drm_sysfs_device_add(drm_class, - MKDEV(DRM_MAJOR, - minor), - &dev->pdev->dev, - "card%d", minor); + head->dev_class = drm_sysfs_device_add(drm_class, head); if (IS_ERR(head->dev_class)) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); @@ -317,10 +313,9 @@ int drm_put_head(drm_head_t * head) DRM_DEBUG("release secondary minor %d\n", minor); drm_proc_cleanup(minor, drm_proc_root, head->dev_root); - drm_sysfs_device_remove(MKDEV(DRM_MAJOR, head->minor)); + drm_sysfs_device_remove(head->dev_class); - *head = (drm_head_t) { - .dev = NULL}; + *head = (drm_head_t) {.dev = NULL}; drm_heads[minor] = NULL; diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 6d3449761914..68e43ddc16ae 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include "drm_core.h" #include "drmP.h" @@ -28,15 +26,11 @@ struct drm_sysfs_class { #define to_drm_sysfs_class(d) container_of(d, struct drm_sysfs_class, class) struct simple_dev { - struct list_head node; dev_t dev; struct class_device class_dev; }; #define to_simple_dev(d) container_of(d, struct simple_dev, class_dev) -static LIST_HEAD(simple_dev_list); -static DEFINE_SPINLOCK(simple_dev_list_lock); - static void release_simple_dev(struct class_device *class_dev) { struct simple_dev *s_dev = to_simple_dev(class_dev); @@ -124,6 +118,18 @@ void drm_sysfs_destroy(struct drm_sysfs_class *cs) class_unregister(&cs->class); } +static ssize_t show_dri(struct class_device *class_device, char *buf) +{ + drm_device_t * dev = ((drm_head_t *)class_get_devdata(class_device))->dev; + if (dev->driver->dri_library_name) + return dev->driver->dri_library_name(dev, buf); + return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); +} + +static struct class_device_attribute class_device_attrs[] = { + __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), +}; + /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver * @cs: pointer to the struct drm_sysfs_class that this device should be registered to. @@ -138,13 +144,11 @@ void drm_sysfs_destroy(struct drm_sysfs_class *cs) * Note: the struct drm_sysfs_class passed to this function must have previously been * created with a call to drm_sysfs_create(). */ -struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs, dev_t dev, - struct device *device, - const char *fmt, ...) +struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs, + drm_head_t *head) { - va_list args; struct simple_dev *s_dev = NULL; - int retval; + int i, retval; if ((cs == NULL) || (IS_ERR(cs))) { retval = -ENODEV; @@ -158,26 +162,23 @@ struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs, dev_t dev, } memset(s_dev, 0x00, sizeof(*s_dev)); - s_dev->dev = dev; - s_dev->class_dev.dev = device; + s_dev->dev = MKDEV(DRM_MAJOR, head->minor); + s_dev->class_dev.dev = &(head->dev->pdev)->dev; s_dev->class_dev.class = &cs->class; - va_start(args, fmt); - vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args); - va_end(args); + snprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, "card%d", head->minor); retval = class_device_register(&s_dev->class_dev); if (retval) goto error; class_device_create_file(&s_dev->class_dev, &cs->attr); + class_set_devdata(&s_dev->class_dev, head); - spin_lock(&simple_dev_list_lock); - list_add(&s_dev->node, &simple_dev_list); - spin_unlock(&simple_dev_list_lock); - + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) + class_device_create_file(&s_dev->class_dev, &class_device_attrs[i]); return &s_dev->class_dev; - error: +error: kfree(s_dev); return ERR_PTR(retval); } @@ -189,23 +190,12 @@ struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs, dev_t dev, * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(dev_t dev) +void drm_sysfs_device_remove(struct class_device *class_dev) { - struct simple_dev *s_dev = NULL; - int found = 0; - - spin_lock(&simple_dev_list_lock); - list_for_each_entry(s_dev, &simple_dev_list, node) { - if (s_dev->dev == dev) { - found = 1; - break; - } - } - if (found) { - list_del(&s_dev->node); - spin_unlock(&simple_dev_list_lock); - class_device_unregister(&s_dev->class_dev); - } else { - spin_unlock(&simple_dev_list_lock); - } + struct simple_dev *s_dev = to_simple_dev(class_dev); + int i; + + for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) + class_device_remove_file(&s_dev->class_dev, &class_device_attrs[i]); + class_device_unregister(&s_dev->class_dev); } diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index 999d74512362..b04ed1b562b9 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c @@ -42,6 +42,16 @@ int radeon_no_wb; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); module_param_named(no_wb, radeon_no_wb, int, 0444); +static int dri_library_name(struct drm_device *dev, char *buf) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int family = dev_priv->flags & CHIP_FAMILY_MASK; + + return snprintf(buf, PAGE_SIZE, "%s\n", + (family < CHIP_R200) ? "radeon" : + ((family < CHIP_R300) ? "r200" : + "r300")); +} static struct pci_device_id pciidlist[] = { radeon_PCI_IDS @@ -61,6 +71,7 @@ static struct drm_driver driver = { .lastclose = radeon_driver_lastclose, .unload = radeon_driver_unload, .vblank_wait = radeon_driver_vblank_wait, + .dri_library_name = dri_library_name, .irq_preinstall = radeon_driver_irq_preinstall, .irq_postinstall = radeon_driver_irq_postinstall, .irq_uninstall = radeon_driver_irq_uninstall, diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 3a91d5fc597e..c37f2ea20783 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -103,8 +103,8 @@ enum radeon_family { CHIP_R100, CHIP_RS100, CHIP_RV100, - CHIP_R200, CHIP_RV200, + CHIP_R200, CHIP_RS200, CHIP_R250, CHIP_RS250, diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index 6f3e6b32fa81..e8adebdba127 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c @@ -29,6 +29,10 @@ #include "drm_pciids.h" +static int dri_library_name(struct drm_device *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "unichrome"); +} static struct pci_device_id pciidlist[] = { viadrv_PCI_IDS @@ -61,6 +65,7 @@ static struct drm_driver driver = { .irq_uninstall = via_driver_irq_uninstall, .irq_handler = via_driver_irq_handler, .dma_quiescent = via_driver_dma_quiescent, + .dri_library_name = dri_library_name, .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, -- cgit v1.2.3 From efa58395bee82dc5a87805e7eb7c710e88eb4bd7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 22:33:39 +1100 Subject: drm: add in-kernel entry points for rest of AGP ioctls Allow DRM modules to call AGP internally in the kernel. From: Ian Romanick Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 12 ++-- drivers/char/drm/drm_agpsupport.c | 123 +++++++++++++++++++++++++------------- drivers/char/drm/drm_core.h | 4 +- drivers/char/drm/drm_drv.c | 8 +-- 4 files changed, 95 insertions(+), 52 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index e9ede8d69e20..66814291949a 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -925,13 +925,17 @@ extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp, extern int drm_agp_info(drm_device_t * dev, drm_agp_info_t * info); extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_agp_alloc(struct inode *inode, struct file *filp, +extern int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request); +extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_agp_free(struct inode *inode, struct file *filp, +extern int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request); +extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_agp_unbind(struct inode *inode, struct file *filp, +extern int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request); +extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_agp_bind(struct inode *inode, struct file *filp, +extern int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request); +extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type); diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c index 2b6453a9ffce..b80e61a4c40b 100644 --- a/drivers/char/drm/drm_agpsupport.c +++ b/drivers/char/drm/drm_agpsupport.c @@ -208,30 +208,22 @@ int drm_agp_enable_ioctl(struct inode *inode, struct file *filp, * Verifies the AGP device is present and has been acquired, allocates the * memory via alloc_agp() and creates a drm_agp_mem entry for it. */ -int drm_agp_alloc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - drm_agp_buffer_t request; drm_agp_mem_t *entry; DRM_AGP_MEM *memory; unsigned long pages; u32 type; - drm_agp_buffer_t __user *argp = (void __user *)arg; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (copy_from_user(&request, argp, sizeof(request))) - return -EFAULT; if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) return -ENOMEM; memset(entry, 0, sizeof(*entry)); - pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; - type = (u32) request.type; - + pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; + type = (u32) request->type; if (!(memory = drm_alloc_agp(dev, pages, type))) { drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); return -ENOMEM; @@ -247,16 +239,39 @@ int drm_agp_alloc(struct inode *inode, struct file *filp, dev->agp->memory->prev = entry; dev->agp->memory = entry; - request.handle = entry->handle; - request.physical = memory->physical; + request->handle = entry->handle; + request->physical = memory->physical; + + return 0; +} +EXPORT_SYMBOL(drm_agp_alloc); + +int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_agp_buffer_t request; + drm_agp_buffer_t __user *argp = (void __user *)arg; + int err; + + if (copy_from_user(&request, argp, sizeof(request))) + return -EFAULT; + + err = drm_agp_alloc(dev, &request); + if (err) + return err; if (copy_to_user(argp, &request, sizeof(request))) { + drm_agp_mem_t *entry = dev->agp->memory; + dev->agp->memory = entry->next; dev->agp->memory->prev = NULL; - drm_free_agp(memory, pages); + drm_free_agp(entry->memory, entry->pages); drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); return -EFAULT; } + return 0; } @@ -293,21 +308,14 @@ static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t * dev, * Verifies the AGP device is present and acquired, looks-up the AGP memory * entry and passes it to the unbind_agp() function. */ -int drm_agp_unbind(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - drm_agp_binding_t request; drm_agp_mem_t *entry; int ret; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (copy_from_user - (&request, (drm_agp_binding_t __user *) arg, sizeof(request))) - return -EFAULT; - if (!(entry = drm_agp_lookup_entry(dev, request.handle))) + if (!(entry = drm_agp_lookup_entry(dev, request->handle))) return -EINVAL; if (!entry->bound) return -EINVAL; @@ -316,6 +324,21 @@ int drm_agp_unbind(struct inode *inode, struct file *filp, entry->bound = 0; return ret; } +EXPORT_SYMBOL(drm_agp_unbind); + +int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_agp_binding_t request; + + if (copy_from_user + (&request, (drm_agp_binding_t __user *) arg, sizeof(request))) + return -EFAULT; + + return drm_agp_unbind(dev, &request); +} /** * Bind AGP memory into the GATT (ioctl) @@ -330,26 +353,19 @@ int drm_agp_unbind(struct inode *inode, struct file *filp, * is currently bound into the GATT. Looks-up the AGP memory entry and passes * it to bind_agp() function. */ -int drm_agp_bind(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - drm_agp_binding_t request; drm_agp_mem_t *entry; int retcode; int page; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (copy_from_user - (&request, (drm_agp_binding_t __user *) arg, sizeof(request))) - return -EFAULT; - if (!(entry = drm_agp_lookup_entry(dev, request.handle))) + if (!(entry = drm_agp_lookup_entry(dev, request->handle))) return -EINVAL; if (entry->bound) return -EINVAL; - page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; + page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE; if ((retcode = drm_bind_agp(entry->memory, page))) return retcode; entry->bound = dev->agp->base + (page << PAGE_SHIFT); @@ -357,6 +373,21 @@ int drm_agp_bind(struct inode *inode, struct file *filp, dev->agp->base, entry->bound); return 0; } +EXPORT_SYMBOL(drm_agp_bind); + +int drm_agp_bind_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_agp_binding_t request; + + if (copy_from_user + (&request, (drm_agp_binding_t __user *) arg, sizeof(request))) + return -EFAULT; + + return drm_agp_bind(dev, &request); +} /** * Free AGP memory (ioctl). @@ -372,20 +403,13 @@ int drm_agp_bind(struct inode *inode, struct file *filp, * unbind_agp(). Frees it via free_agp() as well as the entry itself * and unlinks from the doubly linked list it's inserted in. */ -int drm_agp_free(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - drm_agp_buffer_t request; drm_agp_mem_t *entry; if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (copy_from_user - (&request, (drm_agp_buffer_t __user *) arg, sizeof(request))) - return -EFAULT; - if (!(entry = drm_agp_lookup_entry(dev, request.handle))) + if (!(entry = drm_agp_lookup_entry(dev, request->handle))) return -EINVAL; if (entry->bound) drm_unbind_agp(entry->memory); @@ -402,6 +426,21 @@ int drm_agp_free(struct inode *inode, struct file *filp, drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); return 0; } +EXPORT_SYMBOL(drm_agp_free); + +int drm_agp_free_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_agp_buffer_t request; + + if (copy_from_user + (&request, (drm_agp_buffer_t __user *) arg, sizeof(request))) + return -EFAULT; + + return drm_agp_free(dev, &request); +} /** * Initialize the AGP resources. diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h index cc97bb906dda..f4f9db6c7ed4 100644 --- a/drivers/char/drm/drm_core.h +++ b/drivers/char/drm/drm_core.h @@ -24,11 +24,11 @@ #define CORE_NAME "drm" #define CORE_DESC "DRM shared core routines" -#define CORE_DATE "20040925" +#define CORE_DATE "20051102" #define DRM_IF_MAJOR 1 #define DRM_IF_MINOR 2 #define CORE_MAJOR 1 #define CORE_MINOR 0 -#define CORE_PATCHLEVEL 0 +#define CORE_PATCHLEVEL 1 diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index d8ff84bdc3e7..222ae09ae65f 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -106,10 +106,10 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, 1, 1}, [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, 1, 1}, [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, 1, 1}, #endif [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, 1, 1}, -- cgit v1.2.3 From c0be4d240483f3ebd138db467b5e8fbe15c520e2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 23:10:18 +1100 Subject: drm: remove exports that modules shouldn't use. Modules should go via the new drm_agp_ functions. Signed-off-by: Dave Airlie --- drivers/char/drm/drm_memory.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index 2c74155aa84f..7438741c29e9 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -145,30 +145,22 @@ DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type) return drm_agp_allocate_memory(dev->agp->bridge, pages, type); } -EXPORT_SYMBOL(drm_alloc_agp); - /** Wrapper around agp_free_memory() */ int drm_free_agp(DRM_AGP_MEM * handle, int pages) { return drm_agp_free_memory(handle) ? 0 : -EINVAL; } -EXPORT_SYMBOL(drm_free_agp); - /** Wrapper around agp_bind_memory() */ int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) { return drm_agp_bind_memory(handle, start); } -EXPORT_SYMBOL(drm_bind_agp); - /** Wrapper around agp_unbind_memory() */ int drm_unbind_agp(DRM_AGP_MEM * handle) { return drm_agp_unbind_memory(handle); } - -EXPORT_SYMBOL(drm_unbind_agp); #endif /* agp */ #endif /* debug_memory */ -- cgit v1.2.3 From 7ccf800e9415daf9214eb667318e356f9a3d81fc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 23:11:34 +1100 Subject: drm: update mga driver for new bootstrap code The MGA driver needs to use the full AGP interface. From: Ian Romanick Signed-off-by: Dave Airlie --- drivers/char/drm/mga_dma.c | 144 +++++++++++++++++++++++++++------------------ drivers/char/drm/mga_drv.c | 2 +- drivers/char/drm/mga_drv.h | 8 +-- 3 files changed, 92 insertions(+), 62 deletions(-) diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 9b09d786b158..c2a4bac14521 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -44,7 +44,9 @@ #define MGA_DEFAULT_USEC_TIMEOUT 10000 #define MGA_FREELIST_DEBUG 0 -static int mga_do_cleanup_dma(drm_device_t * dev); +#define MINIMAL_CLEANUP 0 +#define FULL_CLEANUP 1 +static int mga_do_cleanup_dma(drm_device_t *dev, int full_cleanup); /* ================================================================ * Engine control @@ -446,17 +448,19 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, drm_buf_desc_t req; drm_agp_mode_t mode; drm_agp_info_t info; + drm_agp_buffer_t agp_req; + drm_agp_binding_t bind_req; /* Acquire AGP. */ err = drm_agp_acquire(dev); if (err) { - DRM_ERROR("Unable to acquire AGP\n"); + DRM_ERROR("Unable to acquire AGP: %d\n", err); return err; } err = drm_agp_info(dev, &info); if (err) { - DRM_ERROR("Unable to get AGP info\n"); + DRM_ERROR("Unable to get AGP info: %d\n", err); return err; } @@ -480,18 +484,24 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, } /* Allocate and bind AGP memory. */ - dev_priv->agp_pages = agp_size / PAGE_SIZE; - dev_priv->agp_mem = drm_alloc_agp(dev, dev_priv->agp_pages, 0); - if (dev_priv->agp_mem == NULL) { - dev_priv->agp_pages = 0; + agp_req.size = agp_size; + agp_req.type = 0; + err = drm_agp_alloc(dev, &agp_req); + if (err) { + dev_priv->agp_size = 0; DRM_ERROR("Unable to allocate %uMB AGP memory\n", dma_bs->agp_size); - return DRM_ERR(ENOMEM); + return err; } + + dev_priv->agp_size = agp_size; + dev_priv->agp_handle = agp_req.handle; - err = drm_bind_agp(dev_priv->agp_mem, 0); + bind_req.handle = agp_req.handle; + bind_req.offset = 0; + err = drm_agp_bind(dev, &bind_req); if (err) { - DRM_ERROR("Unable to bind AGP memory\n"); + DRM_ERROR("Unable to bind AGP memory: %d\n", err); return err; } @@ -505,7 +515,7 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, err = drm_addmap(dev, offset, warp_size, _DRM_AGP, _DRM_READ_ONLY, &dev_priv->warp); if (err) { - DRM_ERROR("Unable to map WARP microcode\n"); + DRM_ERROR("Unable to map WARP microcode: %d\n", err); return err; } @@ -513,7 +523,7 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, err = drm_addmap(dev, offset, dma_bs->primary_size, _DRM_AGP, _DRM_READ_ONLY, &dev_priv->primary); if (err) { - DRM_ERROR("Unable to map primary DMA region\n"); + DRM_ERROR("Unable to map primary DMA region: %d\n", err); return err; } @@ -521,7 +531,7 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, err = drm_addmap(dev, offset, secondary_size, _DRM_AGP, 0, &dev->agp_buffer_map); if (err) { - DRM_ERROR("Unable to map secondary DMA region\n"); + DRM_ERROR("Unable to map secondary DMA region: %d\n", err); return err; } @@ -533,15 +543,29 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, err = drm_addbufs_agp(dev, &req); if (err) { - DRM_ERROR("Unable to add secondary DMA buffers\n"); + DRM_ERROR("Unable to add secondary DMA buffers: %d\n", err); return err; } + { + drm_map_list_t *_entry; + unsigned long agp_token = 0; + + list_for_each_entry(_entry, &dev->maplist->head, head) { + if (_entry->map == dev->agp_buffer_map) + agp_token = _entry->user_token; + } + if (!agp_token) + return -EFAULT; + + dev->agp_buffer_token = agp_token; + } + offset += secondary_size; err = drm_addmap(dev, offset, agp_size - offset, _DRM_AGP, 0, &dev_priv->agp_textures); if (err) { - DRM_ERROR("Unable to map AGP texture region\n"); + DRM_ERROR("Unable to map AGP texture region %d\n", err); return err; } @@ -611,7 +635,8 @@ static int mga_do_pci_dma_bootstrap(drm_device_t * dev, err = drm_addmap(dev, 0, warp_size, _DRM_CONSISTENT, _DRM_READ_ONLY, &dev_priv->warp); if (err != 0) { - DRM_ERROR("Unable to create mapping for WARP microcode\n"); + DRM_ERROR("Unable to create mapping for WARP microcode: %d\n", + err); return err; } @@ -630,7 +655,7 @@ static int mga_do_pci_dma_bootstrap(drm_device_t * dev, } if (err != 0) { - DRM_ERROR("Unable to allocate primary DMA region\n"); + DRM_ERROR("Unable to allocate primary DMA region: %d\n", err); return DRM_ERR(ENOMEM); } @@ -654,7 +679,7 @@ static int mga_do_pci_dma_bootstrap(drm_device_t * dev, } if (bin_count == 0) { - DRM_ERROR("Unable to add secondary DMA buffers\n"); + DRM_ERROR("Unable to add secondary DMA buffers: %d\n", err); return err; } @@ -690,7 +715,7 @@ static int mga_do_dma_bootstrap(drm_device_t * dev, err = drm_addmap(dev, dev_priv->mmio_base, dev_priv->mmio_size, _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio); if (err) { - DRM_ERROR("Unable to map MMIO region\n"); + DRM_ERROR("Unable to map MMIO region: %d\n", err); return err; } @@ -698,7 +723,7 @@ static int mga_do_dma_bootstrap(drm_device_t * dev, _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL, &dev_priv->status); if (err) { - DRM_ERROR("Unable to map status region\n"); + DRM_ERROR("Unable to map status region: %d\n", err); return err; } @@ -716,7 +741,7 @@ static int mga_do_dma_bootstrap(drm_device_t * dev, */ if (err) { - mga_do_cleanup_dma(dev); + mga_do_cleanup_dma(dev, MINIMAL_CLEANUP); } /* Not only do we want to try and initialized PCI cards for PCI DMA, @@ -739,35 +764,32 @@ int mga_dma_bootstrap(DRM_IOCTL_ARGS) DRM_DEVICE; drm_mga_dma_bootstrap_t bootstrap; int err; + static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 }; + const drm_mga_private_t *const dev_priv = + (drm_mga_private_t *) dev->dev_private; DRM_COPY_FROM_USER_IOCTL(bootstrap, (drm_mga_dma_bootstrap_t __user *) data, sizeof(bootstrap)); err = mga_do_dma_bootstrap(dev, &bootstrap); - if (!err) { - static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 }; - const drm_mga_private_t *const dev_priv = - (drm_mga_private_t *) dev->dev_private; - - if (dev_priv->agp_textures != NULL) { - bootstrap.texture_handle = - dev_priv->agp_textures->offset; - bootstrap.texture_size = dev_priv->agp_textures->size; - } else { - bootstrap.texture_handle = 0; - bootstrap.texture_size = 0; - } + if (err) { + mga_do_cleanup_dma(dev, FULL_CLEANUP); + return err; + } - bootstrap.agp_mode = modes[bootstrap.agp_mode & 0x07]; - if (DRM_COPY_TO_USER((void __user *)data, &bootstrap, - sizeof(bootstrap))) { - err = DRM_ERR(EFAULT); - } + if (dev_priv->agp_textures != NULL) { + bootstrap.texture_handle = dev_priv->agp_textures->offset; + bootstrap.texture_size = dev_priv->agp_textures->size; } else { - mga_do_cleanup_dma(dev); + bootstrap.texture_handle = 0; + bootstrap.texture_size = 0; } + bootstrap.agp_mode = modes[bootstrap.agp_mode & 0x07]; + DRM_COPY_TO_USER_IOCTL((drm_mga_dma_bootstrap_t __user *)data, + bootstrap, sizeof(bootstrap)); + return err; } @@ -861,13 +883,13 @@ static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init) ret = mga_warp_install_microcode(dev_priv); if (ret < 0) { - DRM_ERROR("failed to install WARP ucode!\n"); + DRM_ERROR("failed to install WARP ucode!: %d\n", ret); return ret; } ret = mga_warp_init(dev_priv); if (ret < 0) { - DRM_ERROR("failed to init WARP engine!\n"); + DRM_ERROR("failed to init WARP engine!: %d\n", ret); return ret; } @@ -912,7 +934,7 @@ static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init) return 0; } -static int mga_do_cleanup_dma(drm_device_t * dev) +static int mga_do_cleanup_dma(drm_device_t *dev, int full_cleanup) { int err = 0; DRM_DEBUG("\n"); @@ -940,31 +962,39 @@ static int mga_do_cleanup_dma(drm_device_t * dev) if (dev_priv->used_new_dma_init) { #if __OS_HAS_AGP - if (dev_priv->agp_mem != NULL) { - dev_priv->agp_textures = NULL; - drm_unbind_agp(dev_priv->agp_mem); + if (dev_priv->agp_handle != 0) { + drm_agp_binding_t unbind_req; + drm_agp_buffer_t free_req; - drm_free_agp(dev_priv->agp_mem, - dev_priv->agp_pages); - dev_priv->agp_pages = 0; - dev_priv->agp_mem = NULL; + unbind_req.handle = dev_priv->agp_handle; + drm_agp_unbind(dev, &unbind_req); + + free_req.handle = dev_priv->agp_handle; + drm_agp_free(dev, &free_req); + + dev_priv->agp_textures = NULL; + dev_priv->agp_size = 0; + dev_priv->agp_handle = 0; } if ((dev->agp != NULL) && dev->agp->acquired) { err = drm_agp_release(dev); } #endif - dev_priv->used_new_dma_init = 0; } dev_priv->warp = NULL; dev_priv->primary = NULL; - dev_priv->mmio = NULL; - dev_priv->status = NULL; dev_priv->sarea = NULL; dev_priv->sarea_priv = NULL; dev->agp_buffer_map = NULL; + if (full_cleanup) { + dev_priv->mmio = NULL; + dev_priv->status = NULL; + dev_priv->used_new_dma_init = 0; + } + memset(&dev_priv->prim, 0, sizeof(dev_priv->prim)); dev_priv->warp_pipe = 0; memset(dev_priv->warp_pipe_phys, 0, @@ -975,7 +1005,7 @@ static int mga_do_cleanup_dma(drm_device_t * dev) } } - return err; + return 0; } int mga_dma_init(DRM_IOCTL_ARGS) @@ -993,11 +1023,11 @@ int mga_dma_init(DRM_IOCTL_ARGS) case MGA_INIT_DMA: err = mga_do_init_dma(dev, &init); if (err) { - (void)mga_do_cleanup_dma(dev); + (void)mga_do_cleanup_dma(dev, FULL_CLEANUP); } return err; case MGA_CLEANUP_DMA: - return mga_do_cleanup_dma(dev); + return mga_do_cleanup_dma(dev, FULL_CLEANUP); } return DRM_ERR(EINVAL); @@ -1139,7 +1169,7 @@ int mga_driver_unload(drm_device_t * dev) */ void mga_driver_lastclose(drm_device_t * dev) { - mga_do_cleanup_dma(dev); + mga_do_cleanup_dma(dev, FULL_CLEANUP); } int mga_driver_dma_quiescent(drm_device_t * dev) diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index eae2f91994ec..93f171e634c0 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -45,7 +45,7 @@ static struct pci_device_id pciidlist[] = { static struct drm_driver driver = { .driver_features = - DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, .load = mga_driver_load, diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 137bfdd5e92b..6b0c53193506 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -38,11 +38,11 @@ #define DRIVER_NAME "mga" #define DRIVER_DESC "Matrox G200/G400" -#define DRIVER_DATE "20050607" +#define DRIVER_DATE "20051102" #define DRIVER_MAJOR 3 #define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_PATCHLEVEL 1 typedef struct drm_mga_primary_buffer { u8 *start; @@ -144,8 +144,8 @@ typedef struct drm_mga_private { drm_local_map_t *primary; drm_local_map_t *agp_textures; - DRM_AGP_MEM *agp_mem; - unsigned int agp_pages; + unsigned long agp_handle; + unsigned int agp_size; } drm_mga_private_t; extern drm_ioctl_desc_t mga_ioctls[]; -- cgit v1.2.3 From 792d2b9a12594522111fbe2a7f17460a4d7edff7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 11 Nov 2005 23:30:27 +1100 Subject: drm: drop mtrr from i915 Alan Hourihane wants to set MTRR in the DDX only as otherwise we get problems with the shared memory chipset. From: Alan Hourihane Signed-off-by: Dave Airlie --- drivers/char/drm/i915_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 32b7f8bb420d..e88d32d286f5 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -39,8 +39,11 @@ static struct pci_device_id pciidlist[] = { }; static struct drm_driver driver = { + /* don't use mtrr's here, the Xserver or user space app should + * deal with them for intel hardware. + */ .driver_features = - DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | + DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .load = i915_driver_load, .lastclose = i915_driver_lastclose, -- cgit v1.2.3 From 925142431bd653175b80ae153bd7a8bc13628bde Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 12 Nov 2005 21:52:46 +1100 Subject: drm: update VIA driver to 2.7.2 Add PCI DMA blitengine to VIA DRM Add portability code for porting VIA to FreeBSD. Sync via_drm.h with 3d driver From: Thomas Hellstrom , Eric Anholt Signed-off-by: Dave Airlie --- drivers/char/drm/Makefile | 2 +- drivers/char/drm/drm_os_linux.h | 1 + drivers/char/drm/via_dma.c | 36 ++++++++++++++++++------- drivers/char/drm/via_drm.h | 60 +++++++++++++++++++++++++++++------------ drivers/char/drm/via_drv.c | 21 +++------------ drivers/char/drm/via_drv.h | 56 +++++++++++++++++++++++++++++--------- drivers/char/drm/via_irq.c | 53 +++++++++++++++++++++++++++++------- drivers/char/drm/via_map.c | 47 ++++++++++++++++++++------------ drivers/char/drm/via_mm.c | 16 +++++------ drivers/char/drm/via_verifier.c | 6 ++--- drivers/char/drm/via_verifier.h | 4 ++- drivers/char/drm/via_video.c | 7 +++-- 12 files changed, 211 insertions(+), 98 deletions(-) diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index f1898cd96597..9d180c42816c 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -18,7 +18,7 @@ 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 sis-objs := sis_drv.o sis_ds.o sis_mm.o savage-objs := savage_drv.o savage_bci.o savage_state.o -via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o +via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o ifeq ($(CONFIG_COMPAT),y) drm-objs += drm_ioc32.o diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index d51aeb4966f4..695115d70382 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -13,6 +13,7 @@ #define DRM_ERR(d) -(d) /** Current process ID */ #define DRM_CURRENTPID current->pid +#define DRM_SUSER(p) capable(CAP_SYS_ADMIN) #define DRM_UDELAY(d) udelay(d) /** Read a byte from a MMIO region */ #define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset)) diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index d4b1766608b0..1acbeeb28069 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -213,7 +213,9 @@ static int via_initialize(drm_device_t * dev, dev_priv->dma_wrap = init->size; dev_priv->dma_offset = init->offset; dev_priv->last_pause_ptr = NULL; - dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr; + dev_priv->hw_addr_ptr = + (volatile uint32_t *)((char *)dev_priv->mmio->handle + + init->reg_pause_addr); via_cmdbuf_start(dev_priv); @@ -232,13 +234,13 @@ int via_dma_init(DRM_IOCTL_ARGS) switch (init.func) { case VIA_INIT_DMA: - if (!capable(CAP_SYS_ADMIN)) + if (!DRM_SUSER(DRM_CURPROC)) retcode = DRM_ERR(EPERM); else retcode = via_initialize(dev, dev_priv, &init); break; case VIA_CLEANUP_DMA: - if (!capable(CAP_SYS_ADMIN)) + if (!DRM_SUSER(DRM_CURPROC)) retcode = DRM_ERR(EPERM); else retcode = via_dma_cleanup(dev); @@ -349,9 +351,6 @@ int via_cmdbuffer(DRM_IOCTL_ARGS) return 0; } -extern int -via_parse_command_stream(drm_device_t * dev, const uint32_t * buf, - unsigned int size); static int via_dispatch_pci_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd) { @@ -450,9 +449,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv, if ((count <= 8) && (count >= 0)) { uint32_t rgtr, ptr; rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + - dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 - - CMDBUF_ALIGNMENT_SIZE; + ptr = ((volatile char *)dev_priv->last_pause_ptr - + dev_priv->dma_ptr) + dev_priv->dma_offset + + (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE; if (rgtr <= ptr) { DRM_ERROR ("Command regulator\npaused at count %d, address %x, " @@ -472,7 +471,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv, && count--) ; rgtr = *(dev_priv->hw_addr_ptr); - ptr = ((char *)paused_at - dev_priv->dma_ptr) + + ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ? @@ -724,3 +723,20 @@ int via_cmdbuf_size(DRM_IOCTL_ARGS) sizeof(d_siz)); return ret; } + +drm_ioctl_desc_t via_ioctls[] = { + [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0} +}; + +int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h index ebde9206115e..556d80722fd0 100644 --- a/drivers/char/drm/via_drm.h +++ b/drivers/char/drm/via_drm.h @@ -75,6 +75,8 @@ #define DRM_VIA_CMDBUF_SIZE 0x0b #define NOT_USED #define DRM_VIA_WAIT_IRQ 0x0d +#define DRM_VIA_DMA_BLIT 0x0e +#define DRM_VIA_BLIT_SYNC 0x0f #define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t) #define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t) @@ -89,6 +91,8 @@ #define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \ drm_via_cmdbuf_size_t) #define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t) +#define DRM_IOCTL_VIA_DMA_BLIT DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_DMA_BLIT, drm_via_dmablit_t) +#define DRM_IOCTL_VIA_BLIT_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_BLIT_SYNC, drm_via_blitsync_t) /* Indices into buf.Setup where various bits of state are mirrored per * context and per buffer. These can be fired at the card as a unit, @@ -103,8 +107,12 @@ #define VIA_BACK 0x2 #define VIA_DEPTH 0x4 #define VIA_STENCIL 0x8 -#define VIDEO 0 -#define AGP 1 +#define VIA_MEM_VIDEO 0 /* matches drm constant */ +#define VIA_MEM_AGP 1 /* matches drm constant */ +#define VIA_MEM_SYSTEM 2 +#define VIA_MEM_MIXED 3 +#define VIA_MEM_UNKNOWN 4 + typedef struct { uint32_t offset; uint32_t size; @@ -192,6 +200,9 @@ typedef struct _drm_via_sarea { unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS]; unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */ + /* Used bt the 3d driver only at this point, for pageflipping: + */ + unsigned int pfCurrentOffset; } drm_via_sarea_t; typedef struct _drm_via_cmdbuf_size { @@ -212,6 +223,16 @@ typedef enum { #define VIA_IRQ_FLAGS_MASK 0xF0000000 +enum drm_via_irqs { + drm_via_irq_hqv0 = 0, + drm_via_irq_hqv1, + drm_via_irq_dma0_dd, + drm_via_irq_dma0_td, + drm_via_irq_dma1_dd, + drm_via_irq_dma1_td, + drm_via_irq_num +}; + struct drm_via_wait_irq_request { unsigned irq; via_irq_seq_type_t type; @@ -224,20 +245,25 @@ typedef union drm_via_irqwait { struct drm_wait_vblank_reply reply; } drm_via_irqwait_t; -#ifdef __KERNEL__ - -int via_fb_init(DRM_IOCTL_ARGS); -int via_mem_alloc(DRM_IOCTL_ARGS); -int via_mem_free(DRM_IOCTL_ARGS); -int via_agp_init(DRM_IOCTL_ARGS); -int via_map_init(DRM_IOCTL_ARGS); -int via_decoder_futex(DRM_IOCTL_ARGS); -int via_dma_init(DRM_IOCTL_ARGS); -int via_cmdbuffer(DRM_IOCTL_ARGS); -int via_flush_ioctl(DRM_IOCTL_ARGS); -int via_pci_cmdbuffer(DRM_IOCTL_ARGS); -int via_cmdbuf_size(DRM_IOCTL_ARGS); -int via_wait_irq(DRM_IOCTL_ARGS); +typedef struct drm_via_blitsync { + uint32_t sync_handle; + unsigned engine; +} drm_via_blitsync_t; + +typedef struct drm_via_dmablit { + uint32_t num_lines; + uint32_t line_length; + + uint32_t fb_addr; + uint32_t fb_stride; + + unsigned char *mem_addr; + uint32_t mem_stride; + + int bounce_buffer; + int to_fb; + + drm_via_blitsync_t sync; +} drm_via_dmablit_t; -#endif #endif /* _VIA_DRM_H_ */ diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c index e8adebdba127..3f012255d315 100644 --- a/drivers/char/drm/via_drv.c +++ b/drivers/char/drm/via_drv.c @@ -38,25 +38,12 @@ static struct pci_device_id pciidlist[] = { viadrv_PCI_IDS }; -static drm_ioctl_desc_t ioctls[] = { - [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0} -}; - static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + .load = via_driver_load, + .unload = via_driver_unload, .context_ctor = via_init_context, .context_dtor = via_final_context, .vblank_wait = via_driver_vblank_wait, @@ -69,8 +56,7 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .ioctls = ioctls, - .num_ioctls = DRM_ARRAY_SIZE(ioctls), + .ioctls = via_ioctls, .fops = { .owner = THIS_MODULE, .open = drm_open, @@ -95,6 +81,7 @@ static struct drm_driver driver = { static int __init via_init(void) { + driver.num_ioctls = via_max_ioctl; via_init_command_verifier(); return drm_init(&driver); } diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 7d5daf43797e..0606c752dccb 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -24,24 +24,26 @@ #ifndef _VIA_DRV_H_ #define _VIA_DRV_H_ -#define DRIVER_AUTHOR "VIA" +#define DRIVER_AUTHOR "Various" #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20050523" +#define DRIVER_DATE "20051022" #define DRIVER_MAJOR 2 -#define DRIVER_MINOR 6 -#define DRIVER_PATCHLEVEL 3 +#define DRIVER_MINOR 7 +#define DRIVER_PATCHLEVEL 2 #include "via_verifier.h" +#include "via_dmablit.h" + #define VIA_PCI_BUF_SIZE 60000 #define VIA_FIRE_BUF_SIZE 1024 -#define VIA_NUM_IRQS 2 +#define VIA_NUM_IRQS 4 typedef struct drm_via_ring_buffer { - drm_map_t map; + drm_local_map_t map; char *virtual_start; } drm_via_ring_buffer_t; @@ -56,9 +58,9 @@ typedef struct drm_via_irq { typedef struct drm_via_private { drm_via_sarea_t *sarea_priv; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; unsigned long agpAddr; wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS]; char *dma_ptr; @@ -82,8 +84,15 @@ typedef struct drm_via_private { maskarray_t *irq_masks; uint32_t irq_enable_mask; uint32_t irq_pending_mask; + int *irq_map; + drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; } drm_via_private_t; +enum via_family { + VIA_OTHER = 0, + VIA_PRO_GROUP_A, +}; + /* VIA MMIO register access */ #define VIA_BASE ((dev_priv->mmio)) @@ -92,12 +101,31 @@ typedef struct drm_via_private { #define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg) #define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val) +extern drm_ioctl_desc_t via_ioctls[]; +extern int via_max_ioctl; + +extern int via_fb_init(DRM_IOCTL_ARGS); +extern int via_mem_alloc(DRM_IOCTL_ARGS); +extern int via_mem_free(DRM_IOCTL_ARGS); +extern int via_agp_init(DRM_IOCTL_ARGS); +extern int via_map_init(DRM_IOCTL_ARGS); +extern int via_decoder_futex(DRM_IOCTL_ARGS); +extern int via_dma_init(DRM_IOCTL_ARGS); +extern int via_cmdbuffer(DRM_IOCTL_ARGS); +extern int via_flush_ioctl(DRM_IOCTL_ARGS); +extern int via_pci_cmdbuffer(DRM_IOCTL_ARGS); +extern int via_cmdbuf_size(DRM_IOCTL_ARGS); +extern int via_wait_irq(DRM_IOCTL_ARGS); +extern int via_dma_blit_sync( DRM_IOCTL_ARGS ); +extern int via_dma_blit( DRM_IOCTL_ARGS ); + +extern int via_driver_load(drm_device_t *dev, unsigned long chipset); +extern int via_driver_unload(drm_device_t *dev); + extern int via_init_context(drm_device_t * dev, int context); extern int via_final_context(drm_device_t * dev, int context); extern int via_do_cleanup_map(drm_device_t * dev); -extern int via_map_init(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence); extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); @@ -111,8 +139,10 @@ extern int via_driver_dma_quiescent(drm_device_t * dev); extern void via_init_futex(drm_via_private_t * dev_priv); extern void via_cleanup_futex(drm_via_private_t * dev_priv); extern void via_release_futex(drm_via_private_t * dev_priv, int context); +extern int via_driver_irq_wait(drm_device_t * dev, unsigned int irq, + int force_sequence, unsigned int *sequence); -extern int via_parse_command_stream(drm_device_t * dev, const uint32_t * buf, - unsigned int size); +extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq); +extern void via_init_dmablit(drm_device_t *dev); #endif diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index d023add1929b..56d7e3daea12 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -50,6 +50,15 @@ #define VIA_IRQ_HQV1_ENABLE (1 << 25) #define VIA_IRQ_HQV0_PENDING (1 << 9) #define VIA_IRQ_HQV1_PENDING (1 << 10) +#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20) +#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21) +#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22) +#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23) +#define VIA_IRQ_DMA0_DD_PENDING (1 << 4) +#define VIA_IRQ_DMA0_TD_PENDING (1 << 5) +#define VIA_IRQ_DMA1_DD_PENDING (1 << 6) +#define VIA_IRQ_DMA1_TD_PENDING (1 << 7) + /* * Device-specific IRQs go here. This type might need to be extended with @@ -61,13 +70,24 @@ static maskarray_t via_pro_group_a_irqs[] = { {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000}, {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, - 0x00000000} + 0x00000000}, + {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, + {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, }; static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t); +static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; -static maskarray_t via_unichrome_irqs[] = { }; +static maskarray_t via_unichrome_irqs[] = { + {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, + {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} +}; static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t); +static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; static unsigned time_diff(struct timeval *now, struct timeval *then) { @@ -113,6 +133,11 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) atomic_inc(&cur_irq->irq_received); DRM_WAKEUP(&cur_irq->irq_queue); handled = 1; + if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) { + via_dmablit_handler(dev, 0, 1); + } else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) { + via_dmablit_handler(dev, 1, 1); + } } cur_irq++; } @@ -165,7 +190,7 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence) return ret; } -static int +int via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, unsigned int *sequence) { @@ -174,6 +199,7 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, drm_via_irq_t *cur_irq = dev_priv->via_irqs; int ret = 0; maskarray_t *masks = dev_priv->irq_masks; + int real_irq; DRM_DEBUG("%s\n", __FUNCTION__); @@ -182,15 +208,23 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, return DRM_ERR(EINVAL); } - if (irq >= dev_priv->num_irqs) { + if (irq >= drm_via_irq_num) { DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq); return DRM_ERR(EINVAL); } - cur_irq += irq; + real_irq = dev_priv->irq_map[irq]; + + if (real_irq < 0) { + DRM_ERROR("%s Video IRQ %d not available on this hardware.\n", + __FUNCTION__, irq); + return DRM_ERR(EINVAL); + } + + cur_irq += real_irq; - if (masks[irq][2] && !force_sequence) { + if (masks[real_irq][2] && !force_sequence) { DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ, ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4])); @@ -226,6 +260,8 @@ void via_driver_irq_preinstall(drm_device_t * dev) via_pro_group_a_irqs : via_unichrome_irqs; dev_priv->num_irqs = (dev_priv->pro_group_a) ? via_num_pro_group_a : via_num_unichrome; + dev_priv->irq_map = (dev_priv->pro_group_a) ? + via_irqmap_pro_group_a : via_irqmap_unichrome; for (i = 0; i < dev_priv->num_irqs; ++i) { atomic_set(&cur_irq->irq_received, 0); @@ -241,7 +277,7 @@ void via_driver_irq_preinstall(drm_device_t * dev) dev_priv->last_vblank_valid = 0; - // Clear VSync interrupt regs + /* Clear VSync interrupt regs */ status = VIA_READ(VIA_REG_INTERRUPT); VIA_WRITE(VIA_REG_INTERRUPT, status & ~(dev_priv->irq_enable_mask)); @@ -291,8 +327,7 @@ void via_driver_irq_uninstall(drm_device_t * dev) int via_wait_irq(DRM_IOCTL_ARGS) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; + DRM_DEVICE; drm_via_irqwait_t __user *argp = (void __user *)data; drm_via_irqwait_t irqwait; struct timeval now; diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c index 6bd6ac52ad1b..c6a08e96285b 100644 --- a/drivers/char/drm/via_map.c +++ b/drivers/char/drm/via_map.c @@ -27,16 +27,10 @@ static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init) { - drm_via_private_t *dev_priv; + drm_via_private_t *dev_priv = dev->dev_private; DRM_DEBUG("%s\n", __FUNCTION__); - dev_priv = drm_alloc(sizeof(drm_via_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) - return -ENOMEM; - - memset(dev_priv, 0, sizeof(drm_via_private_t)); - DRM_GETSAREA(); if (!dev_priv->sarea) { DRM_ERROR("could not find sarea!\n"); @@ -67,7 +61,8 @@ static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init) dev_priv->agpAddr = init->agpAddr; via_init_futex(dev_priv); - dev_priv->pro_group_a = (dev->pdev->device == 0x3118); + + via_init_dmablit(dev); dev->dev_private = (void *)dev_priv; return 0; @@ -75,15 +70,7 @@ static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init) int via_do_cleanup_map(drm_device_t * dev) { - if (dev->dev_private) { - - drm_via_private_t *dev_priv = dev->dev_private; - - via_dma_cleanup(dev); - - drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); - dev->dev_private = NULL; - } + via_dma_cleanup(dev); return 0; } @@ -107,3 +94,29 @@ int via_map_init(DRM_IOCTL_ARGS) return -EINVAL; } + +int via_driver_load(drm_device_t *dev, unsigned long chipset) +{ + drm_via_private_t *dev_priv; + + dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return DRM_ERR(ENOMEM); + + dev->dev_private = (void *)dev_priv; + + if (chipset == VIA_PRO_GROUP_A) + dev_priv->pro_group_a = 1; + + return 0; +} + +int via_driver_unload(drm_device_t *dev) +{ + drm_via_private_t *dev_priv = dev->dev_private; + + drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + + return 0; +} + diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c index 3baddacdff26..62e692556a1d 100644 --- a/drivers/char/drm/via_mm.c +++ b/drivers/char/drm/via_mm.c @@ -199,13 +199,13 @@ int via_mem_alloc(DRM_IOCTL_ARGS) sizeof(mem)); switch (mem.type) { - case VIDEO: + case VIA_MEM_VIDEO: if (via_fb_alloc(&mem) < 0) return -EFAULT; DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem)); return 0; - case AGP: + case VIA_MEM_AGP: if (via_agp_alloc(&mem) < 0) return -EFAULT; DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, @@ -232,7 +232,7 @@ static int via_fb_alloc(drm_via_mem_t * mem) if (block) { fb.offset = block->ofs; fb.free = (unsigned long)block; - if (!add_alloc_set(fb.context, VIDEO, fb.free)) { + if (!add_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) { DRM_DEBUG("adding to allocation set fails\n"); via_mmFreeMem((PMemBlock) fb.free); retval = -1; @@ -269,7 +269,7 @@ static int via_agp_alloc(drm_via_mem_t * mem) if (block) { agp.offset = block->ofs; agp.free = (unsigned long)block; - if (!add_alloc_set(agp.context, AGP, agp.free)) { + if (!add_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) { DRM_DEBUG("adding to allocation set fails\n"); via_mmFreeMem((PMemBlock) agp.free); retval = -1; @@ -297,11 +297,11 @@ int via_mem_free(DRM_IOCTL_ARGS) switch (mem.type) { - case VIDEO: + case VIA_MEM_VIDEO: if (via_fb_free(&mem) == 0) return 0; break; - case AGP: + case VIA_MEM_AGP: if (via_agp_free(&mem) == 0) return 0; break; @@ -329,7 +329,7 @@ static int via_fb_free(drm_via_mem_t * mem) via_mmFreeMem((PMemBlock) fb.free); - if (!del_alloc_set(fb.context, VIDEO, fb.free)) { + if (!del_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) { retval = -1; } @@ -352,7 +352,7 @@ static int via_agp_free(drm_via_mem_t * mem) via_mmFreeMem((PMemBlock) agp.free); - if (!del_alloc_set(agp.context, AGP, agp.free)) { + if (!del_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) { retval = -1; } diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c index 4ac495f297f7..70c897c88766 100644 --- a/drivers/char/drm/via_verifier.c +++ b/drivers/char/drm/via_verifier.c @@ -237,7 +237,7 @@ static hazard_t table3[256]; static __inline__ int eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words) { - if ((*buf - buf_end) >= num_words) { + if ((buf_end - *buf) >= num_words) { *buf += num_words; return 0; } @@ -249,14 +249,14 @@ eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words) * Partially stolen from drm_memory.h */ -static __inline__ drm_map_t *via_drm_lookup_agp_map(drm_via_state_t * seq, +static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq, unsigned long offset, unsigned long size, drm_device_t * dev) { struct list_head *list; drm_map_list_t *r_list; - drm_map_t *map = seq->map_cache; + drm_local_map_t *map = seq->map_cache; if (map && map->offset <= offset && (offset + size) <= (map->offset + map->size)) { diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h index eb4eda344345..256590fcc22a 100644 --- a/drivers/char/drm/via_verifier.h +++ b/drivers/char/drm/via_verifier.h @@ -47,7 +47,7 @@ typedef struct { int agp_texture; int multitex; drm_device_t *dev; - drm_map_t *map_cache; + drm_local_map_t *map_cache; uint32_t vertex_count; int agp; const uint32_t *buf_start; @@ -55,5 +55,7 @@ typedef struct { extern int via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t * dev, int agp); +extern int via_parse_command_stream(drm_device_t *dev, const uint32_t *buf, + unsigned int size); #endif diff --git a/drivers/char/drm/via_video.c b/drivers/char/drm/via_video.c index 7fab9fbdf424..300ac61b09ed 100644 --- a/drivers/char/drm/via_video.c +++ b/drivers/char/drm/via_video.c @@ -50,8 +50,11 @@ void via_release_futex(drm_via_private_t * dev_priv, int context) unsigned int i; volatile int *lock; + if (!dev_priv->sarea_priv) + return; + for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { - lock = (int *)XVMCLOCKPTR(dev_priv->sarea_priv, i); + lock = (volatile int *)XVMCLOCKPTR(dev_priv->sarea_priv, i); if ((_DRM_LOCKING_CONTEXT(*lock) == context)) { if (_DRM_LOCK_IS_HELD(*lock) && (*lock & _DRM_LOCK_CONT)) { @@ -79,7 +82,7 @@ int via_decoder_futex(DRM_IOCTL_ARGS) if (fx.lock > VIA_NR_XVMC_LOCKS) return -EFAULT; - lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock); + lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx.lock); switch (fx.func) { case VIA_FUTEX_WAIT: -- cgit v1.2.3 From a3c8ab4fe8f006d742c24be677518bfa9862e732 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 30 Nov 2005 09:55:22 -0800 Subject: IB/mthca: fix QP size limits for mem-free HCAs Unlike tavor, the max work queue size is an exact power of 2 for arbel mode, despite what the documentation (of the QUERY_DEV_LIM firmware command) says. Without this patch, on Arbel, we can start with a QP of a valid size and get above the reported limit after rounding to the next power of two. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cmd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 9ed34587fc5c..22ac72bc20c3 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -937,10 +937,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, if (err) goto out; - MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); - dev_lim->max_srq_sz = (1 << field) - 1; - MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); - dev_lim->max_qp_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET); dev_lim->reserved_qps = 1 << (field & 0xf); MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET); @@ -1056,6 +1052,10 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags); if (mthca_is_memfree(dev)) { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = 1 << field; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET); dev_lim->hca.arbel.resize_srq = field & 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET); @@ -1087,6 +1087,10 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, mthca_dbg(dev, "Max ICM size %lld MB\n", (unsigned long long) dev_lim->hca.arbel.max_icm_sz >> 20); } else { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = (1 << field) - 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET); dev_lim->hca.tavor.max_avs = 1 << (field & 0x3f); dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE; -- cgit v1.2.3 From 227eca83690da7dcbd698d3268e29402e0571723 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 30 Nov 2005 10:00:25 -0800 Subject: IB/cm: correct reported reject code Change reject code from TIMEOUT to CONSUMER_REJECT when destroying a cm_id in the process of connecting. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 02110e00d145..1fe21865d1f2 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -684,6 +684,13 @@ retest: cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); break; case IB_CM_REQ_SENT: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, + &cm_id_priv->av.port->cm_dev->ca_guid, + sizeof cm_id_priv->av.port->cm_dev->ca_guid, + NULL, 0); + break; case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: @@ -694,10 +701,8 @@ retest: case IB_CM_REP_RCVD: case IB_CM_MRA_REP_SENT: spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, - &cm_id_priv->av.port->cm_dev->ca_guid, - sizeof cm_id_priv->av.port->cm_dev->ca_guid, - NULL, 0); + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); break; case IB_CM_ESTABLISHED: spin_unlock_irqrestore(&cm_id_priv->lock, flags); -- cgit v1.2.3 From de1bb1a64c29bae4f5330c70bd1dc6a62954c9f4 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 30 Nov 2005 10:01:13 -0800 Subject: IB/cm: avoid reusing local ID Use an increasing local ID to avoid re-using identifiers while messages may still be outstanding on the old ID. Without this, a quick connect-disconnect-connect sequence can fail by matching messages for the new connection with the old connection. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/cm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 1fe21865d1f2..3a611fe5497e 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -308,10 +308,11 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv) { unsigned long flags; int ret; + static int next_id; do { spin_lock_irqsave(&cm.lock, flags); - ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 1, + ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++, (__force int *) &cm_id_priv->id.local_id); spin_unlock_irqrestore(&cm.lock, flags); } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); -- cgit v1.2.3 From 1a38416cea8ac801ae8f261074721f35317613dc Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Wed, 23 Nov 2005 12:36:00 -0500 Subject: [ACPI] SMP S3 resume: evaluate _WAK after INIT On SMP resume from S3, we reset (INIT) the non-boot processors to boot them cleanly. But the BIOS needs to execute _WAK after INIT in order to properly initialized these processors upon resume. http://bugzilla.kernel.org/show_bug.cgi?id=5651 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- kernel/power/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/power/main.c b/kernel/power/main.c index d253f3ae2fa5..9cb235cba4a9 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -133,10 +133,10 @@ static int suspend_enter(suspend_state_t state) static void suspend_finish(suspend_state_t state) { device_resume(); - if (pm_ops && pm_ops->finish) - pm_ops->finish(state); thaw_processes(); enable_nonboot_cpus(); + if (pm_ops && pm_ops->finish) + pm_ops->finish(state); pm_restore_console(); } -- cgit v1.2.3 From 05131ecc99ea9da7f45ba3058fe8a2c1d0ceeab8 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Sun, 23 Oct 2005 16:31:00 -0400 Subject: [ACPI] Avoid BIOS inflicted crashes by evaluating _PDC only once Linux invokes the AML _PDC method (Processor Driver Capabilities) to tell the BIOS what features it can handle. While the ACPI spec says nothing about the OS invoking _PDC multiple times, doing so with changing bits seems to hopelessly confuse the BIOS on multiple platforms up to and including crashing the system. Factor out the _PDC invocation so Linux invokes it only once. http://bugzilla.kernel.org/show_bug.cgi?id=5483 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- arch/i386/kernel/acpi/Makefile | 2 +- arch/i386/kernel/acpi/cstate.c | 58 ------------------ arch/i386/kernel/acpi/processor.c | 75 +++++++++++++++++++++++ arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 67 -------------------- arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 12 ---- arch/ia64/kernel/cpufreq/Makefile | 5 ++ arch/ia64/kernel/cpufreq/acpi-cpufreq.c | 51 --------------- arch/ia64/kernel/cpufreq/acpi-processor.c | 67 ++++++++++++++++++++ arch/x86_64/kernel/acpi/Makefile | 5 ++ arch/x86_64/kernel/acpi/processor.c | 72 ++++++++++++++++++++++ drivers/acpi/processor_core.c | 28 ++++----- drivers/acpi/processor_idle.c | 2 - drivers/acpi/processor_perflib.c | 2 - include/acpi/pdc_intel.h | 4 +- include/acpi/processor.h | 22 ++----- include/asm-i386/acpi.h | 2 +- 16 files changed, 243 insertions(+), 231 deletions(-) create mode 100644 arch/i386/kernel/acpi/processor.c create mode 100644 arch/ia64/kernel/cpufreq/acpi-processor.c create mode 100644 arch/x86_64/kernel/acpi/processor.c diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index 267ca48e1b6c..d51c7313cae8 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile @@ -3,6 +3,6 @@ obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o ifneq ($(CONFIG_ACPI_PROCESSOR),) -obj-y += cstate.o +obj-y += cstate.o processor.o endif diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c index 4c3036ba65df..25db49ef1770 100644 --- a/arch/i386/kernel/acpi/cstate.c +++ b/arch/i386/kernel/acpi/cstate.c @@ -14,64 +14,6 @@ #include #include -static void acpi_processor_power_init_intel_pdc(struct acpi_processor_power - *pow) -{ - struct acpi_object_list *obj_list; - union acpi_object *obj; - u32 *buf; - - /* allocate and initialize pdc. It will be used later. */ - obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); - if (!obj_list) { - printk(KERN_ERR "Memory allocation error\n"); - return; - } - - obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!obj) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj_list); - return; - } - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj); - kfree(obj_list); - return; - } - - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - buf[2] = ACPI_PDC_C_CAPABILITY_SMP; - - obj->type = ACPI_TYPE_BUFFER; - obj->buffer.length = 12; - obj->buffer.pointer = (u8 *) buf; - obj_list->count = 1; - obj_list->pointer = obj; - pow->pdc = obj_list; - - return; -} - -/* Initialize _PDC data based on the CPU vendor */ -void acpi_processor_power_init_pdc(struct acpi_processor_power *pow, - unsigned int cpu) -{ - struct cpuinfo_x86 *c = cpu_data + cpu; - - pow->pdc = NULL; - if (c->x86_vendor == X86_VENDOR_INTEL) - acpi_processor_power_init_intel_pdc(pow); - - return; -} - -EXPORT_SYMBOL(acpi_processor_power_init_pdc); - /* * Initialize bm_flags based on the CPU cache properties * On SMP it depends on cache configuration diff --git a/arch/i386/kernel/acpi/processor.c b/arch/i386/kernel/acpi/processor.c new file mode 100644 index 000000000000..9f4cc02717ec --- /dev/null +++ b/arch/i386/kernel/acpi/processor.c @@ -0,0 +1,75 @@ +/* + * arch/i386/kernel/acpi/processor.c + * + * Copyright (C) 2005 Intel Corporation + * Venkatesh Pallipadi + * - Added _PDC for platforms with Intel CPUs + */ + +#include +#include +#include +#include + +#include +#include + +static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) { + printk(KERN_ERR "Memory allocation error\n"); + return; + } + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj_list); + return; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj); + kfree(obj_list); + return; + } + + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] = ACPI_PDC_C_CAPABILITY_SMP; + + if (cpu_has(c, X86_FEATURE_EST)) + buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + pr->pdc = obj_list; + + return; +} + +/* Initialize _PDC data based on the CPU vendor */ +void arch_acpi_processor_init_pdc(struct acpi_processor *pr) +{ + unsigned int cpu = pr->id; + struct cpuinfo_x86 *c = cpu_data + cpu; + + pr->pdc = NULL; + if (c->x86_vendor == X86_VENDOR_INTEL) + init_intel_pdc(pr, c); + + return; +} + +EXPORT_SYMBOL(arch_acpi_processor_init_pdc); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 871366b83b3f..31ce890865d5 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -297,68 +297,6 @@ acpi_cpufreq_guess_freq ( } -/* - * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities - * of this driver - * @perf: processor-specific acpi_io_data struct - * @cpu: CPU being initialized - * - * To avoid issues with legacy OSes, some BIOSes require to be informed of - * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC - * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in - * driver/acpi/processor.c - */ -static void -acpi_processor_cpu_init_pdc_est( - struct acpi_processor_performance *perf, - unsigned int cpu, - struct acpi_object_list *obj_list - ) -{ - union acpi_object *obj; - u32 *buf; - struct cpuinfo_x86 *c = cpu_data + cpu; - dprintk("acpi_processor_cpu_init_pdc_est\n"); - - if (!cpu_has(c, X86_FEATURE_EST)) - return; - - /* Initialize pdc. It will be used later. */ - if (!obj_list) - return; - - if (!(obj_list->count && obj_list->pointer)) - return; - - obj = obj_list->pointer; - if ((obj->buffer.length == 12) && obj->buffer.pointer) { - buf = (u32 *)obj->buffer.pointer; - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; - perf->pdc = obj_list; - } - return; -} - - -/* CPU specific PDC initialization */ -static void -acpi_processor_cpu_init_pdc( - struct acpi_processor_performance *perf, - unsigned int cpu, - struct acpi_object_list *obj_list - ) -{ - struct cpuinfo_x86 *c = cpu_data + cpu; - dprintk("acpi_processor_cpu_init_pdc\n"); - perf->pdc = NULL; - if (cpu_has(c, X86_FEATURE_EST)) - acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list); - return; -} - - static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -373,9 +311,6 @@ acpi_cpufreq_cpu_init ( struct acpi_object_list arg_list = {1, &arg0}; dprintk("acpi_cpufreq_cpu_init\n"); - /* setup arg_list for _PDC settings */ - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -383,9 +318,7 @@ acpi_cpufreq_cpu_init ( acpi_io_data[cpu] = data; - acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list); result = acpi_processor_register_performance(&data->acpi_data, cpu); - data->acpi_data.pdc = NULL; if (result) goto err_free; diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index edb9873e27e3..d93023438c4f 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -364,22 +364,10 @@ static struct acpi_processor_performance p; */ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { - union acpi_object arg0 = {ACPI_TYPE_BUFFER}; - u32 arg0_buf[3]; - struct acpi_object_list arg_list = {1, &arg0}; unsigned long cur_freq; int result = 0, i; unsigned int cpu = policy->cpu; - /* _PDC settings */ - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; - arg0_buf[0] = ACPI_PDC_REVISION_ID; - arg0_buf[1] = 1; - arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP_MSR; - - p.pdc = &arg_list; - /* register with ACPI core */ if (acpi_processor_register_performance(&p, cpu)) { dprintk(KERN_INFO PFX "obtaining ACPI data failed\n"); diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile index f748d34c02f0..642648361ed3 100644 --- a/arch/ia64/kernel/cpufreq/Makefile +++ b/arch/ia64/kernel/cpufreq/Makefile @@ -1 +1,6 @@ obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += acpi-processor.o +endif + diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index da4d5cf80a48..5a1bf815282d 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c @@ -269,48 +269,6 @@ acpi_cpufreq_verify ( } -/* - * processor_init_pdc - let BIOS know about the SMP capabilities - * of this driver - * @perf: processor-specific acpi_io_data struct - * @cpu: CPU being initialized - * - * To avoid issues with legacy OSes, some BIOSes require to be informed of - * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC - * accordingly. Actual call to _PDC is done in driver/acpi/processor.c - */ -static void -processor_init_pdc ( - struct acpi_processor_performance *perf, - unsigned int cpu, - struct acpi_object_list *obj_list - ) -{ - union acpi_object *obj; - u32 *buf; - - dprintk("processor_init_pdc\n"); - - perf->pdc = NULL; - /* Initialize pdc. It will be used later. */ - if (!obj_list) - return; - - if (!(obj_list->count && obj_list->pointer)) - return; - - obj = obj_list->pointer; - if ((obj->buffer.length == 12) && obj->buffer.pointer) { - buf = (u32 *)obj->buffer.pointer; - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; - perf->pdc = obj_list; - } - return; -} - - static int acpi_cpufreq_cpu_init ( struct cpufreq_policy *policy) @@ -320,14 +278,7 @@ acpi_cpufreq_cpu_init ( struct cpufreq_acpi_io *data; unsigned int result = 0; - union acpi_object arg0 = {ACPI_TYPE_BUFFER}; - u32 arg0_buf[3]; - struct acpi_object_list arg_list = {1, &arg0}; - dprintk("acpi_cpufreq_cpu_init\n"); - /* setup arg_list for _PDC settings */ - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -337,9 +288,7 @@ acpi_cpufreq_cpu_init ( acpi_io_data[cpu] = data; - processor_init_pdc(&data->acpi_data, cpu, &arg_list); result = acpi_processor_register_performance(&data->acpi_data, cpu); - data->acpi_data.pdc = NULL; if (result) goto err_free; diff --git a/arch/ia64/kernel/cpufreq/acpi-processor.c b/arch/ia64/kernel/cpufreq/acpi-processor.c new file mode 100644 index 000000000000..e683630c8ce2 --- /dev/null +++ b/arch/ia64/kernel/cpufreq/acpi-processor.c @@ -0,0 +1,67 @@ +/* + * arch/ia64/kernel/cpufreq/processor.c + * + * Copyright (C) 2005 Intel Corporation + * Venkatesh Pallipadi + * - Added _PDC for platforms with Intel CPUs + */ + +#include +#include +#include +#include + +#include +#include + +static void init_intel_pdc(struct acpi_processor *pr) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) { + printk(KERN_ERR "Memory allocation error\n"); + return; + } + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj_list); + return; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj); + kfree(obj_list); + return; + } + + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + pr->pdc = obj_list; + + return; +} + +/* Initialize _PDC data based on the CPU vendor */ +void arch_acpi_processor_init_pdc(struct acpi_processor *pr) +{ + pr->pdc = NULL; + init_intel_pdc(pr); + return; +} + +EXPORT_SYMBOL(arch_acpi_processor_init_pdc); diff --git a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile index 7da9ace890bd..4fe97071f297 100644 --- a/arch/x86_64/kernel/acpi/Makefile +++ b/arch/x86_64/kernel/acpi/Makefile @@ -1,3 +1,8 @@ obj-y := boot.o boot-y := ../../../i386/kernel/acpi/boot.o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += processor.o +endif + diff --git a/arch/x86_64/kernel/acpi/processor.c b/arch/x86_64/kernel/acpi/processor.c new file mode 100644 index 000000000000..3bdc2baa5bb1 --- /dev/null +++ b/arch/x86_64/kernel/acpi/processor.c @@ -0,0 +1,72 @@ +/* + * arch/x86_64/kernel/acpi/processor.c + * + * Copyright (C) 2005 Intel Corporation + * Venkatesh Pallipadi + * - Added _PDC for platforms with Intel CPUs + */ + +#include +#include +#include +#include + +#include +#include + +static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) { + printk(KERN_ERR "Memory allocation error\n"); + return; + } + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj_list); + return; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj); + kfree(obj_list); + return; + } + + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + pr->pdc = obj_list; + + return; +} + +/* Initialize _PDC data based on the CPU vendor */ +void arch_acpi_processor_init_pdc(struct acpi_processor *pr) +{ + unsigned int cpu = pr->id; + struct cpuinfo_x86 *c = cpu_data + cpu; + + pr->pdc = NULL; + if (c->x86_vendor == X86_VENDOR_INTEL && cpu_has(c, X86_FEATURE_EST)) + init_intel_pdc(pr, c); + + return; +} + +EXPORT_SYMBOL(arch_acpi_processor_init_pdc); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 421792562642..66bbda78507a 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -253,31 +253,21 @@ static int acpi_processor_errata(struct acpi_processor *pr) * _PDC is required for a BIOS-OS handshake for most of the newer * ACPI processor features. */ - -int acpi_processor_set_pdc(struct acpi_processor *pr, - struct acpi_object_list *pdc_in) +static int acpi_processor_set_pdc(struct acpi_processor *pr) { + struct acpi_object_list *pdc_in = pr->pdc; acpi_status status = AE_OK; - u32 arg0_buf[3]; - union acpi_object arg0 = { ACPI_TYPE_BUFFER }; - struct acpi_object_list no_object = { 1, &arg0 }; - struct acpi_object_list *pdc; ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; - arg0_buf[0] = ACPI_PDC_REVISION_ID; - arg0_buf[1] = 0; - arg0_buf[2] = 0; - - pdc = (pdc_in) ? pdc_in : &no_object; + if (!pdc_in) + return_VALUE(status); - status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); + status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL); - if ((ACPI_FAILURE(status)) && (pdc_in)) + if (ACPI_FAILURE(status)) ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Error evaluating _PDC, using legacy perf. control...\n")); + "Could not evaluate _PDC, using legacy perf. control...\n")); return_VALUE(status); } @@ -574,6 +564,10 @@ static int acpi_processor_start(struct acpi_device *device) "Error installing device notify handler\n")); } + /* _PDC call should be done before doing anything else (if reqd.). */ + arch_acpi_processor_init_pdc(pr); + acpi_processor_set_pdc(pr); + acpi_processor_power_init(pr, device); if (pr->flags.throttling) { diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 70d8a6ec0920..1915c377bfc6 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1014,8 +1014,6 @@ int acpi_processor_power_init(struct acpi_processor *pr, } } - acpi_processor_power_init_pdc(&(pr->power), pr->id); - acpi_processor_set_pdc(pr, pr->power.pdc); acpi_processor_get_power_info(pr); /* diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 22c7bb66c200..532370734c68 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -315,8 +315,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) if (!pr || !pr->performance || !pr->handle) return_VALUE(-EINVAL); - acpi_processor_set_pdc(pr, pr->performance->pdc); - status = acpi_get_handle(pr->handle, "_PCT", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h index 91f4a12a99a1..3fa81d55cd0c 100644 --- a/include/acpi/pdc_intel.h +++ b/include/acpi/pdc_intel.h @@ -15,9 +15,7 @@ #define ACPI_PDC_C_C1_FFH (0x0100) #define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ - ACPI_PDC_C_C1_HALT) - -#define ACPI_PDC_EST_CAPABILITY_SMP_MSR (ACPI_PDC_EST_CAPABILITY_SMP | \ + ACPI_PDC_C_C1_HALT | \ ACPI_PDC_P_FFH) #define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 7a00d5089de9..82a9b7d430ec 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -62,9 +62,6 @@ struct acpi_processor_power { u32 bm_activity; int count; struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; - - /* the _PDC objects passed by the driver, if any */ - struct acpi_object_list *pdc; }; /* Performance Management */ @@ -96,8 +93,6 @@ struct acpi_processor_performance { unsigned int state_count; struct acpi_processor_px *states; - /* the _PDC objects passed by the driver, if any */ - struct acpi_object_list *pdc; }; /* Throttling Control */ @@ -151,6 +146,9 @@ struct acpi_processor { struct acpi_processor_performance *performance; struct acpi_processor_throttling throttling; struct acpi_processor_limit limit; + + /* the _PDC objects for this processor, if any */ + struct acpi_object_list *pdc; }; struct acpi_processor_errata { @@ -178,22 +176,12 @@ int acpi_processor_notify_smm(struct module *calling_module); extern struct acpi_processor *processors[NR_CPUS]; extern struct acpi_processor_errata errata; -int acpi_processor_set_pdc(struct acpi_processor *pr, - struct acpi_object_list *pdc_in); +void arch_acpi_processor_init_pdc(struct acpi_processor *pr); -#ifdef ARCH_HAS_POWER_PDC_INIT -void acpi_processor_power_init_pdc(struct acpi_processor_power *pow, - unsigned int cpu); +#ifdef ARCH_HAS_POWER_INIT void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, unsigned int cpu); #else -static inline void acpi_processor_power_init_pdc(struct acpi_processor_power - *pow, unsigned int cpu) -{ - pow->pdc = NULL; - return; -} - static inline void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, unsigned int cpu) diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index df4ed323aa4d..55059abf9c95 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -179,7 +179,7 @@ extern void acpi_reserve_bootmem(void); extern u8 x86_acpiid_to_apicid[]; -#define ARCH_HAS_POWER_PDC_INIT 1 +#define ARCH_HAS_POWER_INIT 1 #endif /*__KERNEL__*/ -- cgit v1.2.3 From 83451879ab213e152c6fe5c743f257ba58d7acd1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Dec 2005 17:12:59 -0800 Subject: [CIFS] Use fsuid (fsgid) more consistently instead of uid/gid in assembling smb requests when setuids and Linux protocol extensions enabled and in checking more matching sessions in multiuser mount mode. Pointed out by Shaggy. Signed-off-by: Steve French --- fs/cifs/CHANGES | 6 ++++++ fs/cifs/cifsfs.h | 2 +- fs/cifs/dir.c | 8 ++++---- fs/cifs/inode.c | 4 ++-- fs/cifs/misc.c | 8 ++++---- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 943ef9b82244..8bef2f3a4130 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,7 @@ +Version 1.40 +------------ +Use fsuid (fsgid) more consistently instead of uid (gid). + Version 1.39 ------------ Defer close of a file handle slightly if pending writes depend on that handle @@ -7,6 +11,8 @@ Fix SFU style symlinks and mknod needed for servers which do not support the CIFS Unix Extensions. Fix setfacl/getfacl on bigendian. Timeout negative dentries so files that the client sees as deleted but that later get created on the server will be recognized. Add client side permission check on setattr. +Timeout stuck requests better (where server has never responded or sent corrupt +responses) Version 1.38 ------------ diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 9ec40e0e54fc..821a8eb22559 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -99,5 +99,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.39" +#define CIFS_VERSION "1.40" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 32cc96cafa3e..fed55e3c53df 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -3,7 +3,7 @@ * * vfs operations that deal with dentries * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -200,8 +200,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, (oplock & CIFS_CREATE_ACTION)) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - (__u64)current->euid, - (__u64)current->egid, + (__u64)current->fsuid, + (__u64)current->fsgid, 0 /* dev */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -325,7 +325,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, else if (pTcon->ses->capabilities & CAP_UNIX) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, - mode,(__u64)current->euid,(__u64)current->egid, + mode,(__u64)current->fsuid,(__u64)current->fsgid, device_number, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 411c1f7f84da..d1e995757436 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -750,8 +750,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - (__u64)current->euid, - (__u64)current->egid, + (__u64)current->fsuid, + (__u64)current->fsgid, 0 /* dev_t */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 94baf6c8ecbd..9af37f864688 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1,7 +1,7 @@ /* * fs/cifs/misc.c * - * Copyright (C) International Business Machines Corp., 2002,2004 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -348,12 +348,12 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , /* BB Add support for establishing new tCon and SMB Session */ /* with userid/password pairs found on the smb session */ /* for other target tcp/ip addresses BB */ - if(current->uid != treeCon->ses->linux_uid) { - cFYI(1,("Multiuser mode and UID did not match tcon uid ")); + if(current->fsuid != treeCon->ses->linux_uid) { + cFYI(1,("Multiuser mode and UID did not match tcon uid")); read_lock(&GlobalSMBSeslock); list_for_each(temp_item, &GlobalSMBSessionList) { ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); - if(ses->linux_uid == current->uid) { + if(ses->linux_uid == current->fsuid) { if(ses->server == treeCon->ses->server) { cFYI(1,("found matching uid substitute right smb_uid")); buffer->Uid = ses->Suid; -- cgit v1.2.3 From cf82478840188f8c8494c1d7a668a8ae170d0e07 Mon Sep 17 00:00:00 2001 From: Janosch Machowinski Date: Sat, 20 Aug 2005 08:02:00 -0400 Subject: [ACPI] handle BIOS with implicit C1 in _CST The ASUS M6Ne specifies C2, implying C1 but not explicitly specifying it. http://bugzilla.kernel.org/show_bug.cgi?id=4485 Signed-off-by: Janosch Machowinski Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 64 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 83fd1b6c10c4..40c9f9ca5965 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -532,18 +532,10 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) if (!pr->pblk) return_VALUE(-ENODEV); - memset(pr->power.states, 0, sizeof(pr->power.states)); - /* if info is obtained from pblk/fadt, type equals state */ - pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; - /* the C0 state only exists as a filler in our array, - * and all processors need to support C1 */ - pr->power.states[ACPI_STATE_C0].valid = 1; - pr->power.states[ACPI_STATE_C1].valid = 1; - #ifndef CONFIG_HOTPLUG_CPU /* * Check for P_LVL2_UP flag before entering C2 and above on @@ -573,12 +565,11 @@ static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr) { ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_default_c1"); + /* Zero initialize all the C-states info. */ memset(pr->power.states, 0, sizeof(pr->power.states)); - /* if info is obtained from pblk/fadt, type equals state */ + /* set the first C-State to C1 */ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; - pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; - pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; /* the C0 state only exists as a filler in our array, * and all processors need to support C1 */ @@ -592,6 +583,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) { acpi_status status = 0; acpi_integer count; + int current_count; int i; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *cst; @@ -601,10 +593,12 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) if (nocst) return_VALUE(-ENODEV); - pr->power.count = 0; - for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++) - memset(&(pr->power.states[i]), 0, - sizeof(struct acpi_processor_cx)); + current_count = 1; + + /* Zero initialize C2 onwards and prepare for fresh CST lookup */ + for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++) + memset(&(pr->power.states[i]), 0, + sizeof(struct acpi_processor_cx)); status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer); if (ACPI_FAILURE(status)) { @@ -632,16 +626,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) goto end; } - /* We support up to ACPI_PROCESSOR_MAX_POWER. */ - if (count > ACPI_PROCESSOR_MAX_POWER) { - printk(KERN_WARNING - "Limiting number of power states to max (%d)\n", - ACPI_PROCESSOR_MAX_POWER); - printk(KERN_WARNING - "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); - count = ACPI_PROCESSOR_MAX_POWER; - } - /* Tell driver that at least _CST is supported. */ pr->flags.has_cst = 1; @@ -685,7 +669,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) continue; - if ((cx.type < ACPI_STATE_C1) || (cx.type > ACPI_STATE_C3)) + if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3)) continue; obj = (union acpi_object *)&(element->package.elements[2]); @@ -700,15 +684,28 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) cx.power = obj->integer.value; - (pr->power.count)++; - memcpy(&(pr->power.states[pr->power.count]), &cx, sizeof(cx)); + current_count++; + memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx)); + + /* + * We support total ACPI_PROCESSOR_MAX_POWER - 1 + * (From 1 through ACPI_PROCESSOR_MAX_POWER - 1) + */ + if (current_count >= (ACPI_PROCESSOR_MAX_POWER - 1)) { + printk(KERN_WARNING + "Limiting number of power states to max (%d)\n", + ACPI_PROCESSOR_MAX_POWER); + printk(KERN_WARNING + "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); + break; + } } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n", - pr->power.count)); + current_count)); /* Validate number of power states discovered */ - if (pr->power.count < 2) + if (current_count < 2) status = -EFAULT; end: @@ -859,12 +856,13 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) /* NOTE: the idle thread may not be running while calling * this function */ + /* Adding C1 state */ + acpi_processor_get_power_info_default_c1(pr); result = acpi_processor_get_power_info_cst(pr); if (result == -ENODEV) - result = acpi_processor_get_power_info_fadt(pr); + acpi_processor_get_power_info_fadt(pr); - if ((result) || (acpi_processor_power_verify(pr) < 2)) - result = acpi_processor_get_power_info_default_c1(pr); + pr->power.count = acpi_processor_power_verify(pr); /* * Set Default Policy -- cgit v1.2.3 From 06a2a3855e20ed3df380d69b37130ba86bec8001 Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Tue, 27 Sep 2005 00:43:00 -0400 Subject: [ACPI] Disable EC burst mode w/o disabling EC interrupts Need to de-couple the concept of polling/interrupts vs burst/non-burst. http://bugzilla.kernel.org/show_bug.cgi?id=4980 Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7e1a445955bc..6edfbe6f187c 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -213,19 +213,14 @@ static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event) smp_mb(); switch (event) { - case ACPI_EC_EVENT_OBF: - if (acpi_ec_read_status(ec) & event) { - ec->burst.expect_event = 0; - return_VALUE(0); - } - break; - case ACPI_EC_EVENT_IBE: if (~acpi_ec_read_status(ec) & event) { ec->burst.expect_event = 0; return_VALUE(0); } break; + default: + break; } result = wait_event_timeout(ec->burst.wait, @@ -255,7 +250,11 @@ static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event) return_VALUE(-ETIME); } -static int acpi_ec_enter_burst_mode(union acpi_ec *ec) +/* + * Note: samsung nv5000 doesn't work with ec burst mode. + * http://bugzilla.kernel.org/show_bug.cgi?id=4980 + */ +int acpi_ec_enter_burst_mode(union acpi_ec *ec) { u32 tmp = 0; int status = 0; @@ -270,8 +269,6 @@ static int acpi_ec_enter_burst_mode(union acpi_ec *ec) acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->common.command_addr); status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (status) - return_VALUE(-EINVAL); acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr); if (tmp != 0x90) { /* Burst ACK byte */ return_VALUE(-EINVAL); @@ -285,13 +282,25 @@ static int acpi_ec_enter_burst_mode(union acpi_ec *ec) return_VALUE(-1); } -static int acpi_ec_leave_burst_mode(union acpi_ec *ec) +int acpi_ec_leave_burst_mode(union acpi_ec *ec) { + int status = 0; ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode"); + status = acpi_ec_read_status(ec); + if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){ + status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + if(status) + goto end; + acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); + acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + } atomic_set(&ec->burst.leaving_burst, 1); return_VALUE(0); +end: + printk("leave burst_mode:error \n"); + return_VALUE(-1); } static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) @@ -424,7 +433,6 @@ static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data) WARN_ON(in_interrupt()); down(&ec->burst.sem); - acpi_ec_enter_burst_mode(ec); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { printk("read EC, IB not empty\n"); @@ -448,7 +456,6 @@ static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data) *data, address)); end: - acpi_ec_leave_burst_mode(ec); up(&ec->burst.sem); if (ec->common.global_lock) @@ -476,8 +483,6 @@ static int acpi_ec_burst_write(union acpi_ec *ec, u8 address, u8 data) WARN_ON(in_interrupt()); down(&ec->burst.sem); - acpi_ec_enter_burst_mode(ec); - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { printk("write EC, IB not empty\n"); @@ -500,7 +505,6 @@ static int acpi_ec_burst_write(union acpi_ec *ec, u8 address, u8 data) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", data, address)); - acpi_ec_leave_burst_mode(ec); up(&ec->burst.sem); if (ec->common.global_lock) -- cgit v1.2.3 From bf8206791750854bc6668266b694e8fe2cacb924 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Dec 2005 22:32:42 -0800 Subject: [CIFS] Kerberos and CIFS ACL support part 1 Signed-off-by: Steve French --- fs/cifs/README | 12 +++++++++++- fs/cifs/cifsacl.h | 36 ++++++++++++++++++++++++++++++++++++ fs/cifs/cifspdu.h | 2 +- fs/cifs/connect.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 fs/cifs/cifsacl.h diff --git a/fs/cifs/README b/fs/cifs/README index e5d09a2fc7a5..b0070d1b149d 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -436,7 +436,17 @@ A partial list of the supported mount options follows: SFU does). In the future the bottom 9 bits of the mode mode also will be emulated using queries of the security descriptor (ACL). - +sec Security mode. Allowed values are: + none attempt to connection as a null user (no name) + krb5 Use Kerberos version 5 authentication + krb5i Use Kerberos authentication and packet signing + ntlm Use NTLM password hashing (default) + ntlmi Use NTLM password hashing with signing (if + /proc/fs/cifs/PacketSigningEnabled on or if + server requires signing also can be the default) + ntlmv2 Use NTLMv2 password hashing + ntlmv2i Use NTLMv2 password hashing with packet signing + The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h new file mode 100644 index 000000000000..4cfcdf2e6304 --- /dev/null +++ b/fs/cifs/cifsacl.h @@ -0,0 +1,36 @@ +/* + * fs/cifs/cifsacl.h + * + * Copyright (c) International Business Machines Corp., 2005 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CIFSACL_H +#define _CIFSACL_H + +struct cifs_sid { + __u8 revision; /* revision level */ + __u8 num_subauths; + __u8 authority[6]; + __u8 sub_auth[4]; + /* next sub_auth if any ... */ +} __attribute__((packed)); + +/* everyone */ +const cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; +/* group users */ +const cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 33e1859fd2f6..5253e779b3aa 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifspdu.h * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c467de857610..651f3b6cebed 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -82,6 +82,12 @@ struct smb_vol { unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned sfu_emul:1; + unsigned krb5:1; + unsigned ntlm:1; + unsigned ntlmv2:1; + unsigned nullauth:1; /* attempt to authenticate with null user */ + unsigned sign:1; + unsigned seal:1; /* encrypt */ unsigned nocase; /* request case insensitive filenames */ unsigned nobrl; /* disable sending byte range locks to srv */ unsigned int rsize; @@ -777,7 +783,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; - + vol->ntlm = TRUE; /* default is always to request posix paths. */ vol->posix_paths = 1; @@ -903,6 +909,39 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) printk(KERN_WARNING "CIFS: ip address too long\n"); return 1; } + } else if (strnicmp(data, "sec", 3) == 0) { + if (!value || !*value) { + cERROR(1,("no security value specified")); + continue; + } else if (strnicmp(value, "krb5i", 5) == 0) { + vol->sign = 1; + vol->krb5 = 1; + } else if (strnicmp(value, "krb5p", 5) == 0) { + /* vol->seal = 1; + vol->krb5 = 1; */ + cERROR(1,("Krb5 cifs privacy not supported")); + return 1; + } else if (strnicmp(value, "krb5", 4) == 0) { + vol->krb5 = 1; + } else if (strnicmp(value, "ntlmv2i", 7) == 0) { + vol->ntlmv2 = 1; + vol->sign = 1; + } else if (strnicmp(value, "ntlmv2", 6) == 0) { + vol->ntlmv2 = 1; + } else if (strnicmp(value, "ntlmi", 5) == 0) { + vol->ntlm = 1; + vol->sign = 1; + } else if (strnicmp(value, "ntlm", 4) == 0) { + /* ntlm is default so can be turned off too */ + vol->ntlm = 1; + } else if (strnicmp(value, "nontlm", 6) == 0) { + vol->ntlm = 0; + } else if (strnicmp(value, "none", 4) == 0) { + vol->nullauth = 1; + } else { + cERROR(1,("bad security option: %s", value)); + return 1; + } } else if ((strnicmp(data, "unc", 3) == 0) || (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "path", 4) == 0)) { @@ -1546,7 +1585,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cFYI(1, ("Username: %s ", volume_info.username)); } else { - cifserror("No username specified "); + cifserror("No username specified"); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ kfree(volume_info.UNC); @@ -1587,7 +1626,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return -EINVAL; } else /* which servers DFS root would we conect to */ { cERROR(1, - ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); + ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); kfree(volume_info.UNC); kfree(volume_info.password); FreeXid(xid); @@ -1626,7 +1665,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (srvTcp) { - cFYI(1, ("Existing tcp session with server found ")); + cFYI(1, ("Existing tcp session with server found")); } else { /* create socket */ if(volume_info.port) sin_server.sin_port = htons(volume_info.port); @@ -1689,11 +1728,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (existingCifsSes) { pSesInfo = existingCifsSes; - cFYI(1, ("Existing smb sess found ")); + cFYI(1, ("Existing smb sess found")); kfree(volume_info.password); /* volume_info.UNC freed at end of function */ } else if (!rc) { - cFYI(1, ("Existing smb sess not found ")); + cFYI(1, ("Existing smb sess not found")); pSesInfo = sesInfoAlloc(); if (pSesInfo == NULL) rc = -ENOMEM; @@ -1777,7 +1816,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); if (tcon) { - cFYI(1, ("Found match on UNC path ")); + cFYI(1, ("Found match on UNC path")); /* we can have only one retry value for a connection to a share so for resources mounted more than once to the same server share the last value passed in -- cgit v1.2.3 From 84afc29b185334f489975a003b128e1b15e24a54 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 2 Dec 2005 13:32:45 -0800 Subject: [CIFS] Readpages and readir performance improvements - eliminate extra memcpy. Part 1 Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifsencrypt.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/cifsproto.h | 6 +++--- fs/cifs/cifssmb.c | 5 +---- fs/cifs/file.c | 6 ------ fs/cifs/transport.c | 19 ++++++++++-------- 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8bef2f3a4130..1d2137561c55 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,6 +1,7 @@ Version 1.40 ------------ -Use fsuid (fsgid) more consistently instead of uid (gid). +Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance +of readpages by eliminating one extra memcpy. Version 1.39 ------------ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index fe2bb7c4c912..a2c24858d40f 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifsencrypt.c * - * Copyright (C) International Business Machines Corp., 2003 + * Copyright (C) International Business Machines Corp., 2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -82,6 +82,59 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, return rc; } +static int cifs_calc_signature2(const struct kvec * iov, int n_vec, + const char * key, char * signature) +{ + struct MD5Context context; + + if((iov == NULL) || (signature == NULL)) + return -EINVAL; + + MD5Init(&context); + MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + +/* MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); */ /* BB FIXME BB */ + + MD5Final(signature,&context); + + return -EOPNOTSUPP; +/* return 0; */ +} + + +int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server, + __u32 * pexpected_response_sequence_number) +{ + int rc = 0; + char smb_signature[20]; + struct smb_hdr * cifs_pdu = iov[0].iov_base; + + if((cifs_pdu == NULL) || (server == NULL)) + return -EINVAL; + + if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) + return rc; + + spin_lock(&GlobalMid_Lock); + cifs_pdu->Signature.Sequence.SequenceNumber = + cpu_to_le32(server->sequence_number); + cifs_pdu->Signature.Sequence.Reserved = 0; + + *pexpected_response_sequence_number = server->sequence_number++; + server->sequence_number++; + spin_unlock(&GlobalMid_Lock); + + rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, + smb_signature); + if(rc) + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + else + memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); + + return rc; + +} + int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, __u32 expected_sequence_number) { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1b73f4f4c5ce..c058f8a45b2b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -48,7 +48,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, struct smb_hdr * /* out */ , int * /* bytes returned */ , const int long_op); extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, - struct kvec *, int /* nvec */, + struct kvec *, int /* nvec to send */, int * /* bytes returned */ , const int long_op); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); @@ -237,12 +237,10 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const __u64 lseek, unsigned int *nbytes, const char *buf, const char __user *ubuf, const int long_op); -#ifdef CONFIG_CIFS_EXPERIMENTAL extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 offset, unsigned int *nbytes, struct kvec *iov, const int nvec, const int long_op); -#endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, const struct nls_table *nls_codepage, @@ -269,6 +267,8 @@ extern void tconInfoFree(struct cifsTconInfo *); extern int cifs_reconnect(struct TCP_Server_Info *server); extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); +extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, + __u32 *); extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6867e556d37e..3565d3bf2e32 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1155,7 +1155,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, @@ -1223,7 +1222,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; *nbytes += le16_to_cpu(pSMBr->Count); - } + } cifs_small_buf_release(pSMB); @@ -1234,8 +1233,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, } -#endif /* CIFS_EXPERIMENTAL */ - int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 smb_file_id, const __u64 len, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 14a1c72ced92..b67be3d8c019 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -870,7 +870,6 @@ static ssize_t cifs_write(struct file *file, const char *write_data, if (rc != 0) break; } -#ifdef CONFIG_CIFS_EXPERIMENTAL /* BB FIXME We can not sign across two buffers yet */ if((experimEnabled) && ((pTcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { @@ -889,7 +888,6 @@ static ssize_t cifs_write(struct file *file, const char *write_data, iov, 1, long_op); } else /* BB FIXME fixup indentation of line below */ -#endif rc = CIFSSMBWrite(xid, pTcon, open_file->netfid, min_t(const int, cifs_sb->wsize, @@ -1026,7 +1024,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL static int cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) { @@ -1229,7 +1226,6 @@ retry: return rc; } -#endif static int cifs_writepage(struct page* page, struct writeback_control *wbc) { @@ -1875,9 +1871,7 @@ struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, -#ifdef CONFIG_CIFS_EXPERIMENTAL .writepages = cifs_writepages, -#endif .prepare_write = cifs_prepare_write, .commit_write = cifs_commit_write, .set_page_dirty = __set_page_dirty_nobuffers, diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index f8871196098c..0abfbf4e4a49 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -206,7 +206,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL static int smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, struct sockaddr *sin) @@ -392,8 +391,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, return -ENOMEM; } -/* BB FIXME */ -/* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ + rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 @@ -492,11 +490,17 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, if (midQ->resp_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { + in_buf->smb_buf_length = receive_len; - /* BB verify that length would not overrun small buf */ - memcpy((char *)in_buf + 4, - (char *)midQ->resp_buf + 4, - receive_len); + if(receive_len > 500) { + /* use multiple buffers on way out */ + } else { + memcpy((char *)in_buf + 4, + (char *)midQ->resp_buf + 4, + receive_len); + iov[0].iov_len = receive_len + 4; + iov[1].iov_len = 0; + } dump_smb(in_buf, 80); /* convert the length into a more usable form */ @@ -549,7 +553,6 @@ out_unlock2: return rc; } -#endif /* CIFS_EXPERIMENTAL */ int SendReceive(const unsigned int xid, struct cifsSesInfo *ses, -- cgit v1.2.3 From 4498eed50a114565debd38f173acd62cce6e7cb8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 3 Dec 2005 13:58:57 -0800 Subject: [CIFS] Add extended stats (STATS2) for total buffer allocations for better performance debugging. Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 4 ++++ fs/cifs/cifsfs.c | 6 ++++++ fs/cifs/cifsglob.h | 8 ++++++-- fs/cifs/misc.c | 7 +++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 22a444a3fe4c..7f19f2547d01 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -219,6 +219,10 @@ cifs_stats_write(struct file *file, const char __user *buffer, if (c == '1' || c == 'y' || c == 'Y' || c == '0') { read_lock(&GlobalSMBSeslock); +#ifdef CONFIG_CIFS_STATS2 + atomic_set(&totBufAllocCount, 0); + atomic_set(&totSmBufAllocCount, 0); +#endif /* CONFIG_CIFS_STATS2 */ list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2a13a2bac8f1..ba90903909a6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -954,6 +954,12 @@ init_cifs(void) atomic_set(&tconInfoReconnectCount, 0); atomic_set(&bufAllocCount, 0); + atomic_set(&smBufAllocCount, 0); +#ifdef CONFIG_CIFS_STATS2 + atomic_set(&totBufAllocCount, 0); + atomic_set(&totSmBufAllocCount, 0); +#endif /* CONFIG_CIFS_STATS2 */ + atomic_set(&midCount, 0); GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1ba08f8c5bc4..c011c278af4c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -505,8 +505,12 @@ GLOBAL_EXTERN atomic_t tcpSesReconnectCount; GLOBAL_EXTERN atomic_t tconInfoReconnectCount; /* Various Debug counters to remove someday (BB) */ -GLOBAL_EXTERN atomic_t bufAllocCount; -GLOBAL_EXTERN atomic_t smBufAllocCount; +GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ +#ifdef CONFIG_CIFS_STATS2 +GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ +GLOBAL_EXTERN atomic_t totSmBufAllocCount; +#endif +GLOBAL_EXTERN atomic_t smBufAllocCount; GLOBAL_EXTERN atomic_t midCount; /* Misc globals */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 9af37f864688..ac5a72a299a3 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -161,6 +161,9 @@ cifs_buf_get(void) if (ret_buf) { memset(ret_buf, 0, sizeof(struct smb_hdr) + 3); atomic_inc(&bufAllocCount); +#ifdef CONFIG_CIFS_STATS2 + atomic_inc(&totBufAllocCount); +#endif /* CONFIG_CIFS_STATS2 */ } return ret_buf; @@ -195,6 +198,10 @@ cifs_small_buf_get(void) /* No need to clear memory here, cleared in header assemble */ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ atomic_inc(&smBufAllocCount); +#ifdef CONFIG_CIFS_STATS2 + atomic_inc(&totSmBufAllocCount); +#endif /* CONFIG_CIFS_STATS2 */ + } return ret_buf; } -- cgit v1.2.3 From 07475ffba5800c53573180dd521273642adcd0e9 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 3 Dec 2005 14:11:37 -0800 Subject: [CIFS] Display large/small total buffer allocations in /proc/fs/cifs/Stats when CONFIG_CIFS_STATS2 is on (helps in debugging performance) Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7f19f2547d01..6f5d81f5eacb 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -280,6 +280,14 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, smBufAllocCount.counter,cifs_min_small); length += item_length; buf += item_length; +#ifdef CONFIG_CIFS_STATS2 + item_length = sprintf(buf, "Total Large %d Small %d Allocations\n", + atomic_read(&totBufAllocCount), + atomic_read(&totSmBufAllocCount)); + length += item_length; + buf += item_length; +#endif /* CONFIG_CIFS_STATS2 */ + item_length = sprintf(buf,"Operations (MIDs): %d\n", midCount.counter); -- cgit v1.2.3 From 02b28a33aae93a3b53068e0858d62f8bcaef60a3 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 5 Dec 2005 16:33:04 -0500 Subject: [ACPI] Embedded Controller (EC) driver syntax update "intr" largely replaces "burst" for syntax to follow semantics "poll" largely replaces "polling" for economy of expression append "interrupt mode" or "polling mode" to dmesg line no functional changes Signed-off-by: Len Brown --- drivers/acpi/ec.c | 233 +++++++++++++++++++++++++++--------------------------- 1 file changed, 117 insertions(+), 116 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6edfbe6f187c..bb3963b49a98 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -60,20 +60,20 @@ ACPI_MODULE_NAME("acpi_ec") #define ACPI_EC_BURST_ENABLE 0x82 #define ACPI_EC_BURST_DISABLE 0x83 #define ACPI_EC_COMMAND_QUERY 0x84 -#define EC_POLLING 0xFF -#define EC_BURST 0x00 +#define EC_POLL 0xFF +#define EC_INTR 0x00 static int acpi_ec_remove(struct acpi_device *device, int type); static int acpi_ec_start(struct acpi_device *device); static int acpi_ec_stop(struct acpi_device *device, int type); -static int acpi_ec_burst_add(struct acpi_device *device); -static int acpi_ec_polling_add(struct acpi_device *device); +static int acpi_ec_intr_add(struct acpi_device *device); +static int acpi_ec_poll_add(struct acpi_device *device); static struct acpi_driver acpi_ec_driver = { .name = ACPI_EC_DRIVER_NAME, .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { - .add = acpi_ec_polling_add, + .add = acpi_ec_poll_add, .remove = acpi_ec_remove, .start = acpi_ec_start, .stop = acpi_ec_stop, @@ -105,7 +105,7 @@ union acpi_ec { atomic_t pending_gpe; struct semaphore sem; wait_queue_head_t wait; - } burst; + } intr; struct { u32 mode; @@ -117,37 +117,37 @@ union acpi_ec { struct acpi_generic_address data_addr; unsigned long global_lock; spinlock_t lock; - } polling; + } poll; }; -static int acpi_ec_polling_wait(union acpi_ec *ec, u8 event); -static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event); -static int acpi_ec_polling_read(union acpi_ec *ec, u8 address, u32 * data); -static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data); -static int acpi_ec_polling_write(union acpi_ec *ec, u8 address, u8 data); -static int acpi_ec_burst_write(union acpi_ec *ec, u8 address, u8 data); -static int acpi_ec_polling_query(union acpi_ec *ec, u32 * data); -static int acpi_ec_burst_query(union acpi_ec *ec, u32 * data); -static void acpi_ec_gpe_polling_query(void *ec_cxt); -static void acpi_ec_gpe_burst_query(void *ec_cxt); -static u32 acpi_ec_gpe_polling_handler(void *data); -static u32 acpi_ec_gpe_burst_handler(void *data); +static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event); +static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event); +static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data); +static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data); +static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data); +static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data); +static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data); +static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data); +static void acpi_ec_gpe_poll_query(void *ec_cxt); +static void acpi_ec_gpe_intr_query(void *ec_cxt); +static u32 acpi_ec_gpe_poll_handler(void *data); +static u32 acpi_ec_gpe_intr_handler(void *data); static acpi_status __init -acpi_fake_ecdt_polling_callback(acpi_handle handle, +acpi_fake_ecdt_poll_callback(acpi_handle handle, u32 Level, void *context, void **retval); static acpi_status __init -acpi_fake_ecdt_burst_callback(acpi_handle handle, +acpi_fake_ecdt_intr_callback(acpi_handle handle, u32 Level, void *context, void **retval); -static int __init acpi_ec_polling_get_real_ecdt(void); -static int __init acpi_ec_burst_get_real_ecdt(void); +static int __init acpi_ec_poll_get_real_ecdt(void); +static int __init acpi_ec_intr_get_real_ecdt(void); /* If we find an EC via the ECDT, we need to keep a ptr to its context */ static union acpi_ec *ec_ecdt; /* External interfaces use first EC only, so remember */ static struct acpi_device *first_ec; -static int acpi_ec_polling_mode = EC_POLLING; +static int acpi_ec_poll_mode = EC_POLL; /* -------------------------------------------------------------------------- Transaction Management @@ -163,13 +163,13 @@ static inline u32 acpi_ec_read_status(union acpi_ec *ec) static int acpi_ec_wait(union acpi_ec *ec, u8 event) { - if (acpi_ec_polling_mode) - return acpi_ec_polling_wait(ec, event); + if (acpi_ec_poll_mode) + return acpi_ec_poll_wait(ec, event); else - return acpi_ec_burst_wait(ec, event); + return acpi_ec_intr_wait(ec, event); } -static int acpi_ec_polling_wait(union acpi_ec *ec, u8 event) +static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event) { u32 acpi_ec_status = 0; u32 i = ACPI_EC_UDELAY_COUNT; @@ -203,19 +203,19 @@ static int acpi_ec_polling_wait(union acpi_ec *ec, u8 event) return -ETIME; } -static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event) +static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event) { int result = 0; ACPI_FUNCTION_TRACE("acpi_ec_wait"); - ec->burst.expect_event = event; + ec->intr.expect_event = event; smp_mb(); switch (event) { case ACPI_EC_EVENT_IBE: if (~acpi_ec_read_status(ec) & event) { - ec->burst.expect_event = 0; + ec->intr.expect_event = 0; return_VALUE(0); } break; @@ -223,11 +223,11 @@ static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event) break; } - result = wait_event_timeout(ec->burst.wait, - !ec->burst.expect_event, + result = wait_event_timeout(ec->intr.wait, + !ec->intr.expect_event, msecs_to_jiffies(ACPI_EC_DELAY)); - ec->burst.expect_event = 0; + ec->intr.expect_event = 0; smp_mb(); /* @@ -250,6 +250,7 @@ static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event) return_VALUE(-ETIME); } +#ifdef ACPI_FUTURE_USAGE /* * Note: samsung nv5000 doesn't work with ec burst mode. * http://bugzilla.kernel.org/show_bug.cgi?id=4980 @@ -275,7 +276,7 @@ int acpi_ec_enter_burst_mode(union acpi_ec *ec) } } - atomic_set(&ec->burst.leaving_burst, 0); + atomic_set(&ec->intr.leaving_burst, 0); return_VALUE(0); end: printk("Error in acpi_ec_wait\n"); @@ -296,28 +297,29 @@ int acpi_ec_leave_burst_mode(union acpi_ec *ec) acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr); acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); } - atomic_set(&ec->burst.leaving_burst, 1); + atomic_set(&ec->intr.leaving_burst, 1); return_VALUE(0); end: printk("leave burst_mode:error \n"); return_VALUE(-1); } +#endif /* ACPI_FUTURE_USAGE */ static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data) { - if (acpi_ec_polling_mode) - return acpi_ec_polling_read(ec, address, data); + if (acpi_ec_poll_mode) + return acpi_ec_poll_read(ec, address, data); else - return acpi_ec_burst_read(ec, address, data); + return acpi_ec_intr_read(ec, address, data); } static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data) { - if (acpi_ec_polling_mode) - return acpi_ec_polling_write(ec, address, data); + if (acpi_ec_poll_mode) + return acpi_ec_poll_write(ec, address, data); else - return acpi_ec_burst_write(ec, address, data); + return acpi_ec_intr_write(ec, address, data); } -static int acpi_ec_polling_read(union acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data) { acpi_status status = AE_OK; int result = 0; @@ -337,7 +339,7 @@ static int acpi_ec_polling_read(union acpi_ec *ec, u8 address, u32 * data) return_VALUE(-ENODEV); } - spin_lock_irqsave(&ec->polling.lock, flags); + spin_lock_irqsave(&ec->poll.lock, flags); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->common.command_addr); @@ -356,7 +358,7 @@ static int acpi_ec_polling_read(union acpi_ec *ec, u8 address, u32 * data) *data, address)); end: - spin_unlock_irqrestore(&ec->polling.lock, flags); + spin_unlock_irqrestore(&ec->poll.lock, flags); if (ec->common.global_lock) acpi_release_global_lock(glk); @@ -364,7 +366,7 @@ static int acpi_ec_polling_read(union acpi_ec *ec, u8 address, u32 * data) return_VALUE(result); } -static int acpi_ec_polling_write(union acpi_ec *ec, u8 address, u8 data) +static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data) { int result = 0; acpi_status status = AE_OK; @@ -382,7 +384,7 @@ static int acpi_ec_polling_write(union acpi_ec *ec, u8 address, u8 data) return_VALUE(-ENODEV); } - spin_lock_irqsave(&ec->polling.lock, flags); + spin_lock_irqsave(&ec->poll.lock, flags); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->common.command_addr); @@ -404,7 +406,7 @@ static int acpi_ec_polling_write(union acpi_ec *ec, u8 address, u8 data) data, address)); end: - spin_unlock_irqrestore(&ec->polling.lock, flags); + spin_unlock_irqrestore(&ec->poll.lock, flags); if (ec->common.global_lock) acpi_release_global_lock(glk); @@ -412,7 +414,7 @@ static int acpi_ec_polling_write(union acpi_ec *ec, u8 address, u8 data) return_VALUE(result); } -static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data) +static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) { int status = 0; u32 glk; @@ -431,7 +433,7 @@ static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data) } WARN_ON(in_interrupt()); - down(&ec->burst.sem); + down(&ec->intr.sem); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { @@ -456,7 +458,7 @@ static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data) *data, address)); end: - up(&ec->burst.sem); + up(&ec->intr.sem); if (ec->common.global_lock) acpi_release_global_lock(glk); @@ -464,7 +466,7 @@ static int acpi_ec_burst_read(union acpi_ec *ec, u8 address, u32 * data) return_VALUE(status); } -static int acpi_ec_burst_write(union acpi_ec *ec, u8 address, u8 data) +static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data) { int status = 0; u32 glk; @@ -481,7 +483,7 @@ static int acpi_ec_burst_write(union acpi_ec *ec, u8 address, u8 data) } WARN_ON(in_interrupt()); - down(&ec->burst.sem); + down(&ec->intr.sem); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { @@ -505,7 +507,7 @@ static int acpi_ec_burst_write(union acpi_ec *ec, u8 address, u8 data) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", data, address)); - up(&ec->burst.sem); + up(&ec->intr.sem); if (ec->common.global_lock) acpi_release_global_lock(glk); @@ -557,12 +559,12 @@ EXPORT_SYMBOL(ec_write); static int acpi_ec_query(union acpi_ec *ec, u32 * data) { - if (acpi_ec_polling_mode) - return acpi_ec_polling_query(ec, data); + if (acpi_ec_poll_mode) + return acpi_ec_poll_query(ec, data); else - return acpi_ec_burst_query(ec, data); + return acpi_ec_intr_query(ec, data); } -static int acpi_ec_polling_query(union acpi_ec *ec, u32 * data) +static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data) { int result = 0; acpi_status status = AE_OK; @@ -587,7 +589,7 @@ static int acpi_ec_polling_query(union acpi_ec *ec, u32 * data) * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ - spin_lock_irqsave(&ec->polling.lock, flags); + spin_lock_irqsave(&ec->poll.lock, flags); acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->common.command_addr); @@ -600,14 +602,14 @@ static int acpi_ec_polling_query(union acpi_ec *ec, u32 * data) result = -ENODATA; end: - spin_unlock_irqrestore(&ec->polling.lock, flags); + spin_unlock_irqrestore(&ec->poll.lock, flags); if (ec->common.global_lock) acpi_release_global_lock(glk); return_VALUE(result); } -static int acpi_ec_burst_query(union acpi_ec *ec, u32 * data) +static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data) { int status = 0; u32 glk; @@ -624,7 +626,7 @@ static int acpi_ec_burst_query(union acpi_ec *ec, u32 * data) return_VALUE(-ENODEV); } - down(&ec->burst.sem); + down(&ec->intr.sem); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { @@ -649,7 +651,7 @@ static int acpi_ec_burst_query(union acpi_ec *ec, u32 * data) status = -ENODATA; end: - up(&ec->burst.sem); + up(&ec->intr.sem); if (ec->common.global_lock) acpi_release_global_lock(glk); @@ -668,13 +670,13 @@ union acpi_ec_query_data { static void acpi_ec_gpe_query(void *ec_cxt) { - if (acpi_ec_polling_mode) - acpi_ec_gpe_polling_query(ec_cxt); + if (acpi_ec_poll_mode) + acpi_ec_gpe_poll_query(ec_cxt); else - acpi_ec_gpe_burst_query(ec_cxt); + acpi_ec_gpe_intr_query(ec_cxt); } -static void acpi_ec_gpe_polling_query(void *ec_cxt) +static void acpi_ec_gpe_poll_query(void *ec_cxt) { union acpi_ec *ec = (union acpi_ec *)ec_cxt; u32 value = 0; @@ -689,9 +691,9 @@ static void acpi_ec_gpe_polling_query(void *ec_cxt) if (!ec_cxt) goto end; - spin_lock_irqsave(&ec->polling.lock, flags); + spin_lock_irqsave(&ec->poll.lock, flags); acpi_hw_low_level_read(8, &value, &ec->common.command_addr); - spin_unlock_irqrestore(&ec->polling.lock, flags); + spin_unlock_irqrestore(&ec->poll.lock, flags); /* TBD: Implement asynch events! * NOTE: All we care about are EC-SCI's. Other EC events are @@ -715,7 +717,7 @@ static void acpi_ec_gpe_polling_query(void *ec_cxt) end: acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR); } -static void acpi_ec_gpe_burst_query(void *ec_cxt) +static void acpi_ec_gpe_intr_query(void *ec_cxt) { union acpi_ec *ec = (union acpi_ec *)ec_cxt; u32 value; @@ -740,18 +742,18 @@ static void acpi_ec_gpe_burst_query(void *ec_cxt) acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL); end: - atomic_dec(&ec->burst.pending_gpe); + atomic_dec(&ec->intr.pending_gpe); return; } static u32 acpi_ec_gpe_handler(void *data) { - if (acpi_ec_polling_mode) - return acpi_ec_gpe_polling_handler(data); + if (acpi_ec_poll_mode) + return acpi_ec_gpe_poll_handler(data); else - return acpi_ec_gpe_burst_handler(data); + return acpi_ec_gpe_intr_handler(data); } -static u32 acpi_ec_gpe_polling_handler(void *data) +static u32 acpi_ec_gpe_poll_handler(void *data) { acpi_status status = AE_OK; union acpi_ec *ec = (union acpi_ec *)data; @@ -769,7 +771,7 @@ static u32 acpi_ec_gpe_polling_handler(void *data) else return ACPI_INTERRUPT_NOT_HANDLED; } -static u32 acpi_ec_gpe_burst_handler(void *data) +static u32 acpi_ec_gpe_intr_handler(void *data) { acpi_status status = AE_OK; u32 value; @@ -781,22 +783,22 @@ static u32 acpi_ec_gpe_burst_handler(void *data) acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); value = acpi_ec_read_status(ec); - switch (ec->burst.expect_event) { + switch (ec->intr.expect_event) { case ACPI_EC_EVENT_OBF: if (!(value & ACPI_EC_FLAG_OBF)) break; case ACPI_EC_EVENT_IBE: if ((value & ACPI_EC_FLAG_IBF)) break; - ec->burst.expect_event = 0; - wake_up(&ec->burst.wait); + ec->intr.expect_event = 0; + wake_up(&ec->intr.wait); return ACPI_INTERRUPT_HANDLED; default: break; } if (value & ACPI_EC_FLAG_SCI) { - atomic_add(1, &ec->burst.pending_gpe); + atomic_add(1, &ec->intr.pending_gpe); status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); return status == AE_OK ? @@ -984,7 +986,7 @@ static int acpi_ec_remove_fs(struct acpi_device *device) Driver Interface -------------------------------------------------------------------------- */ -static int acpi_ec_polling_add(struct acpi_device *device) +static int acpi_ec_poll_add(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; @@ -1003,7 +1005,7 @@ static int acpi_ec_polling_add(struct acpi_device *device) ec->common.handle = device->handle; ec->common.uid = -1; - spin_lock_init(&ec->polling.lock); + spin_lock_init(&ec->poll.lock); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; @@ -1042,7 +1044,7 @@ static int acpi_ec_polling_add(struct acpi_device *device) if (result) goto end; - printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n", + printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n", acpi_device_name(device), acpi_device_bid(device), (u32) ec->common.gpe_bit); @@ -1055,7 +1057,7 @@ static int acpi_ec_polling_add(struct acpi_device *device) return_VALUE(result); } -static int acpi_ec_burst_add(struct acpi_device *device) +static int acpi_ec_intr_add(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; @@ -1074,10 +1076,10 @@ static int acpi_ec_burst_add(struct acpi_device *device) ec->common.handle = device->handle; ec->common.uid = -1; - atomic_set(&ec->burst.pending_gpe, 0); - atomic_set(&ec->burst.leaving_burst, 1); - init_MUTEX(&ec->burst.sem); - init_waitqueue_head(&ec->burst.wait); + atomic_set(&ec->intr.pending_gpe, 0); + atomic_set(&ec->intr.leaving_burst, 1); + init_MUTEX(&ec->intr.sem); + init_waitqueue_head(&ec->intr.wait); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; @@ -1116,8 +1118,7 @@ static int acpi_ec_burst_add(struct acpi_device *device) if (result) goto end; - printk("burst-mode-ec-10-Aug\n"); - printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n", + printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n", acpi_device_name(device), acpi_device_bid(device), (u32) ec->common.gpe_bit); @@ -1271,16 +1272,16 @@ acpi_fake_ecdt_callback(acpi_handle handle, u32 Level, void *context, void **retval) { - if (acpi_ec_polling_mode) - return acpi_fake_ecdt_polling_callback(handle, + if (acpi_ec_poll_mode) + return acpi_fake_ecdt_poll_callback(handle, Level, context, retval); else - return acpi_fake_ecdt_burst_callback(handle, + return acpi_fake_ecdt_intr_callback(handle, Level, context, retval); } static acpi_status __init -acpi_fake_ecdt_polling_callback(acpi_handle handle, +acpi_fake_ecdt_poll_callback(acpi_handle handle, u32 Level, void *context, void **retval) { acpi_status status; @@ -1299,7 +1300,7 @@ acpi_fake_ecdt_polling_callback(acpi_handle handle, &ec_ecdt->common.gpe_bit); if (ACPI_FAILURE(status)) return status; - spin_lock_init(&ec_ecdt->polling.lock); + spin_lock_init(&ec_ecdt->poll.lock); ec_ecdt->common.global_lock = TRUE; ec_ecdt->common.handle = handle; @@ -1312,13 +1313,13 @@ acpi_fake_ecdt_polling_callback(acpi_handle handle, } static acpi_status __init -acpi_fake_ecdt_burst_callback(acpi_handle handle, +acpi_fake_ecdt_intr_callback(acpi_handle handle, u32 Level, void *context, void **retval) { acpi_status status; - init_MUTEX(&ec_ecdt->burst.sem); - init_waitqueue_head(&ec_ecdt->burst.wait); + init_MUTEX(&ec_ecdt->intr.sem); + init_waitqueue_head(&ec_ecdt->intr.wait); status = acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_ec_io_ports, ec_ecdt); if (ACPI_FAILURE(status)) @@ -1384,13 +1385,13 @@ static int __init acpi_ec_fake_ecdt(void) static int __init acpi_ec_get_real_ecdt(void) { - if (acpi_ec_polling_mode) - return acpi_ec_polling_get_real_ecdt(); + if (acpi_ec_poll_mode) + return acpi_ec_poll_get_real_ecdt(); else - return acpi_ec_burst_get_real_ecdt(); + return acpi_ec_intr_get_real_ecdt(); } -static int __init acpi_ec_polling_get_real_ecdt(void) +static int __init acpi_ec_poll_get_real_ecdt(void) { acpi_status status; struct acpi_table_ecdt *ecdt_ptr; @@ -1415,7 +1416,7 @@ static int __init acpi_ec_polling_get_real_ecdt(void) ec_ecdt->common.status_addr = ecdt_ptr->ec_control; ec_ecdt->common.data_addr = ecdt_ptr->ec_data; ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit; - spin_lock_init(&ec_ecdt->polling.lock); + spin_lock_init(&ec_ecdt->poll.lock); /* use the GL just to be safe */ ec_ecdt->common.global_lock = TRUE; ec_ecdt->common.uid = ecdt_ptr->uid; @@ -1435,7 +1436,7 @@ static int __init acpi_ec_polling_get_real_ecdt(void) return -ENODEV; } -static int __init acpi_ec_burst_get_real_ecdt(void) +static int __init acpi_ec_intr_get_real_ecdt(void) { acpi_status status; struct acpi_table_ecdt *ecdt_ptr; @@ -1456,8 +1457,8 @@ static int __init acpi_ec_burst_get_real_ecdt(void) return -ENOMEM; memset(ec_ecdt, 0, sizeof(union acpi_ec)); - init_MUTEX(&ec_ecdt->burst.sem); - init_waitqueue_head(&ec_ecdt->burst.wait); + init_MUTEX(&ec_ecdt->intr.sem); + init_waitqueue_head(&ec_ecdt->intr.wait); ec_ecdt->common.command_addr = ecdt_ptr->ec_control; ec_ecdt->common.status_addr = ecdt_ptr->ec_control; ec_ecdt->common.data_addr = ecdt_ptr->ec_data; @@ -1575,22 +1576,22 @@ static int __init acpi_fake_ecdt_setup(char *str) } __setup("acpi_fake_ecdt", acpi_fake_ecdt_setup); -static int __init acpi_ec_set_polling_mode(char *str) +static int __init acpi_ec_set_intr_mode(char *str) { - int burst; + int intr; - if (!get_option(&str, &burst)) + if (!get_option(&str, &intr)) return 0; - if (burst) { - acpi_ec_polling_mode = EC_BURST; - acpi_ec_driver.ops.add = acpi_ec_burst_add; + if (intr) { + acpi_ec_poll_mode = EC_INTR; + acpi_ec_driver.ops.add = acpi_ec_intr_add; } else { - acpi_ec_polling_mode = EC_POLLING; - acpi_ec_driver.ops.add = acpi_ec_polling_add; + acpi_ec_poll_mode = EC_POLL; + acpi_ec_driver.ops.add = acpi_ec_poll_add; } - printk(KERN_INFO PREFIX "EC %s mode.\n", burst ? "burst" : "polling"); + printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling"); return 0; } -__setup("ec_burst=", acpi_ec_set_polling_mode); +__setup("ec_burst=", acpi_ec_set_intr_mode); -- cgit v1.2.3 From 53f11d4ff8797bcceaf014e62bd39f16ce84baec Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 5 Dec 2005 16:46:36 -0500 Subject: [ACPI] Enable Embedded Controller (EC) interrupt mode by default "ec_intr=0" reverts to polling "ec_burst=" no longer exists. Signed-off-by: Len Brown Acked-by: Luming Yu --- Documentation/kernel-parameters.txt | 5 +++++ drivers/acpi/ec.c | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5dffcfefc3c7..2ad64efdf183 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -452,6 +452,11 @@ running once the system is up. eata= [HW,SCSI] + ec_intr= [HW,ACPI] ACPI Embedded Controller interrupt mode + Format: + 0: polling mode + non-0: interrupt mode (default) + eda= [HW,PS2] edb= [HW,PS2] diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index bb3963b49a98..d4366ad4edcd 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -73,7 +73,7 @@ static struct acpi_driver acpi_ec_driver = { .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { - .add = acpi_ec_poll_add, + .add = acpi_ec_intr_add, .remove = acpi_ec_remove, .start = acpi_ec_start, .stop = acpi_ec_stop, @@ -147,7 +147,7 @@ static union acpi_ec *ec_ecdt; /* External interfaces use first EC only, so remember */ static struct acpi_device *first_ec; -static int acpi_ec_poll_mode = EC_POLL; +static int acpi_ec_poll_mode = EC_INTR; /* -------------------------------------------------------------------------- Transaction Management @@ -1594,4 +1594,4 @@ static int __init acpi_ec_set_intr_mode(char *str) return 0; } -__setup("ec_burst=", acpi_ec_set_intr_mode); +__setup("ec_intr=", acpi_ec_set_intr_mode); -- cgit v1.2.3 From 1e8df53c925024548cca4374f03bed1a7e2b0c45 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 5 Dec 2005 16:47:46 -0500 Subject: [ACPI] Embedded Controller (EC) driver printk syntax update no functional changes Signed-off-by: Len Brown --- drivers/acpi/ec.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index d4366ad4edcd..93fcaec6d589 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -279,7 +279,7 @@ int acpi_ec_enter_burst_mode(union acpi_ec *ec) atomic_set(&ec->intr.leaving_burst, 0); return_VALUE(0); end: - printk("Error in acpi_ec_wait\n"); + printk(KERN_WARNING PREFIX "Error in acpi_ec_wait\n"); return_VALUE(-1); } @@ -300,7 +300,7 @@ int acpi_ec_leave_burst_mode(union acpi_ec *ec) atomic_set(&ec->intr.leaving_burst, 1); return_VALUE(0); end: - printk("leave burst_mode:error \n"); + printk(KERN_WARNING PREFIX "leave burst_mode:error\n"); return_VALUE(-1); } #endif /* ACPI_FUTURE_USAGE */ @@ -437,20 +437,20 @@ static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data) status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { - printk("read EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); goto end; } acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->common.command_addr); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { - printk("read EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); } acpi_hw_low_level_write(8, address, &ec->common.data_addr); status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); if (status) { - printk("read EC, OB not full\n"); + printk(KERN_DEBUG PREFIX "read EC, OB not full\n"); goto end; } acpi_hw_low_level_read(8, data, &ec->common.data_addr); @@ -487,19 +487,19 @@ static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data) status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { - printk("write EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); } acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->common.command_addr); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { - printk("write EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); } acpi_hw_low_level_write(8, address, &ec->common.data_addr); status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { - printk("write EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX "write EC, IB not empty\n"); } acpi_hw_low_level_write(8, data, &ec->common.data_addr); @@ -630,7 +630,7 @@ static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data) status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); if (status) { - printk("query EC, IB not empty\n"); + printk(KERN_DEBUG PREFIX "query EC, IB not empty\n"); goto end; } /* @@ -642,7 +642,7 @@ static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data) &ec->common.command_addr); status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); if (status) { - printk("query EC, OB not full\n"); + printk(KERN_DEBUG PREFIX "query EC, OB not full\n"); goto end; } -- cgit v1.2.3 From c82e6abfb3182c84d0204b178363086b09881a4a Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Thu, 1 Dec 2005 18:16:00 -0500 Subject: [ACPI] IA64 ZX1 buildfix for _PDC patch http://bugzilla.kernel.org/show_bug.cgi?id=5483 ZX1 config doesn't include cpufreq, so move move acpi-processor.c up out of ia64/cpufreq directory. no functional changes Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- arch/ia64/kernel/Makefile | 5 +++ arch/ia64/kernel/acpi-processor.c | 67 +++++++++++++++++++++++++++++++ arch/ia64/kernel/cpufreq/Makefile | 4 -- arch/ia64/kernel/cpufreq/acpi-processor.c | 67 ------------------------------- 4 files changed, 72 insertions(+), 71 deletions(-) create mode 100644 arch/ia64/kernel/acpi-processor.c delete mode 100644 arch/ia64/kernel/cpufreq/acpi-processor.c diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 307514f7a282..09a0dbc17fb6 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -13,6 +13,11 @@ obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += acpi-ext.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += acpi-processor.o +endif + obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/ia64/kernel/acpi-processor.c b/arch/ia64/kernel/acpi-processor.c new file mode 100644 index 000000000000..e683630c8ce2 --- /dev/null +++ b/arch/ia64/kernel/acpi-processor.c @@ -0,0 +1,67 @@ +/* + * arch/ia64/kernel/cpufreq/processor.c + * + * Copyright (C) 2005 Intel Corporation + * Venkatesh Pallipadi + * - Added _PDC for platforms with Intel CPUs + */ + +#include +#include +#include +#include + +#include +#include + +static void init_intel_pdc(struct acpi_processor *pr) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) { + printk(KERN_ERR "Memory allocation error\n"); + return; + } + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj_list); + return; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj); + kfree(obj_list); + return; + } + + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + pr->pdc = obj_list; + + return; +} + +/* Initialize _PDC data based on the CPU vendor */ +void arch_acpi_processor_init_pdc(struct acpi_processor *pr) +{ + pr->pdc = NULL; + init_intel_pdc(pr); + return; +} + +EXPORT_SYMBOL(arch_acpi_processor_init_pdc); diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile index 642648361ed3..4838f2a57c7a 100644 --- a/arch/ia64/kernel/cpufreq/Makefile +++ b/arch/ia64/kernel/cpufreq/Makefile @@ -1,6 +1,2 @@ obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o -ifneq ($(CONFIG_ACPI_PROCESSOR),) -obj-y += acpi-processor.o -endif - diff --git a/arch/ia64/kernel/cpufreq/acpi-processor.c b/arch/ia64/kernel/cpufreq/acpi-processor.c deleted file mode 100644 index e683630c8ce2..000000000000 --- a/arch/ia64/kernel/cpufreq/acpi-processor.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * arch/ia64/kernel/cpufreq/processor.c - * - * Copyright (C) 2005 Intel Corporation - * Venkatesh Pallipadi - * - Added _PDC for platforms with Intel CPUs - */ - -#include -#include -#include -#include - -#include -#include - -static void init_intel_pdc(struct acpi_processor *pr) -{ - struct acpi_object_list *obj_list; - union acpi_object *obj; - u32 *buf; - - /* allocate and initialize pdc. It will be used later. */ - obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); - if (!obj_list) { - printk(KERN_ERR "Memory allocation error\n"); - return; - } - - obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!obj) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj_list); - return; - } - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(obj); - kfree(obj_list); - return; - } - - buf[0] = ACPI_PDC_REVISION_ID; - buf[1] = 1; - buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; - - obj->type = ACPI_TYPE_BUFFER; - obj->buffer.length = 12; - obj->buffer.pointer = (u8 *) buf; - obj_list->count = 1; - obj_list->pointer = obj; - pr->pdc = obj_list; - - return; -} - -/* Initialize _PDC data based on the CPU vendor */ -void arch_acpi_processor_init_pdc(struct acpi_processor *pr) -{ - pr->pdc = NULL; - init_intel_pdc(pr); - return; -} - -EXPORT_SYMBOL(arch_acpi_processor_init_pdc); -- cgit v1.2.3 From 0efc4883a6b3de12476cd7a35e638c0a9f5fd75f Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 9 Dec 2005 13:46:32 -0800 Subject: IB/umad: fix memory leaks Don't leak packet if it had a timeout, and don't leak timeout struct if queue_packet() fails. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index eb7f52537ccc..c908de8db5a9 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -197,8 +197,8 @@ static void send_handler(struct ib_mad_agent *agent, memcpy(timeout->mad.data, packet->mad.data, sizeof (struct ib_mad_hdr)); - if (!queue_packet(file, agent, timeout)) - return; + if (queue_packet(file, agent, timeout)) + kfree(timeout); } out: kfree(packet); -- cgit v1.2.3 From 52d0df153c987e4ad57d15f5df91848f65858e5d Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 9 Dec 2005 13:48:50 -0800 Subject: IB/mthca: fix memory user DB table leak Free the memory allocated in mthca_init_user_db_tab() when releasing the db_tab in mthca_cleanup_user_db_tab(). Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_memfree.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index d72fe95cba08..5798ed00d83d 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -485,6 +485,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, put_page(db_tab->page[i].mem.page); } } + + kfree(db_tab); } int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, -- cgit v1.2.3 From 94361cf74a6fca1973d2fed5338d5fb4bcd902fa Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 9 Dec 2005 16:32:21 -0800 Subject: IB/mthca: check RDMA limits Add limit checking on rd_atomic and dest_rd_atomic attributes: especially for max_dest_rd_atomic, a value that is larger than HCA capability can cause RDB overflow and corruption of another QP. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 7450550db736..c5c3d0edbbf5 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -591,6 +591,20 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) return -EINVAL; } + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { + mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n", + attr->max_rd_atomic, dev->limits.max_qp_init_rdma); + return -EINVAL; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) { + mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n", + attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift); + return -EINVAL; + } + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); if (IS_ERR(mailbox)) return PTR_ERR(mailbox); -- cgit v1.2.3 From 6aa2e4e8063114bd7cea8616dd5848d3c64b4c36 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 9 Dec 2005 16:38:04 -0800 Subject: IB/mthca: correct log2 calculation Fix thinko in rd_atomic calculation: ffs(x) - 1 does not find the next power of 2 -- it should be fls(x - 1). Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index c5c3d0edbbf5..84056a8b794e 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -728,9 +728,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { - qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ? - ffs(attr->max_rd_atomic) - 1 : 0, - 7) << 21); + if (attr->max_rd_atomic) + qp_context->params1 |= + cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX); } @@ -769,8 +769,6 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { - u8 rra_max; - if (qp->resp_depth && !attr->max_dest_rd_atomic) { /* * Lowering our responder resources to zero. @@ -798,13 +796,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) MTHCA_QP_OPTPAR_RAE); } - for (rra_max = 0; - 1 << rra_max < attr->max_dest_rd_atomic && - rra_max < dev->qp_table.rdb_shift; - ++rra_max) - ; /* nothing */ + if (attr->max_dest_rd_atomic) + qp_context->params2 |= + cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); - qp_context->params2 |= cpu_to_be32(rra_max << 21); qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX); qp->resp_depth = attr->max_dest_rd_atomic; -- cgit v1.2.3 From 44b5b0303327cfb23f135b95b2fe5436c81ed27c Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 9 Dec 2005 16:40:14 -0800 Subject: IB/mthca: don't change driver's copy of attributes if modify QP fails Only change the driver's copy of the QP attributes in modify QP after checking the modify QP command completed successfully. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 84056a8b794e..3543299ecb15 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -764,8 +764,6 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE | MTHCA_QP_OPTPAR_RRE | MTHCA_QP_OPTPAR_RAE); - - qp->atomic_rd_en = attr->qp_access_flags; } if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { @@ -801,8 +799,6 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX); - - qp->resp_depth = attr->max_dest_rd_atomic; } qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC); @@ -844,8 +840,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) err = -EINVAL; } - if (!err) + if (!err) { qp->state = new_state; + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->atomic_rd_en = attr->qp_access_flags; + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->resp_depth = attr->max_dest_rd_atomic; + } mthca_free_mailbox(dev, mailbox); -- cgit v1.2.3 From 3a51f7c40437077ac4a463307e9a4ae6b78755a8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 11 Dec 2005 12:40:37 -0500 Subject: Input: evdev - consolidate compat and regular code Compat and normal code mirror each other and are hard to maintain. When EV_SW was added compat_ioctl case was missed. Here is my attempt at consolidating the code. Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 493 ++++++++++++++++++++++---------------------------- 1 file changed, 213 insertions(+), 280 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 9f2352bd8348..0270d1ec9425 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -146,6 +146,7 @@ static int evdev_open(struct inode * inode, struct file * file) } #ifdef CONFIG_COMPAT + struct input_event_compat { struct compat_timeval time; __u16 type; @@ -165,98 +166,107 @@ struct input_event_compat { # define COMPAT_TEST test_thread_flag(TIF_32BIT) #endif -static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) +static inline size_t evdev_event_size(void) { - struct evdev_list *list = file->private_data; - struct input_event_compat event; - int retval = 0; + return COMPAT_TEST ? + sizeof(struct input_event_compat) : sizeof(struct input_event); +} - while (retval < count) { - if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat))) +static int evdev_event_from_user(const char __user *buffer, struct input_event *event) +{ + if (COMPAT_TEST) { + struct input_event_compat compat_event; + + if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat))) + return -EFAULT; + + event->time.tv_sec = compat_event.time.tv_sec; + event->time.tv_usec = compat_event.time.tv_usec; + event->type = compat_event.type; + event->code = compat_event.code; + event->value = compat_event.value; + + } else { + if (copy_from_user(event, buffer, sizeof(struct input_event))) return -EFAULT; - input_event(list->evdev->handle.dev, event.type, event.code, event.value); - retval += sizeof(struct input_event_compat); } - return retval; + return 0; } -#endif -static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) +static int evdev_event_to_user(char __user *buffer, const struct input_event *event) { - struct evdev_list *list = file->private_data; - struct input_event event; - int retval = 0; - - if (!list->evdev->exist) return -ENODEV; + if (COMPAT_TEST) { + struct input_event_compat compat_event; -#ifdef CONFIG_COMPAT - if (COMPAT_TEST) - return evdev_write_compat(file, buffer, count, ppos); -#endif + compat_event.time.tv_sec = event->time.tv_sec; + compat_event.time.tv_usec = event->time.tv_usec; + compat_event.type = event->type; + compat_event.code = event->code; + compat_event.value = event->value; - while (retval < count) { + if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat))) + return -EFAULT; - if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) + } else { + if (copy_to_user(buffer, event, sizeof(struct input_event))) return -EFAULT; - input_event(list->evdev->handle.dev, event.type, event.code, event.value); - retval += sizeof(struct input_event); } - return retval; + return 0; } -#ifdef CONFIG_COMPAT -static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos) +#else + +static inline size_t evdev_event_size(void) { - struct evdev_list *list = file->private_data; - int retval; + return sizeof(struct input_event); +} - if (count < sizeof(struct input_event_compat)) - return -EINVAL; +static int evdev_event_from_user(const char __user *buffer, struct input_event *event) +{ + if (copy_from_user(event, buffer, sizeof(struct input_event))) + return -EFAULT; - if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; + return 0; +} - retval = wait_event_interruptible(list->evdev->wait, - list->head != list->tail || (!list->evdev->exist)); +static int evdev_event_to_user(char __user *buffer, const struct input_event *event) +{ + if (copy_to_user(buffer, event, sizeof(struct input_event))) + return -EFAULT; - if (retval) - return retval; + return 0; +} + +#endif /* CONFIG_COMPAT */ + +static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) +{ + struct evdev_list *list = file->private_data; + struct input_event event; + int retval = 0; if (!list->evdev->exist) return -ENODEV; - while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) { - struct input_event *event = (struct input_event *) list->buffer + list->tail; - struct input_event_compat event_compat; - event_compat.time.tv_sec = event->time.tv_sec; - event_compat.time.tv_usec = event->time.tv_usec; - event_compat.type = event->type; - event_compat.code = event->code; - event_compat.value = event->value; - - if (copy_to_user(buffer + retval, &event_compat, - sizeof(struct input_event_compat))) return -EFAULT; - list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); - retval += sizeof(struct input_event_compat); + while (retval < count) { + + if (evdev_event_from_user(buffer + retval, &event)) + return -EFAULT; + input_event(list->evdev->handle.dev, event.type, event.code, event.value); + retval += evdev_event_size(); } return retval; } -#endif static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) { struct evdev_list *list = file->private_data; int retval; -#ifdef CONFIG_COMPAT - if (COMPAT_TEST) - return evdev_read_compat(file, buffer, count, ppos); -#endif - - if (count < sizeof(struct input_event)) + if (count < evdev_event_size()) return -EINVAL; if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) @@ -271,11 +281,15 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count if (!list->evdev->exist) return -ENODEV; - while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { - if (copy_to_user(buffer + retval, list->buffer + list->tail, - sizeof(struct input_event))) return -EFAULT; + while (list->head != list->tail && retval + evdev_event_size() <= count) { + + struct input_event *event = (struct input_event *) list->buffer + list->tail; + + if (evdev_event_to_user(buffer + retval, event)) + return -EFAULT; + list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); - retval += sizeof(struct input_event); + retval += evdev_event_size(); } return retval; @@ -290,17 +304,95 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait) (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); } -static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +#ifdef CONFIG_COMPAT + +#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) +#define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) + +#ifdef __BIG_ENDIAN +static int bits_to_user(unsigned long *bits, unsigned int maxbit, + unsigned int maxlen, void __user *p, int compat) +{ + int len, i; + + if (compat) { + len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); + if (len < maxlen) + len = maxlen; + + for (i = 0; i < len / sizeof(compat_long_t); i++) + if (copy_to_user((compat_long_t __user *) p + i, + (compat_long_t *) bits + + i + 1 - ((i % 2) << 1), + sizeof(compat_long_t))) + return -EFAULT; + } else { + len = NBITS(maxbit) * sizeof(long); + if (len > maxlen) + len = maxlen; + + if (copy_to_user(p, bits, len)) + return -EFAULT; + } + + return len; +} +#else +static int bits_to_user(unsigned long *bits, unsigned int maxbit, + unsigned int maxlen, void __user *p, int compat) +{ + int len = compat ? + NBITS_COMPAT(maxbit) * sizeof(compat_long_t) : + NBITS(maxbit) * sizeof(long); + + if (len > maxlen) + len = maxlen; + + return copy_to_user(p, bits, len) ? -EFAULT : len; +} +#endif /* __BIG_ENDIAN */ + +#else + +static int bits_to_user(unsigned long *bits, unsigned int maxbit, + unsigned int maxlen, void __user *p, int compat) +{ + int len = NBITS(maxbit) * sizeof(long); + + if (len > maxlen) + len = maxlen; + + return copy_to_user(p, bits, len) ? -EFAULT : len; +} + +#endif /* CONFIG_COMPAT */ + +static int str_to_user(const char *str, unsigned int maxlen, void __user *p) +{ + int len; + + if (!str) + return -ENOENT; + + len = strlen(str) + 1; + if (len > maxlen) + len = maxlen; + + return copy_to_user(p, str, len) ? -EFAULT : len; +} + +static long evdev_ioctl_handler(struct file *file, unsigned int cmd, + void __user *p, int compat_mode) { struct evdev_list *list = file->private_data; struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; struct input_absinfo abs; - void __user *p = (void __user *)arg; - int __user *ip = (int __user *)arg; + int __user *ip = (int __user *)p; int i, t, u, v; - if (!evdev->exist) return -ENODEV; + if (!evdev->exist) + return -ENODEV; switch (cmd) { @@ -308,26 +400,39 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return put_user(EV_VERSION, ip); case EVIOCGID: - return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0; + if (copy_to_user(p, &dev->id, sizeof(struct input_id))) + return -EFAULT; + + return 0; case EVIOCGKEYCODE: - if (get_user(t, ip)) return -EFAULT; - if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; - if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT; + if (get_user(t, ip)) + return -EFAULT; + if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) + return -EINVAL; + if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) + return -EFAULT; return 0; case EVIOCSKEYCODE: - if (get_user(t, ip)) return -EFAULT; - if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; - if (get_user(v, ip + 1)) return -EFAULT; - if (v < 0 || v > KEY_MAX) return -EINVAL; - if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) return -EINVAL; + if (get_user(t, ip)) + return -EFAULT; + if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) + return -EINVAL; + if (get_user(v, ip + 1)) + return -EFAULT; + if (v < 0 || v > KEY_MAX) + return -EINVAL; + if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) + return -EINVAL; + u = SET_INPUT_KEYCODE(dev, t, v); clear_bit(u, dev->keybit); set_bit(v, dev->keybit); for (i = 0; i < dev->keycodemax; i++) - if (INPUT_KEYCODE(dev,i) == u) + if (INPUT_KEYCODE(dev, i) == u) set_bit(u, dev->keybit); + return 0; case EVIOCSFF: @@ -338,17 +443,17 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (copy_from_user(&effect, p, sizeof(effect))) return -EFAULT; err = dev->upload_effect(dev, &effect); - if (put_user(effect.id, &(((struct ff_effect __user *)arg)->id))) + if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) return -EFAULT; return err; - } - else return -ENOSYS; + } else + return -ENOSYS; case EVIOCRMFF: - if (dev->erase_effect) { - return dev->erase_effect(dev, (int)arg); - } - else return -ENOSYS; + if (!dev->erase_effect) + return -ENOSYS; + + return dev->erase_effect(dev, (int)(unsigned long) p); case EVIOCGEFFECTS: if (put_user(dev->ff_effects_max, ip)) @@ -356,7 +461,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; case EVIOCGRAB: - if (arg) { + if (p) { if (evdev->grab) return -EBUSY; if (input_grab_device(&evdev->handle)) @@ -395,62 +500,33 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case EV_SW: bits = dev->swbit; len = SW_MAX; break; default: return -EINVAL; } - len = NBITS(len) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, bits, len) ? -EFAULT : len; + return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); } - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { - int len; - len = NBITS(KEY_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->key, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) + return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { - int len; - len = NBITS(LED_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->led, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) + return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { - int len; - len = NBITS(SND_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->snd, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) + return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) { - int len; - len = NBITS(SW_MAX) * sizeof(long); - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->sw, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) + return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { - int len; - if (!dev->name) return -ENOENT; - len = strlen(dev->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->name, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) + return str_to_user(dev->name, _IOC_SIZE(cmd), p); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { - int len; - if (!dev->phys) return -ENOENT; - len = strlen(dev->phys) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->phys, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) + return str_to_user(dev->phys, _IOC_SIZE(cmd), p); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { - int len; - if (!dev->uniq) return -ENOENT; - len = strlen(dev->uniq) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; - } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) + return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { @@ -492,158 +568,15 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EINVAL; } -#ifdef CONFIG_COMPAT - -#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) -#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1) -#define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT) -#define BIT_COMPAT(x) (1UL<> OFF_COMPAT(bit)) & 1) - -#ifdef __BIG_ENDIAN -#define bit_to_user(bit, max) \ -do { \ - int i; \ - int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ - for (i = 0; i < len / sizeof(compat_long_t); i++) \ - if (copy_to_user((compat_long_t __user *) p + i, \ - (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \ - sizeof(compat_long_t))) \ - return -EFAULT; \ - return len; \ -} while (0) -#else -#define bit_to_user(bit, max) \ -do { \ - int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ - return copy_to_user(p, (bit), len) ? -EFAULT : len; \ -} while (0) -#endif +static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); +} +#ifdef CONFIG_COMPAT static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { - struct evdev_list *list = file->private_data; - struct evdev *evdev = list->evdev; - struct input_dev *dev = evdev->handle.dev; - struct input_absinfo abs; - void __user *p = compat_ptr(arg); - - if (!evdev->exist) return -ENODEV; - - switch (cmd) { - - case EVIOCGVERSION: - case EVIOCGID: - case EVIOCGKEYCODE: - case EVIOCSKEYCODE: - case EVIOCSFF: - case EVIOCRMFF: - case EVIOCGEFFECTS: - case EVIOCGRAB: - return evdev_ioctl(file, cmd, (unsigned long) p); - - default: - - if (_IOC_TYPE(cmd) != 'E') - return -EINVAL; - - if (_IOC_DIR(cmd) == _IOC_READ) { - - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { - long *bits; - int max; - - switch (_IOC_NR(cmd) & EV_MAX) { - case 0: bits = dev->evbit; max = EV_MAX; break; - case EV_KEY: bits = dev->keybit; max = KEY_MAX; break; - case EV_REL: bits = dev->relbit; max = REL_MAX; break; - case EV_ABS: bits = dev->absbit; max = ABS_MAX; break; - case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break; - case EV_LED: bits = dev->ledbit; max = LED_MAX; break; - case EV_SND: bits = dev->sndbit; max = SND_MAX; break; - case EV_FF: bits = dev->ffbit; max = FF_MAX; break; - case EV_SW: bits = dev->swbit; max = SW_MAX; break; - default: return -EINVAL; - } - bit_to_user(bits, max); - } - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) - bit_to_user(dev->key, KEY_MAX); - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) - bit_to_user(dev->led, LED_MAX); - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) - bit_to_user(dev->snd, SND_MAX); - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) - bit_to_user(dev->sw, SW_MAX); - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { - int len; - if (!dev->name) return -ENOENT; - len = strlen(dev->name) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->name, len) ? -EFAULT : len; - } - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { - int len; - if (!dev->phys) return -ENOENT; - len = strlen(dev->phys) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->phys, len) ? -EFAULT : len; - } - - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { - int len; - if (!dev->uniq) return -ENOENT; - len = strlen(dev->uniq) + 1; - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; - } - - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { - - int t = _IOC_NR(cmd) & ABS_MAX; - - abs.value = dev->abs[t]; - abs.minimum = dev->absmin[t]; - abs.maximum = dev->absmax[t]; - abs.fuzz = dev->absfuzz[t]; - abs.flat = dev->absflat[t]; - - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) - return -EFAULT; - - return 0; - } - } - - if (_IOC_DIR(cmd) == _IOC_WRITE) { - - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { - - int t = _IOC_NR(cmd) & ABS_MAX; - - if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) - return -EFAULT; - - dev->abs[t] = abs.value; - dev->absmin[t] = abs.minimum; - dev->absmax[t] = abs.maximum; - dev->absfuzz[t] = abs.fuzz; - dev->absflat[t] = abs.flat; - - return 0; - } - } - } - return -EINVAL; + return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); } #endif -- cgit v1.2.3 From 84c12b2410ea3b88523270064222fbf505dbf15e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 11 Dec 2005 12:41:03 -0500 Subject: Input: mousedev - make module parameters visible in sysfs Signed-off-by: Dmitry Torokhov --- drivers/input/mousedev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 2d0af44ac4b9..81fd7a97a93d 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -40,15 +40,15 @@ MODULE_LICENSE("GPL"); #endif static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; -module_param(xres, uint, 0); +module_param(xres, uint, 0644); MODULE_PARM_DESC(xres, "Horizontal screen resolution"); static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; -module_param(yres, uint, 0); +module_param(yres, uint, 0644); MODULE_PARM_DESC(yres, "Vertical screen resolution"); static unsigned tap_time = 200; -module_param(tap_time, uint, 0); +module_param(tap_time, uint, 0644); MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); struct mousedev_hw_data { @@ -155,7 +155,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, switch (code) { case ABS_X: size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) size = xres; + if (size == 0) size = xres ? : 1; if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; @@ -164,7 +164,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, case ABS_Y: size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; - if (size == 0) size = yres; + if (size == 0) size = yres ? : 1; if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; -- cgit v1.2.3 From 58057b9e57849ae28fbcb013edfe6b5a63edc799 Mon Sep 17 00:00:00 2001 From: Jasper Spaans Date: Sun, 11 Dec 2005 12:41:22 -0500 Subject: Input: logips2pp - add new signature (85) Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/logips2pp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 31a59f7abfaf..9a0bbe88c0e2 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -226,6 +226,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 96, 0, 0 }, -- cgit v1.2.3 From 74a89c966ebc4ec4b80fa93eee0b37ff7de7f4e6 Mon Sep 17 00:00:00 2001 From: Ashutosh Naik Date: Sun, 11 Dec 2005 12:41:32 -0500 Subject: Input: wistron - add Acer TravelMate 240 to DMI table Signed-off-by: Ashutosh Naik Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 49d0416a2a9a..ef7ee924ecc6 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -296,6 +296,16 @@ static struct key_entry keymap_acer_aspire_1500[] = { { KE_END, 0 } }; +static struct key_entry keymap_acer_travelmate_240[] = { + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_BLUETOOTH, 0x44, 0 }, + { KE_WIFI, 0x30, 0 }, + { KE_END, 0 } +}; + /* * If your machine is not here (which is currently rather likely), please send * a list of buttons and their key codes (reported when loading this module @@ -320,6 +330,15 @@ static struct dmi_system_id dmi_ids[] = { }, .driver_data = keymap_acer_aspire_1500 }, + { + .callback = dmi_matched, + .ident = "Acer TravelMate 240", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), + }, + .driver_data = keymap_acer_travelmate_240 + }, { 0, } }; -- cgit v1.2.3 From 56f0356321a876a1a356712f2486d6188a3b4992 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sun, 11 Dec 2005 22:33:26 -0500 Subject: Input: add the fn key to hid-debug.h Signed-off-by: Michael Hanselmann Acked-by: Johannes Berg Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index ceebab99eff2..4a42162ee2ea 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h @@ -681,6 +681,7 @@ static char *keys[KEY_MAX + 1] = { [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", [KEY_DOCUMENTS] = "Documents", + [KEY_FN] = "Fn", }; static char *relatives[REL_MAX + 1] = { -- cgit v1.2.3 From ec637e3ffb6b978143652477c7c5f96c9519b691 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 12 Dec 2005 20:53:18 -0800 Subject: [CIFS] Avoid extra large buffer allocation (and memcpy) in cifs_readpages Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 39 +++++++++++----------- fs/cifs/cifsfs.c | 5 +-- fs/cifs/cifsglob.h | 8 ++++- fs/cifs/cifspdu.h | 6 +++- fs/cifs/cifsproto.h | 14 ++++---- fs/cifs/cifssmb.c | 93 ++++++++++++++++++++++++++++++++-------------------- fs/cifs/connect.c | 2 +- fs/cifs/file.c | 52 ++++++++++++++++++----------- fs/cifs/inode.c | 5 +-- fs/cifs/misc.c | 2 +- fs/cifs/transport.c | 38 ++++++++++----------- 11 files changed, 156 insertions(+), 108 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 6f5d81f5eacb..f4124a32bef8 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -401,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; static write_proc_t packet_signing_enabled_write; -static read_proc_t quotaEnabled_read; -static write_proc_t quotaEnabled_write; +static read_proc_t experimEnabled_read; +static write_proc_t experimEnabled_write; static read_proc_t linuxExtensionsEnabled_read; static write_proc_t linuxExtensionsEnabled_write; @@ -442,9 +442,9 @@ cifs_proc_init(void) pde->write_proc = oplockEnabled_write; pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, - quotaEnabled_read, NULL); + experimEnabled_read, NULL); if (pde) - pde->write_proc = quotaEnabled_write; + pde->write_proc = experimEnabled_write; pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, linuxExtensionsEnabled_read, NULL); @@ -586,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer, } static int -quotaEnabled_read(char *page, char **start, off_t off, +experimEnabled_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; len = sprintf(page, "%d\n", experimEnabled); -/* could also check if quotas are enabled in kernel - as a whole first */ + len -= off; *start = page + off; @@ -608,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off, return len; } static int -quotaEnabled_write(struct file *file, const char __user *buffer, +experimEnabled_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { - char c; - int rc; + char c; + int rc; - rc = get_user(c, buffer); - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - experimEnabled = 0; - else if (c == '1' || c == 'y' || c == 'Y') - experimEnabled = 1; + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + experimEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + experimEnabled = 1; + else if (c == '2') + experimEnabled = 2; - return count; + return count; } static int @@ -632,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off, int len; len = sprintf(page, "%d\n", linuxExtEnabled); -/* could also check if quotas are enabled in kernel - as a whole first */ len -= off; *start = page + off; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ba90903909a6..582d66ca6da5 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -733,7 +733,7 @@ cifs_init_request_bufs(void) kmem_cache_destroy(cifs_req_cachep); return -ENOMEM; } - /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and + /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and almost all handle based requests (but not write response, nor is it sufficient for path based requests). A smaller size would have been more efficient (compacting multiple slab items on one 4k page) @@ -742,7 +742,8 @@ cifs_init_request_bufs(void) efficient to alloc 1 per page off the slab compared to 17K (5page) alloc of large cifs buffers even when page debugging is on */ cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", - MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); if (cifs_sm_req_cachep == NULL) { mempool_destroy(cifs_req_poolp); kmem_cache_destroy(cifs_req_cachep); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c011c278af4c..862e403ff211 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -285,6 +285,7 @@ struct cifs_search_info { unsigned endOfSearch:1; unsigned emptyDir:1; unsigned unicode:1; + unsigned smallBuf:1; /* so we know which buf_release function to call */ }; struct cifsFileInfo { @@ -420,7 +421,12 @@ struct dir_notify_req { #define MID_RESPONSE_RECEIVED 4 #define MID_RETRY_NEEDED 8 /* session closed while this request out */ #define MID_NO_RESP_NEEDED 0x10 -#define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ + +/* Types of response buffer returned from SendReceive2 */ +#define CIFS_NO_BUFFER 0 /* Response buffer not returned */ +#define CIFS_SMALL_BUFFER 1 +#define CIFS_LARGE_BUFFER 2 +#define CIFS_IOVEC 4 /* array of response buffers */ /* ***************************************************************** diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 5253e779b3aa..3c09fb9cc569 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -80,7 +80,11 @@ #define NT_TRANSACT_GET_USER_QUOTA 0x07 #define NT_TRANSACT_SET_USER_QUOTA 0x08 -#define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ +#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ +/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */ +/* among the requests (NTCreateX response is bigger with wct of 34) */ +#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */ +#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */ /* internal cifs vfs structures */ /***************************************************************** diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c058f8a45b2b..8ef0ce47f5b6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -49,7 +49,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, int * /* bytes returned */ , const int long_op); extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, struct kvec *, int /* nvec to send */, - int * /* bytes returned */ , const int long_op); + int * /* type of buf returned */ , const int long_op); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); @@ -93,11 +93,12 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const struct nls_table *); extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, - const char *searchName, const struct nls_table *nls_codepage, - __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); + const char *searchName, const struct nls_table *nls_codepage, + __u16 *searchHandle, struct cifs_search_info * psrch_inf, + int map, const char dirsep); extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, - __u16 searchHandle, struct cifs_search_info * psrch_inf); + __u16 searchHandle, struct cifs_search_info * psrch_inf); extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, const __u16 search_handle); @@ -230,8 +231,9 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, const int smb_file_id); extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, - const int netfid, unsigned int count, - const __u64 lseek, unsigned int *nbytes, char **buf); + const int netfid, unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf, + int * return_buf_type); extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 lseek, unsigned int *nbytes, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 3565d3bf2e32..1620991cd4d2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -958,21 +958,19 @@ openRetry: return rc; } -/* If no buffer passed in, then caller wants to do the copy - as in the case of readpages so the SMB buffer must be - freed by the caller */ - int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, - const int netfid, const unsigned int count, - const __u64 lseek, unsigned int *nbytes, char **buf) + const int netfid, const unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf, + int * pbuf_type) { int rc = -EACCES; READ_REQ *pSMB = NULL; READ_RSP *pSMBr = NULL; char *pReadData = NULL; - int bytes_returned; int wct; + int resp_buf_type = 0; + struct kvec iov[1]; cFYI(1,("Reading %d bytes on fid %d",count,netfid)); if(tcon->ses->capabilities & CAP_LARGE_FILES) @@ -981,8 +979,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, wct = 10; /* old style read */ *nbytes = 0; - rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); if (rc) return rc; @@ -990,13 +987,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, if (tcon->ses->server == NULL) return -ECONNABORTED; - pSMB->AndXCommand = 0xFF; /* none */ + pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = netfid; pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); if(wct == 12) pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); - else if((lseek >> 32) > 0) /* can not handle this big offset for old */ - return -EIO; + else if((lseek >> 32) > 0) /* can not handle this big offset for old */ + return -EIO; pSMB->Remaining = 0; pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); @@ -1005,14 +1002,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ else { /* old style read */ - struct smb_com_readx_req * pSMBW = + struct smb_com_readx_req * pSMBW = (struct smb_com_readx_req *)pSMB; - pSMBW->ByteCount = 0; + pSMBW->ByteCount = 0; } - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + rc = SendReceive2(xid, tcon->ses, iov, + 1 /* num iovecs */, + &resp_buf_type, 0); cifs_stats_inc(&tcon->num_reads); + pSMBr = (READ_RSP *)iov[0].iov_base; if (rc) { cERROR(1, ("Send error in read = %d", rc)); } else { @@ -1022,33 +1023,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, *nbytes = data_length; /*check that DataLength would not go beyond end of SMB */ - if ((data_length > CIFSMaxBufSize) + if ((data_length > CIFSMaxBufSize) || (data_length > count)) { cFYI(1,("bad length %d for count %d",data_length,count)); rc = -EIO; *nbytes = 0; } else { - pReadData = - (char *) (&pSMBr->hdr.Protocol) + + pReadData = (char *) (&pSMBr->hdr.Protocol) + le16_to_cpu(pSMBr->DataOffset); -/* if(rc = copy_to_user(buf, pReadData, data_length)) { - cERROR(1,("Faulting on read rc = %d",rc)); - rc = -EFAULT; - }*/ /* can not use copy_to_user when using page cache*/ +/* if(rc = copy_to_user(buf, pReadData, data_length)) { + cERROR(1,("Faulting on read rc = %d",rc)); + rc = -EFAULT; + }*/ /* can not use copy_to_user when using page cache*/ if(*buf) - memcpy(*buf,pReadData,data_length); + memcpy(*buf,pReadData,data_length); } } - if(*buf) - cifs_buf_release(pSMB); - else - *buf = (char *)pSMB; - /* Note: On -EAGAIN error only caller can retry on handle based calls + cifs_small_buf_release(pSMB); + if(*buf) { + if(resp_buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(iov[0].iov_base); + else if(resp_buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); + } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ { + *buf = iov[0].iov_base; + if(resp_buf_type == CIFS_SMALL_BUFFER) + *pbuf_type = CIFS_SMALL_BUFFER; + else if(resp_buf_type == CIFS_LARGE_BUFFER) + *pbuf_type = CIFS_LARGE_BUFFER; + } + + /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ return rc; } + int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, @@ -1163,10 +1174,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, { int rc = -EACCES; WRITE_REQ *pSMB = NULL; - int bytes_returned, wct; + int wct; int smb_hdr_len; + int resp_buf_type = 0; - /* BB removeme BB */ cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); if(tcon->ses->capabilities & CAP_LARGE_FILES) @@ -1209,22 +1220,34 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, pSMBW->ByteCount = cpu_to_le16(count + 5); } iov[0].iov_base = pSMB; - iov[0].iov_len = smb_hdr_len + 4; + if(wct == 14) + iov[0].iov_len = smb_hdr_len + 4; + else /* wct == 12 pad bigger by four bytes */ + iov[0].iov_len = smb_hdr_len + 8; + - rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, + rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, long_op); cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error Write2 = %d", rc)); *nbytes = 0; + } else if(resp_buf_type == 0) { + /* presumably this can not happen, but best to be safe */ + rc = -EIO; + *nbytes = 0; } else { - WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; + WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base; *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; *nbytes += le16_to_cpu(pSMBr->Count); } cifs_small_buf_release(pSMB); + if(resp_buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(iov[0].iov_base); + else if(resp_buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 651f3b6cebed..45c9d726c002 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -514,7 +514,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* else length ok */ reconnect = 0; - if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { isLargeBuf = TRUE; memcpy(bigbuf, smallbuf, 4); smb_buffer = bigbuf; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b67be3d8c019..c249b628fd1c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -555,13 +555,13 @@ int cifs_closedir(struct inode *inode, struct file *file) } ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; if (ptmp) { - /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); + cFYI(1, ("closedir free smb buf in srch struct")); pCFileStruct->srch_inf.ntwrk_buf_start = NULL; cifs_buf_release(ptmp); } ptmp = pCFileStruct->search_resume_name; if (ptmp) { - /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); + cFYI(1, ("closedir free resume name")); pCFileStruct->search_resume_name = NULL; kfree(ptmp); } @@ -871,8 +871,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, break; } /* BB FIXME We can not sign across two buffers yet */ - if((experimEnabled) && ((pTcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { + if((pTcon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { struct kvec iov[2]; unsigned int len; @@ -1424,6 +1424,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, rc = -EAGAIN; smb_read_data = NULL; while (rc == -EAGAIN) { + int buf_type = CIFS_NO_BUFFER; if ((open_file->invalidHandle) && (!open_file->closePend)) { rc = cifs_reopen_file(file->f_dentry->d_inode, @@ -1432,20 +1433,22 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, break; } rc = CIFSSMBRead(xid, pTcon, - open_file->netfid, - current_read_size, *poffset, - &bytes_read, &smb_read_data); + open_file->netfid, + current_read_size, *poffset, + &bytes_read, &smb_read_data, + &buf_type); pSMBr = (struct smb_com_read_rsp *)smb_read_data; if (copy_to_user(current_offset, smb_read_data + 4 /* RFC1001 hdr */ + le16_to_cpu(pSMBr->DataOffset), bytes_read)) { rc = -EFAULT; - FreeXid(xid); - return rc; - } + } if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } } @@ -1478,6 +1481,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, int xid; char *current_offset; struct cifsFileInfo *open_file; + int buf_type = CIFS_NO_BUFFER; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -1514,9 +1518,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, break; } rc = CIFSSMBRead(xid, pTcon, - open_file->netfid, - current_read_size, *poffset, - &bytes_read, ¤t_offset); + open_file->netfid, + current_read_size, *poffset, + &bytes_read, ¤t_offset, + &buf_type); } if (rc || (bytes_read == 0)) { if (total_read) { @@ -1614,6 +1619,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, struct smb_com_read_rsp *pSMBr; struct pagevec lru_pvec; struct cifsFileInfo *open_file; + int buf_type = CIFS_NO_BUFFER; xid = GetXid(); if (file->private_data == NULL) { @@ -1670,14 +1676,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, } rc = CIFSSMBRead(xid, pTcon, - open_file->netfid, - read_size, offset, - &bytes_read, &smb_read_data); - + open_file->netfid, + read_size, offset, + &bytes_read, &smb_read_data, + &buf_type); /* BB more RC checks ? */ if (rc== -EAGAIN) { if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } } @@ -1734,7 +1743,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, break; } if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } bytes_read = 0; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d1e995757436..f65310cc60a1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -229,11 +229,12 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { + int buf_type = CIFS_NO_BUFFER; /* Read header */ rc = CIFSSMBRead(xid, pTcon, netfid, 24 /* length */, 0 /* offset */, - &bytes_read, &pbuf); + &bytes_read, &pbuf, &buf_type); if((rc == 0) && (bytes_read >= 8)) { if(memcmp("IntxBLK", pbuf, 8) == 0) { cFYI(1,("Block device")); @@ -267,7 +268,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, } else { inode->i_mode |= S_IFREG; /* then it is a file */ rc = -EOPNOTSUPP; /* or some unknown SFU type */ - } + } CIFSSMBClose(xid, pTcon, netfid); } return rc; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index ac5a72a299a3..812c6bb0fe38 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -299,7 +299,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , struct cifsSesInfo * ses; char *temp = (char *) buffer; - memset(temp,0,MAX_CIFS_HDR_SIZE); + memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */ buffer->smb_buf_length = (2 * word_count) + sizeof (struct smb_hdr) - diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0abfbf4e4a49..c96a148c39b2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -298,7 +298,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, - struct kvec *iov, int n_vec, int *pbytes_returned, + struct kvec *iov, int n_vec, int * pRespBufType /* ret */, const int long_op) { int rc = 0; @@ -306,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, unsigned long timeout; struct mid_q_entry *midQ; struct smb_hdr *in_buf = iov[0].iov_base; + + *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ if (ses == NULL) { cERROR(1,("Null smb session")); @@ -491,23 +493,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, if (midQ->resp_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { - in_buf->smb_buf_length = receive_len; - if(receive_len > 500) { - /* use multiple buffers on way out */ - } else { - memcpy((char *)in_buf + 4, - (char *)midQ->resp_buf + 4, - receive_len); - iov[0].iov_len = receive_len + 4; - iov[1].iov_len = 0; - } + iov[0].iov_base = (char *)midQ->resp_buf; + if(midQ->largeBuf) + *pRespBufType = CIFS_LARGE_BUFFER; + else + *pRespBufType = CIFS_SMALL_BUFFER; + iov[0].iov_len = receive_len + 4; + iov[1].iov_len = 0; - dump_smb(in_buf, 80); + dump_smb(midQ->resp_buf, 80); /* convert the length into a more usable form */ if((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(in_buf, + rc = cifs_verify_signature(midQ->resp_buf, ses->server->mac_signing_key, midQ->sequence_number+1); if(rc) { @@ -516,18 +515,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, } } - *pbytes_returned = in_buf->smb_buf_length; - /* BB special case reconnect tid and uid here? */ /* BB special case Errbadpassword and pwdexpired here */ - rc = map_smb_to_linux_error(in_buf); + rc = map_smb_to_linux_error(midQ->resp_buf); /* convert ByteCount if necessary */ if (receive_len >= sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + - (2 * in_buf->WordCount) + 2 /* bcc */ ) - BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf)); + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) + BCC(midQ->resp_buf) = + le16_to_cpu(BCC_LE(midQ->resp_buf)); + midQ->resp_buf = NULL; /* mark it so will not be freed + by DeleteMidQEntry */ } else { rc = -EIO; cFYI(1,("Bad MID state?")); @@ -793,7 +793,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { rc = -EIO; - cERROR(1,("Bad MID state? ")); + cERROR(1,("Bad MID state?")); } } cifs_no_response_exit: -- cgit v1.2.3 From 729b4d4ce1982c52040bbf22d6711cdf8db07ad8 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Thu, 1 Dec 2005 04:29:00 -0500 Subject: [ACPI] fix reboot upon suspend-to-disk http://bugzilla.kernel.org/show_bug.cgi?id=4320 Signed-off-by: Alexey Starikovskiy Acked-by: Pavel Machek Signed-off-by: Len Brown --- drivers/acpi/sleep/poweroff.c | 15 +++++++++------ drivers/acpi/sleep/sleep.h | 2 +- drivers/acpi/sleep/wakeup.c | 6 +++--- include/linux/kernel.h | 1 + include/linux/reboot.h | 3 +-- kernel/power/disk.c | 9 +-------- kernel/sys.c | 25 ++++++++++--------------- 7 files changed, 26 insertions(+), 35 deletions(-) diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index af7935a95bcc..47fb4b394eec 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -33,9 +33,7 @@ int acpi_sleep_prepare(u32 acpi_state) ACPI_FLUSH_CPU_CACHE(); acpi_enable_wakeup_device_prep(acpi_state); #endif - if (acpi_state == ACPI_STATE_S5) { - acpi_wakeup_gpe_poweroff_prepare(); - } + acpi_gpe_sleep_prepare(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -53,11 +51,16 @@ void acpi_power_off(void) static int acpi_shutdown(struct sys_device *x) { - if (system_state == SYSTEM_POWER_OFF) { - /* Prepare if we are going to power off the system */ + switch (system_state) { + case SYSTEM_POWER_OFF: + /* Prepare to power off the system */ return acpi_sleep_prepare(ACPI_STATE_S5); + case SYSTEM_SUSPEND_DISK: + /* Prepare to suspend the system to disk */ + return acpi_sleep_prepare(ACPI_STATE_S4); + default: + return 0; } - return 0; } static struct sysdev_class acpi_sysclass = { diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index efd0001c6f05..f3e70397a7d6 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h @@ -5,4 +5,4 @@ extern int acpi_suspend (u32 state); extern void acpi_enable_wakeup_device_prep(u8 sleep_state); extern void acpi_enable_wakeup_device(u8 sleep_state); extern void acpi_disable_wakeup_device(u8 sleep_state); -extern void acpi_wakeup_gpe_poweroff_prepare(void); +extern void acpi_gpe_sleep_prepare(u32 sleep_state); diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c index 4134ed43d026..85df0ceda2a9 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/sleep/wakeup.c @@ -192,7 +192,7 @@ late_initcall(acpi_wakeup_device_init); * RUNTIME GPEs, we simply mark all GPES that * are not enabled for wakeup from S5 as RUNTIME. */ -void acpi_wakeup_gpe_poweroff_prepare(void) +void acpi_gpe_sleep_prepare(u32 sleep_state) { struct list_head *node, *next; @@ -201,8 +201,8 @@ void acpi_wakeup_gpe_poweroff_prepare(void) struct acpi_device, wakeup_list); - /* The GPE can wakeup system from S5, don't touch it */ - if ((u32) dev->wakeup.sleep_state == ACPI_STATE_S5) + /* The GPE can wakeup system from this state, don't touch it */ + if ((u32) dev->wakeup.sleep_state >= sleep_state) continue; /* acpi_set_gpe_type will automatically disable GPE */ acpi_set_gpe_type(dev->wakeup.gpe_device, diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b1e407a4fbda..73aa55a73334 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -181,6 +181,7 @@ extern enum system_states { SYSTEM_HALT, SYSTEM_POWER_OFF, SYSTEM_RESTART, + SYSTEM_SUSPEND_DISK, } system_state; #define TAINT_PROPRIETARY_MODULE (1<<0) diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 7ab2cdb83ef0..015297ff73fa 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -60,8 +60,7 @@ extern void machine_crash_shutdown(struct pt_regs *); */ extern void kernel_restart_prepare(char *cmd); -extern void kernel_halt_prepare(void); -extern void kernel_power_off_prepare(void); +extern void kernel_shutdown_prepare(enum system_states state); extern void kernel_restart(char *cmd); extern void kernel_halt(void); diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 027322a564f4..f2cd279d07c7 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -52,7 +52,7 @@ static void power_down(suspend_disk_method_t mode) switch(mode) { case PM_DISK_PLATFORM: - kernel_power_off_prepare(); + kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); error = pm_ops->enter(PM_SUSPEND_DISK); break; case PM_DISK_SHUTDOWN: @@ -119,13 +119,6 @@ static int prepare_processes(void) goto thaw; } - if (pm_disk_mode == PM_DISK_PLATFORM) { - if (pm_ops && pm_ops->prepare) { - if ((error = pm_ops->prepare(PM_SUSPEND_DISK))) - goto thaw; - } - } - /* Free memory before shutting down devices. */ free_some_memory(); return 0; diff --git a/kernel/sys.c b/kernel/sys.c index eecf84526afe..c3b1874661fa 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -427,23 +427,25 @@ void kernel_kexec(void) } EXPORT_SYMBOL_GPL(kernel_kexec); +void kernel_shutdown_prepare(enum system_states state) +{ + notifier_call_chain(&reboot_notifier_list, + (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); + system_state = state; + device_shutdown(); +} /** * kernel_halt - halt the system * * Shutdown everything and perform a clean system halt. */ -void kernel_halt_prepare(void) -{ - notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); - system_state = SYSTEM_HALT; - device_shutdown(); -} void kernel_halt(void) { - kernel_halt_prepare(); + kernel_shutdown_prepare(SYSTEM_HALT); printk(KERN_EMERG "System halted.\n"); machine_halt(); } + EXPORT_SYMBOL_GPL(kernel_halt); /** @@ -451,20 +453,13 @@ EXPORT_SYMBOL_GPL(kernel_halt); * * Shutdown everything and perform a clean system power_off. */ -void kernel_power_off_prepare(void) -{ - notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); - system_state = SYSTEM_POWER_OFF; - device_shutdown(); -} void kernel_power_off(void) { - kernel_power_off_prepare(); + kernel_shutdown_prepare(SYSTEM_POWER_OFF); printk(KERN_EMERG "Power down.\n"); machine_power_off(); } EXPORT_SYMBOL_GPL(kernel_power_off); - /* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers -- cgit v1.2.3 From 6c7d2a75b512c64c910b69adf32dbaddb461910b Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 15 Dec 2005 13:55:50 -0800 Subject: IB/mthca: Fix thinko in mthca_table_find() break only escapes from the innermost loop, and we want to escape both loops and return an answer. Noticed by Ishai Rabinovitch. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_memfree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 5798ed00d83d..9fb985a016e9 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -233,7 +233,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj) for (i = 0; i < chunk->npages; ++i) { if (chunk->mem[i].length >= offset) { page = chunk->mem[i].page; - break; + goto out; } offset -= chunk->mem[i].length; } -- cgit v1.2.3 From 576d2e4e40315e8140c04be99cd057720d8a3817 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 15 Dec 2005 14:20:23 -0800 Subject: IB/mthca: Fix SRQ cleanup during QP destroy When cleaning up a CQ for a QP attached to SRQ, need to free an SRQ WQE only if the CQE is a receive completion. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cq.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 4a8adcef2079..fcef8dc2c121 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -253,6 +253,15 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn, wake_up(&cq->wait); } +static inline int is_recv_cqe(struct mthca_cqe *cqe) +{ + if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK) + return !(cqe->opcode & 0x01); + else + return !(cqe->is_send & 0x80); +} + void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, struct mthca_srq *srq) { @@ -296,7 +305,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, while ((int) --prod_index - (int) cq->cons_index >= 0) { cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); if (cqe->my_qpn == cpu_to_be32(qpn)) { - if (srq) + if (srq && is_recv_cqe(cqe)) mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe)); ++nfreed; } else if (nfreed) -- cgit v1.2.3 From d1646f86a2a05a956adbb163c81a81bd621f055e Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 15 Dec 2005 14:36:24 -0800 Subject: IB/mthca: Fix IB_QP_ACCESS_FLAGS handling. This patch corrects some corner cases in managing the RAE/RRE bits in the mthca qp context. These bits need to be zero if the user requests max_dest_rd_atomic of zero. The bits need to be restored to the value implied by the qp access flags attribute in a previous (or the current) modify-qp command if the dest_rd_atomic variable is changed to non-zero. In the current implementation, the following scenario will not work: RESET-to-INIT set QP access flags to all disabled (zeroes) INIT-to-RTR set max_dest_rd_atomic=10, AND set qp_access_flags = IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_ATOMIC The current code will incorrectly take the access-flags value set in the RESET-to-INIT transition. We can simplify, and correct, this IB_QP_ACCESS_FLAGS handling: it is always safe to set qp access flags in the firmware command if either of IB_QP_MAX_DEST_RD_ATOMIC or IB_QP_ACCESS_FLAGS is set, so let's just set it to the correct value, always. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 87 +++++++++++++++------------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 3543299ecb15..e826c9ff5d70 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -522,6 +522,36 @@ static void init_port(struct mthca_dev *dev, int port) mthca_warn(dev, "INIT_IB returned status %02x.\n", status); } +static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr, + int attr_mask) +{ + u8 dest_rd_atomic; + u32 access_flags; + u32 hw_access_flags = 0; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + dest_rd_atomic = attr->max_dest_rd_atomic; + else + dest_rd_atomic = qp->resp_depth; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + access_flags = attr->qp_access_flags; + else + access_flags = qp->atomic_rd_en; + + if (!dest_rd_atomic) + access_flags &= IB_ACCESS_REMOTE_WRITE; + + if (access_flags & IB_ACCESS_REMOTE_READ) + hw_access_flags |= MTHCA_QP_BIT_RRE; + if (access_flags & IB_ACCESS_REMOTE_ATOMIC) + hw_access_flags |= MTHCA_QP_BIT_RAE; + if (access_flags & IB_ACCESS_REMOTE_WRITE) + hw_access_flags |= MTHCA_QP_BIT_RWE; + + return cpu_to_be32(hw_access_flags); +} + int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) { struct mthca_dev *dev = to_mdev(ibqp->device); @@ -743,57 +773,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_context->snd_db_index = cpu_to_be32(qp->sq.db_index); } - if (attr_mask & IB_QP_ACCESS_FLAGS) { - qp_context->params2 |= - cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE ? - MTHCA_QP_BIT_RWE : 0); - - /* - * Only enable RDMA reads and atomics if we have - * responder resources set to a non-zero value. - */ - if (qp->resp_depth) { - qp_context->params2 |= - cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_READ ? - MTHCA_QP_BIT_RRE : 0); - qp_context->params2 |= - cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC ? - MTHCA_QP_BIT_RAE : 0); - } - - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE | - MTHCA_QP_OPTPAR_RRE | - MTHCA_QP_OPTPAR_RAE); - } - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { - if (qp->resp_depth && !attr->max_dest_rd_atomic) { - /* - * Lowering our responder resources to zero. - * Turn off reads RDMA and atomics as responder. - * (RRE/RAE in params2 already zero) - */ - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRE | - MTHCA_QP_OPTPAR_RAE); - } - - if (!qp->resp_depth && attr->max_dest_rd_atomic) { - /* - * Increasing our responder resources from - * zero. Turn on RDMA reads and atomics as - * appropriate. - */ - qp_context->params2 |= - cpu_to_be32(qp->atomic_rd_en & IB_ACCESS_REMOTE_READ ? - MTHCA_QP_BIT_RRE : 0); - qp_context->params2 |= - cpu_to_be32(qp->atomic_rd_en & IB_ACCESS_REMOTE_ATOMIC ? - MTHCA_QP_BIT_RAE : 0); - - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRE | - MTHCA_QP_OPTPAR_RAE); - } - if (attr->max_dest_rd_atomic) qp_context->params2 |= cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); @@ -801,6 +781,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX); } + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + qp_context->params2 |= get_hw_access_flags(qp, attr, attr_mask); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE | + MTHCA_QP_OPTPAR_RRE | + MTHCA_QP_OPTPAR_RAE); + } + qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC); if (ibqp->srq) -- cgit v1.2.3 From c4342d8a4d95e18b957b898dbf5bfce28fca2780 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 15 Dec 2005 19:59:01 -0800 Subject: IB/mthca: Fix corner cases in max_rd_atomic value handling in modify QP sae and sre bits should only be set when setting sra_max. Further, in the old code, if the caller specifies max_rd_atomic = 0, the sre and sae bits are still set, with the result that the QP ends up with max_rd_atomic = 1 in effect. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index e826c9ff5d70..d786ef443614 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -747,9 +747,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_context->wqe_lkey = cpu_to_be32(qp->mr.ibmr.lkey); qp_context->params1 = cpu_to_be32((MTHCA_ACK_REQ_FREQ << 28) | (MTHCA_FLIGHT_LIMIT << 24) | - MTHCA_QP_BIT_SRE | - MTHCA_QP_BIT_SWE | - MTHCA_QP_BIT_SAE); + MTHCA_QP_BIT_SWE); if (qp->sq_policy == IB_SIGNAL_ALL_WR) qp_context->params1 |= cpu_to_be32(MTHCA_QP_BIT_SSC); if (attr_mask & IB_QP_RETRY_CNT) { @@ -758,9 +756,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { - if (attr->max_rd_atomic) + if (attr->max_rd_atomic) { + qp_context->params1 |= + cpu_to_be32(MTHCA_QP_BIT_SRE | + MTHCA_QP_BIT_SAE); qp_context->params1 |= cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); + } qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX); } -- cgit v1.2.3 From e1e02c9f766e5cf20d951d35e6d2bc2683aa87ef Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Wed, 21 Dec 2005 00:50:23 -0500 Subject: Input: appletouch - add support for Geyser 2 This patch adds support for the Geyser 2 touchpads used on post Oct 2005 Apple PowerBooks to the appletouch driver. Signed-off-by: Michael Hanselmann Acked-by: Rene Nussbaumer Acked-by: Johannes Berg Acked-by: Stelian Pop Signed-off-by: Dmitry Torokhov --- Documentation/input/appletouch.txt | 5 +- drivers/usb/input/appletouch.c | 145 ++++++++++++++++++++++++++++--------- 2 files changed, 112 insertions(+), 38 deletions(-) diff --git a/Documentation/input/appletouch.txt b/Documentation/input/appletouch.txt index b48d11d0326d..4f7c633a76d2 100644 --- a/Documentation/input/appletouch.txt +++ b/Documentation/input/appletouch.txt @@ -3,7 +3,7 @@ Apple Touchpad Driver (appletouch) Copyright (C) 2005 Stelian Pop appletouch is a Linux kernel driver for the USB touchpad found on post -February 2005 Apple Alu Powerbooks. +February 2005 and October 2005 Apple Aluminium Powerbooks. This driver is derived from Johannes Berg's appletrackpad driver[1], but it has been improved in some areas: @@ -13,7 +13,8 @@ been improved in some areas: Credits go to Johannes Berg for reverse-engineering the touchpad protocol, Frank Arnold for further improvements, and Alex Harper for some additional -information about the inner workings of the touchpad sensors. +information about the inner workings of the touchpad sensors. Michael +Hanselmann added support for the October 2005 models. Usage: ------ diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index 15840db092a5..6cce8527ba06 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -6,6 +6,7 @@ * Copyright (C) 2005 Stelian Pop (stelian@popies.net) * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) + * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) * * Thanks to Alex Harper for his inputs. * @@ -38,6 +39,11 @@ /* Apple has powerbooks which have the keyboard with different Product IDs */ #define APPLE_VENDOR_ID 0x05AC +/* These names come from Info.plist in AppleUSBTrackpad.kext */ +#define GEYSER_ANSI_PRODUCT_ID 0x0214 +#define GEYSER_ISO_PRODUCT_ID 0x0215 +#define GEYSER_JIS_PRODUCT_ID 0x0216 + #define ATP_DEVICE(prod) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS | \ @@ -53,13 +59,17 @@ static struct usb_device_id atp_table [] = { { ATP_DEVICE(0x020F) }, { ATP_DEVICE(0x030A) }, { ATP_DEVICE(0x030B) }, - { } /* Terminating entry */ + + /* PowerBooks Oct 2005 */ + { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, + + /* Terminating entry */ + { } }; MODULE_DEVICE_TABLE (usb, atp_table); -/* size of a USB urb transfer */ -#define ATP_DATASIZE 81 - /* * number of sensors. Note that only 16 instead of 26 X (horizontal) * sensors exist on 12" and 15" PowerBooks. All models have 16 Y @@ -108,6 +118,8 @@ struct atp { signed char xy_old[ATP_XSENSORS + ATP_YSENSORS]; /* accumulated sensors */ int xy_acc[ATP_XSENSORS + ATP_YSENSORS]; + int overflowwarn; /* overflow warning printed? */ + int datalen; /* size of an USB urb transfer */ }; #define dbg_dump(msg, tab) \ @@ -124,7 +136,7 @@ struct atp { if (debug) printk(format, ##a); \ } while (0) -MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold"); +MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann"); MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); MODULE_LICENSE("GPL"); @@ -132,6 +144,16 @@ static int debug = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activate debugging output"); +/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ +static inline int atp_is_geyser_2(struct atp *dev) +{ + int16_t productId = le16_to_cpu(dev->udev->descriptor.idProduct); + + return (productId == GEYSER_ANSI_PRODUCT_ID) || + (productId == GEYSER_ISO_PRODUCT_ID) || + (productId == GEYSER_JIS_PRODUCT_ID); +} + static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, int *z, int *fingers) { @@ -168,13 +190,20 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers) static void atp_complete(struct urb* urb, struct pt_regs* regs) { int x, y, x_z, y_z, x_f, y_f; - int retval, i; + int retval, i, j; struct atp *dev = urb->context; switch (urb->status) { case 0: /* success */ break; + case -EOVERFLOW: + if(!dev->overflowwarn) { + printk("appletouch: OVERFLOW with data " + "length %d, actual length is %d\n", + dev->datalen, dev->urb->actual_length); + dev->overflowwarn = 1; + } case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: @@ -189,23 +218,45 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) } /* drop incomplete datasets */ - if (dev->urb->actual_length != ATP_DATASIZE) { + if (dev->urb->actual_length != dev->datalen) { dprintk("appletouch: incomplete data package.\n"); goto exit; } /* reorder the sensors values */ - for (i = 0; i < 8; i++) { - /* X values */ - dev->xy_cur[i ] = dev->data[5 * i + 2]; - dev->xy_cur[i + 8] = dev->data[5 * i + 4]; - dev->xy_cur[i + 16] = dev->data[5 * i + 42]; - if (i < 2) - dev->xy_cur[i + 24] = dev->data[5 * i + 44]; - - /* Y values */ - dev->xy_cur[i + 26] = dev->data[5 * i + 1]; - dev->xy_cur[i + 34] = dev->data[5 * i + 3]; + if (atp_is_geyser_2(dev)) { + memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); + + /* + * The values are laid out like this: + * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ... + * '-' is an unused value. + */ + + /* read X values */ + for (i = 0, j = 19; i < 20; i += 2, j += 3) { + dev->xy_cur[i] = dev->data[j]; + dev->xy_cur[i + 1] = dev->data[j + 1]; + } + + /* read Y values */ + for (i = 0, j = 1; i < 9; i += 2, j += 3) { + dev->xy_cur[ATP_XSENSORS + i] = dev->data[j]; + dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1]; + } + } else { + for (i = 0; i < 8; i++) { + /* X values */ + dev->xy_cur[i ] = dev->data[5 * i + 2]; + dev->xy_cur[i + 8] = dev->data[5 * i + 4]; + dev->xy_cur[i + 16] = dev->data[5 * i + 42]; + if (i < 2) + dev->xy_cur[i + 24] = dev->data[5 * i + 44]; + + /* Y values */ + dev->xy_cur[i + 26] = dev->data[5 * i + 1]; + dev->xy_cur[i + 34] = dev->data[5 * i + 3]; + } } dbg_dump("sample", dev->xy_cur); @@ -216,16 +267,24 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) dev->x_old = dev->y_old = -1; memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); - /* 17" Powerbooks have 10 extra X sensors */ - for (i = 16; i < ATP_XSENSORS; i++) - if (dev->xy_cur[i]) { - printk("appletouch: 17\" model detected.\n"); + /* 17" Powerbooks have extra X sensors */ + for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) { + if (!dev->xy_cur[i]) continue; + + printk("appletouch: 17\" model detected.\n"); + if(atp_is_geyser_2(dev)) + input_set_abs_params(dev->input, ABS_X, 0, + (20 - 1) * + ATP_XFACT - 1, + ATP_FUZZ, 0); + else input_set_abs_params(dev->input, ABS_X, 0, (ATP_XSENSORS - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); - break; - } + + break; + } goto exit; } @@ -282,7 +341,8 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); } - input_report_key(dev->input, BTN_LEFT, !!dev->data[80]); + input_report_key(dev->input, BTN_LEFT, + !!dev->data[dev->datalen - 1]); input_sync(dev->input); @@ -353,6 +413,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id dev->udev = udev; dev->input = input_dev; + dev->overflowwarn = 0; + dev->datalen = (atp_is_geyser_2(dev)?64:81); dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) { @@ -360,7 +422,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id goto err_free_devs; } - dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL, + dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->data) { retval = -ENOMEM; @@ -369,7 +431,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id usb_fill_int_urb(dev->urb, udev, usb_rcvintpipe(udev, int_in_endpointAddr), - dev->data, ATP_DATASIZE, atp_complete, dev, 1); + dev->data, dev->datalen, atp_complete, dev, 1); usb_make_path(udev, dev->phys, sizeof(dev->phys)); strlcat(dev->phys, "/input0", sizeof(dev->phys)); @@ -385,14 +447,25 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id set_bit(EV_ABS, input_dev->evbit); - /* - * 12" and 15" Powerbooks only have 16 x sensors, - * 17" models are detected later. - */ - input_set_abs_params(input_dev, ABS_X, 0, - (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); + if (atp_is_geyser_2(dev)) { + /* + * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected + * later. + */ + input_set_abs_params(input_dev, ABS_X, 0, + ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); + input_set_abs_params(input_dev, ABS_Y, 0, + ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); + } else { + /* + * 12" and 15" Powerbooks only have 16 x sensors, + * 17" models are detected later. + */ + input_set_abs_params(input_dev, ABS_X, 0, + (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0); + input_set_abs_params(input_dev, ABS_Y, 0, + (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0); + } input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0); set_bit(EV_KEY, input_dev->evbit); @@ -427,7 +500,7 @@ static void atp_disconnect(struct usb_interface *iface) usb_kill_urb(dev->urb); input_unregister_device(dev->input); usb_free_urb(dev->urb); - usb_buffer_free(dev->udev, ATP_DATASIZE, + usb_buffer_free(dev->udev, dev->datalen, dev->data, dev->urb->transfer_dma); kfree(dev); } -- cgit v1.2.3 From f5e9c9ca54e31c0f629bae487eadaa5b8515b86d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 21 Dec 2005 00:51:13 -0500 Subject: Input: ALPS - add signature for HP ze1115 Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 4f41ec3e4332..24474335dfd1 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -40,6 +40,7 @@ static struct alps_model_info alps_model_data[] = { { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, + { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */ { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ -- cgit v1.2.3 From ba44995a1e84b6cebf32e61d9492e8e133d192ce Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 00:51:31 -0500 Subject: Input: psmouse - don't leave mouse asleep It looks like quite a few mice out there treat PSMOUSE_RESET_DIS as a powerdown request and turn off the light rendering the mouse unusable. Vojtech recommended to switch from PSMOUSE_RESET_DIS to full reset, however we don't want to do that everywhere as full reset is pretty slow. Instead we only use it before probing for "generic" protocols, such as IntelliMouse and Explorer, to make sure that the mouse will be woken up if it went to sleep as a result of PSMOUSE_RESET_DIS issued earlier. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 6ee9999a2eaa..4d5ecc04c5b6 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -527,11 +527,15 @@ static int psmouse_extensions(struct psmouse *psmouse, if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0) return PSMOUSE_PS2PP; + if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0) + return PSMOUSE_TRACKPOINT; + /* * Reset to defaults in case the device got confused by extended - * protocol probes. + * protocol probes. Note that we do full reset becuase some mice + * put themselves to sleep when see PSMOUSE_RESET_DIS. */ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + psmouse_reset(psmouse); if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0) return PSMOUSE_IMEX; @@ -539,12 +543,6 @@ static int psmouse_extensions(struct psmouse *psmouse, if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0) return PSMOUSE_IMPS; -/* - * Try to initialize the IBM TrackPoint - */ - if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0) - return PSMOUSE_TRACKPOINT; - /* * Okay, all failed, we have a standard mouse here. The number of the buttons * is still a question, though. We assume 3. @@ -559,7 +557,6 @@ static int psmouse_extensions(struct psmouse *psmouse, * extensions. */ psmouse_reset(psmouse); - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); } return PSMOUSE_PS2; -- cgit v1.2.3 From 4eb38ac0629716871591b594fe0c611b19613983 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 00:51:51 -0500 Subject: Input: i8042 - disable MUX mode for Sharp MM20 Add yet another entry to the ever-growing list of boxes with non-working MUX implementation. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 273bb3b08cfa..057beca1986a 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -158,6 +158,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), }, }, + { + .ident = "Sharp Actius MM20", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), + DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), + }, + }, { } }; -- cgit v1.2.3 From 41293e5368d9ba9760935cf510d2631c257f2b74 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 00:52:00 -0500 Subject: Input: add help entry for FM801 gameport driver to Kconfig Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 7524bd7d8b8f..d279454a5c9e 100644 --- a/drivers/input/gameport/Kconfig +++ b/drivers/input/gameport/Kconfig @@ -52,5 +52,12 @@ config GAMEPORT_EMU10K1 config GAMEPORT_FM801 tristate "ForteMedia FM801 gameport support" depends on PCI + help + Say Y here if you have ForteMedia FM801 PCI audio controller + (Abit AU10, Genius Sound Maker, HP Workstation zx2000, + and others), and want to use its gameport. + + To compile this driver as a module, choose M here: the + module will be called fm801-gp. endif -- cgit v1.2.3 From 1f1a91e033f4ec60a70669e2e3e358d7e4f32495 Mon Sep 17 00:00:00 2001 From: Daniele Gozzi Date: Wed, 21 Dec 2005 00:52:10 -0500 Subject: Input: lifebook - add DMI signature of Fujitsu Lifebook B142 This DMI data was found in Fujitsu LifeBook B142 (Product S/N FPC01003B, italian keyboard); re: bugzilla #5335 Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/lifebook.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 55991424ac91..5ccc3ef3b89e 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -27,6 +27,13 @@ static struct dmi_system_id lifebook_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"), }, }, + { + .ident = "Lifebook B142", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), + }, + + }, { } }; -- cgit v1.2.3 From 59317747359dbc26af920813b3df358333a3840c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 00:52:22 -0500 Subject: Input: pcspkr - register with driver core as a platfrom device Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pcspkr.c | 86 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 68ac97f101b0..1ef477f4469c 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -23,8 +24,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); -static struct input_dev *pcspkr_dev; - +static struct platform_device *pcspkr_platform_device; static DEFINE_SPINLOCK(i8253_beep_lock); static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -64,8 +64,11 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c return 0; } -static int __init pcspkr_init(void) +static int __devinit pcspkr_probe(struct platform_device *dev) { + struct input_dev *pcspkr_dev; + int err; + pcspkr_dev = input_allocate_device(); if (!pcspkr_dev) return -ENOMEM; @@ -76,22 +79,93 @@ static int __init pcspkr_init(void) pcspkr_dev->id.vendor = 0x001f; pcspkr_dev->id.product = 0x0001; pcspkr_dev->id.version = 0x0100; + pcspkr_dev->cdev.dev = &dev->dev; pcspkr_dev->evbit[0] = BIT(EV_SND); pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); pcspkr_dev->event = pcspkr_event; - input_register_device(pcspkr_dev); + err = input_register_device(pcspkr_dev); + if (err) { + input_free_device(pcspkr_dev); + return err; + } + + platform_set_drvdata(dev, pcspkr_dev); return 0; } -static void __exit pcspkr_exit(void) +static int __devexit pcspkr_remove(struct platform_device *dev) +{ + struct input_dev *pcspkr_dev = platform_get_drvdata(dev); + + input_unregister_device(pcspkr_dev); + platform_set_drvdata(dev, NULL); + /* turn off the speaker */ + pcspkr_event(NULL, EV_SND, SND_BELL, 0); + + return 0; +} + +static int pcspkr_suspend(struct platform_device *dev, pm_message_t state) +{ + pcspkr_event(NULL, EV_SND, SND_BELL, 0); + + return 0; +} + +static void pcspkr_shutdown(struct platform_device *dev) { - input_unregister_device(pcspkr_dev); /* turn off the speaker */ pcspkr_event(NULL, EV_SND, SND_BELL, 0); } +static struct platform_driver pcspkr_platform_driver = { + .driver = { + .name = "pcspkr", + .owner = THIS_MODULE, + }, + .probe = pcspkr_probe, + .remove = __devexit_p(pcspkr_remove), + .suspend = pcspkr_suspend, + .shutdown = pcspkr_shutdown, +}; + + +static int __init pcspkr_init(void) +{ + int err; + + err = platform_driver_register(&pcspkr_platform_driver); + if (err) + return err; + + pcspkr_platform_device = platform_device_alloc("pcspkr", -1); + if (!pcspkr_platform_device) { + err = -ENOMEM; + goto err_unregister_driver; + } + + err = platform_device_add(pcspkr_platform_device); + if (err) + goto err_free_device; + + return 0; + + err_free_device: + platform_device_put(pcspkr_platform_device); + err_unregister_driver: + platform_driver_unregister(&pcspkr_platform_driver); + + return err; +} + +static void __exit pcspkr_exit(void) +{ + platform_device_unregister(pcspkr_platform_device); + platform_driver_unregister(&pcspkr_platform_driver); +} + module_init(pcspkr_init); module_exit(pcspkr_exit); -- cgit v1.2.3 From 1f75e6bdfa011c0c2afa65ed1585200a3bc92ddf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 00:52:29 -0500 Subject: Input: m68kspkr - register with driver core as a platfrom device Signed-off-by: Dmitry Torokhov --- drivers/input/misc/m68kspkr.c | 102 +++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 04489ad7702a..8d6c3837badb 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,7 @@ MODULE_AUTHOR("Richard Zidlicky "); MODULE_DESCRIPTION("m68k beeper driver"); MODULE_LICENSE("GPL"); -static struct input_dev *m68kspkr_dev; +static struct platform_device *m68kspkr_platform_device; static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -47,36 +48,103 @@ static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int return 0; } +static int __devinit m68kspkr_probe(struct platform_device *dev) +{ + struct input_dev *input_dev; + int err; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "m68k beeper"; + input_dev->phys = "m68k/generic"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x001f; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &dev->dev; + + input_dev->evbit[0] = BIT(EV_SND); + input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + input_dev->event = m68kspkr_event; + + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + + platform_set_drvdata(dev, input_dev); + + return 0; +} + +static int __devexit m68kspkr_remove(struct platform_device *dev) +{ + struct input_dev *input_dev = platform_get_drvdata(dev); + + input_unregister_device(input_dev); + platform_set_drvdata(dev, NULL); + /* turn off the speaker */ + m68kspkr_event(NULL, EV_SND, SND_BELL, 0); + + return 0; +} + +static void m68kspkr_shutdown(struct platform_device *dev) +{ + /* turn off the speaker */ + m68kspkr_event(NULL, EV_SND, SND_BELL, 0); +} + +static struct platform_driver m68kspkr_platform_driver = { + .driver = { + .name = "m68kspkr", + .owner = THIS_MODULE, + }, + .probe = m68kspkr_probe, + .remove = __devexit_p(m68kspkr_remove), + .shutdown = m68kspkr_shutdown, +}; + static int __init m68kspkr_init(void) { - if (!mach_beep) { + int err; + + if (!mach_beep) { printk(KERN_INFO "m68kspkr: no lowlevel beep support\n"); return -ENODEV; } - m68kspkr_dev = input_allocate_device(); - if (!m68kspkr_dev) - return -ENOMEM; - - m68kspkr_dev->name = "m68k beeper"; - m68kspkr_dev->phys = "m68k/generic"; - m68kspkr_dev->id.bustype = BUS_HOST; - m68kspkr_dev->id.vendor = 0x001f; - m68kspkr_dev->id.product = 0x0001; - m68kspkr_dev->id.version = 0x0100; + err = platform_driver_register(&m68kspkr_platform_driver); + if (err) + return err; - m68kspkr_dev->evbit[0] = BIT(EV_SND); - m68kspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - m68kspkr_dev->event = m68kspkr_event; + m68kspkr_platform_device = platform_device_alloc("m68kspkr", -1); + if (!m68kspkr_platform_device) { + err = -ENOMEM; + goto err_unregister_driver; + } - input_register_device(m68kspkr_dev); + err = platform_device_add(m68kspkr_platform_device); + if (err) + goto err_free_device; return 0; + + err_free_device: + platform_device_put(m68kspkr_platform_device); + err_unregister_driver: + platform_driver_unregister(&m68kspkr_platform_driver); + + return err; } static void __exit m68kspkr_exit(void) { - input_unregister_device(m68kspkr_dev); + platform_device_unregister(m68kspkr_platform_device); + platform_driver_unregister(&m68kspkr_platform_driver); } module_init(m68kspkr_init); -- cgit v1.2.3 From f5b64078d75528f36b78d30e945bb1b05cb05f26 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 00:52:35 -0500 Subject: Input: sparcspkr - register with driver core as a platfrom device Signed-off-by: Dmitry Torokhov --- drivers/input/misc/sparcspkr.c | 162 ++++++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 57 deletions(-) diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 29d97b12be7a..f0fd2c4740f1 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -20,22 +21,10 @@ MODULE_AUTHOR("David S. Miller "); MODULE_DESCRIPTION("Sparc Speaker beeper driver"); MODULE_LICENSE("GPL"); +const char *beep_name; static unsigned long beep_iobase; -static struct input_dev *sparcspkr_dev; - -DEFINE_SPINLOCK(beep_lock); - -static void __init init_sparcspkr_struct(void) -{ - sparcspkr_dev->evbit[0] = BIT(EV_SND); - sparcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - - sparcspkr_dev->phys = "sparc/input0"; - sparcspkr_dev->id.bustype = BUS_ISA; - sparcspkr_dev->id.vendor = 0x001f; - sparcspkr_dev->id.product = 0x0001; - sparcspkr_dev->id.version = 0x0100; -} +static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); +static DEFINE_SPINLOCK(beep_lock); static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -59,39 +48,16 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in /* EBUS speaker only has on/off state, the frequency does not * appear to be programmable. */ - if (count) { - if (beep_iobase & 0x2UL) - outb(1, beep_iobase); - else - outl(1, beep_iobase); - } else { - if (beep_iobase & 0x2UL) - outb(0, beep_iobase); - else - outl(0, beep_iobase); - } + if (beep_iobase & 0x2UL) + outb(!!count, beep_iobase); + else + outl(!!count, beep_iobase); spin_unlock_irqrestore(&beep_lock, flags); return 0; } -static int __init init_ebus_beep(struct linux_ebus_device *edev) -{ - beep_iobase = edev->resource[0].start; - - sparcspkr_dev = input_allocate_device(); - if (!sparcspkr_dev) - return -ENOMEM; - - sparcspkr_dev->name = "Sparc EBUS Speaker"; - sparcspkr_dev->event = ebus_spkr_event; - - input_register_device(sparcspkr_dev); - - return 0; -} - #ifdef CONFIG_SPARC64 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -129,30 +95,103 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int return 0; } +#endif -static int __init init_isa_beep(struct sparc_isa_device *isa_dev) +static int __devinit sparcspkr_probe(struct platform_device *dev) { - beep_iobase = isa_dev->resource.start; + struct input_dev *input_dev; + int error; - sparcspkr_dev = input_allocate_device(); - if (!sparcspkr_dev) + input_dev = input_allocate_device(); + if (!input_dev) return -ENOMEM; - init_sparcspkr_struct(); + input_dev->name = beep_name; + input_dev->phys = "sparc/input0"; + input_dev->id.bustype = BUS_ISA; + input_dev->id.vendor = 0x001f; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &dev->dev; - sparcspkr_dev->name = "Sparc ISA Speaker"; - sparcspkr_dev->event = isa_spkr_event; + input_dev->evbit[0] = BIT(EV_SND); + input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - input_register_device(sparcspkr_dev); + input_dev->event = beep_event; + + error = input_register_device(input_dev); + if (error) { + input_free_device(input_dev); + return error; + } + + platform_set_drvdata(dev, input_dev); return 0; } -#endif + +static int __devexit sparcspkr_remove(struct platform_device *dev) +{ + struct input_dev *input_dev = platform_get_drvdata(dev); + + input_unregister_device(input_dev); + platform_set_drvdata(dev, NULL); + /* turn off the speaker */ + beep_event(NULL, EV_SND, SND_BELL, 0); + + return 0; +} + +static void sparcspkr_shutdown(struct platform_device *dev) +{ + /* turn off the speaker */ + beep_event(NULL, EV_SND, SND_BELL, 0); +} + +static struct platform_driver sparcspkr_platform_driver = { + .driver = { + .name = "sparcspkr", + .owner = THIS_MODULE, + }, + .probe = sparcspkr_probe, + .remove = __devexit_p(sparcspkr_remove), + .shutdown = sparcspkr_shutdown, +}; + +static struct platform_device *sparcspkr_platform_device; + +static int __init sparcspkr_drv_init(void) +{ + int error; + + error = platform_driver_register(&sparcspkr_platform_driver); + if (error) + return error; + + sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1); + if (!sparcspkr_platform_device) { + error = -ENOMEM; + goto err_unregister_driver; + } + + error = platform_device_add(sparcspkr_platform_device); + if (error) + goto err_free_device; + + return 0; + + err_free_device: + platform_device_put(sparcspkr_platform_device); + err_unregister_driver: + platform_driver_unregister(&sparcspkr_platform_driver); + + return error; +} static int __init sparcspkr_init(void) { struct linux_ebus *ebus; - struct linux_ebus_device *edev = NULL; + struct linux_ebus_device *edev; #ifdef CONFIG_SPARC64 struct sparc_isa_bridge *isa_br; struct sparc_isa_device *isa_dev; @@ -160,8 +199,12 @@ static int __init sparcspkr_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "beep")) - return init_ebus_beep(edev); + if (!strcmp(edev->prom_name, "beep")) { + beep_name = "Sparc EBUS Speaker"; + beep_event = ebus_spkr_event; + beep_iobase = edev->resource[0].start; + return sparcspkr_drv_init(); + } } } #ifdef CONFIG_SPARC64 @@ -170,8 +213,12 @@ static int __init sparcspkr_init(void) /* A hack, the beep device's base lives in * the DMA isa node. */ - if (!strcmp(isa_dev->prom_name, "dma")) - return init_isa_beep(isa_dev); + if (!strcmp(isa_dev->prom_name, "dma")) { + beep_name = "Sparc ISA Speaker"; + beep_event = isa_spkr_event, + beep_iobase = isa_dev->resource.start; + return sparcspkr_drv_init(); + } } } #endif @@ -181,7 +228,8 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - input_unregister_device(sparcspkr_dev); + platform_device_unregister(sparcspkr_platform_device); + platform_driver_unregister(&sparcspkr_platform_driver); } module_init(sparcspkr_init); -- cgit v1.2.3 From 8ea3694fcb7e5471cf84313a10e012b48e33c892 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 21 Dec 2005 01:02:54 -0500 Subject: Input: logips2pp - add signature of MouseMan Wheel Mouse (87) Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/logips2pp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 9a0bbe88c0e2..025a71de5404 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -228,6 +228,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 87, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 96, 0, 0 }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, -- cgit v1.2.3 From 63c94b68ec30847a6e2b36651703f41066f91480 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 5 Dec 2005 20:51:00 -0500 Subject: [ACPI] build EC driver on IA64 Signed-off-by: Kenji Kaneshige Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fe1e8126fbae..0c6abf49528e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -270,7 +270,6 @@ config ACPI_DEBUG config ACPI_EC bool - depends on X86 default y help This driver is required on some systems for the proper operation of -- cgit v1.2.3 From 87fd6318a6c381ba1e10a4f56907d11ae4a987b9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Dec 2005 01:25:11 -0500 Subject: Input: i8042 - convert to the new platform device interface Do not use platform_device_register_simple() as it is going away, implement ->probe() and ->remove() functions so manual binding and unbinding will work with this driver. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 116 +++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index ac86c1d1d83e..a7d91d5356a5 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -572,7 +572,7 @@ static int i8042_enable_mux_ports(void) * LCS/Telegraphics. */ -static int __init i8042_check_mux(void) +static int __devinit i8042_check_mux(void) { unsigned char mux_version; @@ -600,7 +600,7 @@ static int __init i8042_check_mux(void) * the presence of an AUX interface. */ -static int __init i8042_check_aux(void) +static int __devinit i8042_check_aux(void) { unsigned char param; static int i8042_check_aux_cookie; @@ -678,7 +678,7 @@ static int __init i8042_check_aux(void) * registers it, and reports to the user. */ -static int __init i8042_port_register(struct i8042_port *port) +static int __devinit i8042_port_register(struct i8042_port *port) { i8042_ctr &= ~port->disable; @@ -956,7 +956,6 @@ static int i8042_resume(struct platform_device *dev) panic_blink = i8042_panic_blink; return 0; - } /* @@ -969,16 +968,7 @@ static void i8042_shutdown(struct platform_device *dev) i8042_controller_cleanup(); } -static struct platform_driver i8042_driver = { - .suspend = i8042_suspend, - .resume = i8042_resume, - .shutdown = i8042_shutdown, - .driver = { - .name = "i8042", - }, -}; - -static int __init i8042_create_kbd_port(void) +static int __devinit i8042_create_kbd_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; @@ -1003,7 +993,7 @@ static int __init i8042_create_kbd_port(void) return i8042_port_register(port); } -static int __init i8042_create_aux_port(void) +static int __devinit i8042_create_aux_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; @@ -1028,7 +1018,7 @@ static int __init i8042_create_aux_port(void) return i8042_port_register(port); } -static int __init i8042_create_mux_port(int index) +static int __devinit i8042_create_mux_port(int index) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; @@ -1057,37 +1047,16 @@ static int __init i8042_create_mux_port(int index) return i8042_port_register(port); } -static int __init i8042_init(void) +static int __devinit i8042_probe(struct platform_device *dev) { int i, have_ports = 0; int err; - dbg_init(); - init_timer(&i8042_timer); i8042_timer.function = i8042_timer_func; - err = i8042_platform_init(); - if (err) - return err; - - i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; - i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; - - if (i8042_controller_init()) { - err = -ENODEV; - goto err_platform_exit; - } - - err = platform_driver_register(&i8042_driver); - if (err) - goto err_controller_cleanup; - - i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); - if (IS_ERR(i8042_platform_device)) { - err = PTR_ERR(i8042_platform_device); - goto err_unregister_driver; - } + if (i8042_controller_init()) + return -ENODEV; if (!i8042_noaux && !i8042_check_aux()) { if (!i8042_nomux && !i8042_check_mux()) { @@ -1113,30 +1082,23 @@ static int __init i8042_init(void) if (!have_ports) { err = -ENODEV; - goto err_unregister_device; + goto err_controller_cleanup; } mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - return 0; err_unregister_ports: for (i = 0; i < I8042_NUM_PORTS; i++) if (i8042_ports[i].serio) serio_unregister_port(i8042_ports[i].serio); - err_unregister_device: - platform_device_unregister(i8042_platform_device); - err_unregister_driver: - platform_driver_unregister(&i8042_driver); err_controller_cleanup: i8042_controller_cleanup(); - err_platform_exit: - i8042_platform_exit(); return err; } -static void __exit i8042_exit(void) +static int __devexit i8042_remove(struct platform_device *dev) { int i; @@ -1148,6 +1110,62 @@ static void __exit i8042_exit(void) del_timer_sync(&i8042_timer); + return 0; +} + +static struct platform_driver i8042_driver = { + .driver = { + .name = "i8042", + .owner = THIS_MODULE, + }, + .probe = i8042_probe, + .remove = __devexit_p(i8042_remove), + .suspend = i8042_suspend, + .resume = i8042_resume, + .shutdown = i8042_shutdown, +}; + +static int __init i8042_init(void) +{ + int err; + + dbg_init(); + + err = i8042_platform_init(); + if (err) + return err; + + i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; + i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; + + err = platform_driver_register(&i8042_driver); + if (err) + goto err_platform_exit; + + i8042_platform_device = platform_device_alloc("i8042", -1); + if (!i8042_platform_device) { + err = -ENOMEM; + goto err_unregister_driver; + } + + err = platform_device_add(i8042_platform_device); + if (err) + goto err_free_device; + + return 0; + + err_free_device: + platform_device_put(i8042_platform_device); + err_unregister_driver: + platform_driver_unregister(&i8042_driver); + err_platform_exit: + i8042_platform_exit(); + + return err; +} + +static void __exit i8042_exit(void) +{ platform_device_unregister(i8042_platform_device); platform_driver_unregister(&i8042_driver); -- cgit v1.2.3 From 916d83cfe5da1cda454d8b0ae233f06b58bd7f91 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Dec 2005 01:25:30 -0500 Subject: Input: ct82c710 - convert to the new platform device interface Do not use platform_device_register_simple() as it is going away, implement ->probe() and ->remove() functions so manual binding and unbinding will work with this driver. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ct82c710.c | 89 ++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 4da6c86b5d76..096b6a0b5cca 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -154,7 +154,7 @@ static int ct82c710_write(struct serio *port, unsigned char c) * See if we can find a 82C710 device. Read mouse address. */ -static int __init ct82c710_probe(void) +static int __init ct82c710_detect(void) { outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ outb_p(0xaa, 0x3fa); /* Inverse of 55 */ @@ -163,7 +163,7 @@ static int __init ct82c710_probe(void) outb_p(0x1b, 0x2fa); /* Inverse of e4 */ outb_p(0x0f, 0x390); /* Write index */ if (inb_p(0x391) != 0xe4) /* Config address found? */ - return -1; /* No: no 82C710 here */ + return -ENODEV; /* No: no 82C710 here */ outb_p(0x0d, 0x390); /* Write index */ ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ @@ -175,51 +175,88 @@ static int __init ct82c710_probe(void) return 0; } -static struct serio * __init ct82c710_allocate_port(void) +static int __devinit ct82c710_probe(struct platform_device *dev) { - struct serio *serio; - - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_8042; - serio->open = ct82c710_open; - serio->close = ct82c710_close; - serio->write = ct82c710_write; - serio->dev.parent = &ct82c710_device->dev; - strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); - snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA); - } + ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!ct82c710_port) + return -ENOMEM; + + ct82c710_port->id.type = SERIO_8042; + ct82c710_port->dev.parent = &dev->dev; + ct82c710_port->open = ct82c710_open; + ct82c710_port->close = ct82c710_close; + ct82c710_port->write = ct82c710_write; + strlcpy(ct82c710_port->name, "C&T 82c710 mouse port", + sizeof(ct82c710_port->name)); + snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys), + "isa%04lx/serio0", CT82C710_DATA); + + serio_register_port(ct82c710_port); + + return 0; +} + +static int __devexit ct82c710_remove(struct platform_device *dev) +{ + serio_unregister_port(ct82c710_port); - return serio; + return 0; } +static struct platform_driver ct82c710_driver = { + .driver = { + .name = "ct82c710", + .owner = THIS_MODULE, + }, + .probe = ct82c710_probe, + .remove = __devexit_p(ct82c710_remove), +}; + + static int __init ct82c710_init(void) { - if (ct82c710_probe()) - return -ENODEV; + int error; - ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1); - if (IS_ERR(ct82c710_device)) - return PTR_ERR(ct82c710_device); + error = ct82c710_detect(); + if (error) + return error; - if (!(ct82c710_port = ct82c710_allocate_port())) { - platform_device_unregister(ct82c710_device); - return -ENOMEM; + error = platform_driver_register(&ct82c710_driver); + if (error) + return error; + + ct82c710_device = platform_device_alloc("ct82c710", -1); + if (!ct82c710_device) { + error = -ENOMEM; + goto err_unregister_driver; } + error = platform_device_add_resources(ct82c710_device, &ct82c710_iores, 1); + if (error) + goto err_free_device; + + error = platform_device_add(ct82c710_device); + if (error) + goto err_free_device; + serio_register_port(ct82c710_port); printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n", CT82C710_DATA, CT82C710_IRQ); return 0; + + err_free_device: + platform_device_put(ct82c710_device); + err_unregister_driver: + platform_driver_unregister(&ct82c710_driver); + return error; } static void __exit ct82c710_exit(void) { - serio_unregister_port(ct82c710_port); platform_device_unregister(ct82c710_device); + platform_driver_unregister(&ct82c710_driver); } module_init(ct82c710_init); -- cgit v1.2.3 From 26421c7acc02847c724eb9f92797f84dbf9be007 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Dec 2005 01:25:42 -0500 Subject: Input: q40kbd - convert to the new platform device interface Do not use platform_device_register_simple() as it is going away, implement ->probe() and ->remove() functions so manual binding and unbinding will work with this driver. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/q40kbd.c | 89 ++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index b44d255596c2..d3827c5fe119 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -75,13 +75,13 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void q40kbd_flush(void) { - int maxread = 100; + int maxread = 100; unsigned long flags; spin_lock_irqsave(&q40kbd_lock, flags); - while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) - master_inb(KEYCODE_REG); + while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) + master_inb(KEYCODE_REG); spin_unlock_irqrestore(&q40kbd_lock, flags); } @@ -97,14 +97,14 @@ static int q40kbd_open(struct serio *port) if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); - return -1; + return -EBUSY; } - /* off we go */ - master_outb(-1, KEYBOARD_UNLOCK_REG); - master_outb(1, KEY_IRQ_ENABLE_REG); + /* off we go */ + master_outb(-1, KEYBOARD_UNLOCK_REG); + master_outb(1, KEY_IRQ_ENABLE_REG); - return 0; + return 0; } static void q40kbd_close(struct serio *port) @@ -116,48 +116,73 @@ static void q40kbd_close(struct serio *port) q40kbd_flush(); } -static struct serio * __init q40kbd_allocate_port(void) +static int __devinit q40kbd_probe(struct platform_device *dev) { - struct serio *serio; - - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_8042; - serio->open = q40kbd_open; - serio->close = q40kbd_close; - serio->dev.parent = &q40kbd_device->dev; - strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); - strlcpy(serio->phys, "Q40", sizeof(serio->phys)); - } + q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!q40kbd_port) + return -ENOMEM; + + q40kbd_port->id.type = SERIO_8042; + q40kbd_port->open = q40kbd_open; + q40kbd_port->close = q40kbd_close; + q40kbd_port->dev.parent = &dev->dev; + strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name)); + strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys)); + + serio_register_port(q40kbd_port); + printk(KERN_INFO "serio: Q40 kbd registered\n"); - return serio; + return 0; } +static int __devexit q40kbd_remove(struct platform_device *dev) +{ + serio_unregister_port(q40kbd_port); + + return 0; +} + +static struct platform_driver q40kbd_driver = { + .driver = { + .name = "q40kbd", + .owner = THIS_MODULE, + }, + .probe = q40kbd_probe, + .remove = __devexit_p(q40kbd_remove), +}; + static int __init q40kbd_init(void) { + int error; + if (!MACH_IS_Q40) return -EIO; - q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0); - if (IS_ERR(q40kbd_device)) - return PTR_ERR(q40kbd_device); + error = platform_driver_register(&q40kbd_driver); + if (error) + return error; - if (!(q40kbd_port = q40kbd_allocate_port())) { - platform_device_unregister(q40kbd_device); - return -ENOMEM; - } + q40kbd_device = platform_device_alloc("q40kbd", -1); + if (!q40kbd_device) + goto err_unregister_driver; - serio_register_port(q40kbd_port); - printk(KERN_INFO "serio: Q40 kbd registered\n"); + error = platform_device_add(q40kbd_device); + if (error) + goto err_free_device; return 0; + + err_free_device: + platform_device_put(q40kbd_device); + err_unregister_driver: + platform_driver_unregister(&q40kbd_driver); + return error; } static void __exit q40kbd_exit(void) { - serio_unregister_port(q40kbd_port); platform_device_unregister(q40kbd_device); + platform_driver_unregister(&q40kbd_driver); } module_init(q40kbd_init); -- cgit v1.2.3 From 9d6c25029db6de7fc375b07da936c3341af0accf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Dec 2005 01:25:53 -0500 Subject: Input: maceps2 - convert to the new platform device interface Do not use platform_device_register_simple() as it is going away, implement ->probe() and ->remove() functions so manual binding and unbinding will work with this driver. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/maceps2.c | 68 +++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index d857f7081adb..f08a5d0cd5fa 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -118,13 +118,12 @@ static void maceps2_close(struct serio *dev) } -static struct serio * __init maceps2_allocate_port(int idx) +static struct serio * __devinit maceps2_allocate_port(int idx) { struct serio *serio; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { - memset(serio, 0, sizeof(struct serio)); serio->id.type = SERIO_8042; serio->write = maceps2_write; serio->open = maceps2_open; @@ -138,24 +137,13 @@ static struct serio * __init maceps2_allocate_port(int idx) return serio; } - -static int __init maceps2_init(void) +static int __devinit maceps2_probe(struct platform_device *dev) { - maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0); - if (IS_ERR(maceps2_device)) - return PTR_ERR(maceps2_device); - - port_data[0].port = &mace->perif.ps2.keyb; - port_data[0].irq = MACEISA_KEYB_IRQ; - port_data[1].port = &mace->perif.ps2.mouse; - port_data[1].irq = MACEISA_MOUSE_IRQ; - maceps2_port[0] = maceps2_allocate_port(0); maceps2_port[1] = maceps2_allocate_port(1); if (!maceps2_port[0] || !maceps2_port[1]) { kfree(maceps2_port[0]); kfree(maceps2_port[1]); - platform_device_unregister(maceps2_device); return -ENOMEM; } @@ -165,11 +153,59 @@ static int __init maceps2_init(void) return 0; } -static void __exit maceps2_exit(void) +static int __devexit maceps2_remove(struct platform_device *dev) { serio_unregister_port(maceps2_port[0]); serio_unregister_port(maceps2_port[1]); + + return 0; +} + +static struct platform_driver maceps2_driver = { + .driver = { + .name = "maceps2", + .owner = THIS_MODULE, + }, + .probe = maceps2_probe, + .remove = __devexit_p(maceps2_remove), +}; + +static int __init maceps2_init(void) +{ + int error; + + error = platform_driver_register(&maceps2_driver); + if (error) + return error; + + maceps2_device = platform_device_alloc("maceps2", -1); + if (!maceps2_device) { + error = -ENOMEM; + goto err_unregister_driver; + } + + port_data[0].port = &mace->perif.ps2.keyb; + port_data[0].irq = MACEISA_KEYB_IRQ; + port_data[1].port = &mace->perif.ps2.mouse; + port_data[1].irq = MACEISA_MOUSE_IRQ; + + error = platform_device_add(maceps2_device); + if (error) + goto err_free_device; + + return 0; + + err_free_device: + platform_device_put(maceps2_device); + err_unregister_driver: + platform_driver_unregister(&maceps2_driver); + return error; +} + +static void __exit maceps2_exit(void) +{ platform_device_unregister(maceps2_device); + platform_driver_unregister(&maceps2_driver); } module_init(maceps2_init); -- cgit v1.2.3 From e7c3aad53dba54d375b632f2a21b680546828dec Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 28 Dec 2005 01:26:24 -0500 Subject: Input: wistron - convert to the new platform device interface Do not use platform_device_register_simple() as it is going away, implement ->probe() and ->remove() functions so manual binding and unbinding would work. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 114 +++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 46 deletions(-) diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index b77e2692ba3a..a05b8557842f 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -174,7 +174,7 @@ static u16 bios_pop_queue(void) return regs.eax; } -static void __init bios_attach(void) +static void __devinit bios_attach(void) { struct regs regs; @@ -194,7 +194,7 @@ static void bios_detach(void) call_bios(®s); } -static u8 __init bios_get_cmos_address(void) +static u8 __devinit bios_get_cmos_address(void) { struct regs regs; @@ -206,7 +206,7 @@ static u8 __init bios_get_cmos_address(void) return regs.ecx; } -static u16 __init bios_get_default_setting(u8 subsys) +static u16 __devinit bios_get_default_setting(u8 subsys) { struct regs regs; @@ -367,7 +367,7 @@ static int __init select_keymap(void) static struct input_dev *input_dev; -static int __init setup_input_dev(void) +static int __devinit setup_input_dev(void) { const struct key_entry *key; int error; @@ -466,6 +466,52 @@ static void poll_bios(unsigned long discard) mod_timer(&poll_timer, jiffies + HZ / POLL_FREQUENCY); } +static int __devinit wistron_probe(struct platform_device *dev) +{ + int err = setup_input_dev(); + if (err) + return err; + + bios_attach(); + cmos_address = bios_get_cmos_address(); + + if (have_wifi) { + u16 wifi = bios_get_default_setting(WIFI); + if (wifi & 1) + wifi_enabled = (wifi & 2) ? 1 : 0; + else + have_wifi = 0; + + if (have_wifi) + bios_set_state(WIFI, wifi_enabled); + } + + if (have_bluetooth) { + u16 bt = bios_get_default_setting(BLUETOOTH); + if (bt & 1) + bluetooth_enabled = (bt & 2) ? 1 : 0; + else + have_bluetooth = 0; + + if (have_bluetooth) + bios_set_state(BLUETOOTH, bluetooth_enabled); + } + + poll_bios(1); /* Flush stale event queue and arm timer */ + + return 0; +} + +static int __devexit wistron_remove(struct platform_device *dev) +{ + del_timer_sync(&poll_timer); + input_unregister_device(input_dev); + bios_detach(); + + return 0; +} + +#ifdef CONFIG_PM static int wistron_suspend(struct platform_device *dev, pm_message_t state) { del_timer_sync(&poll_timer); @@ -491,13 +537,20 @@ static int wistron_resume(struct platform_device *dev) return 0; } +#else +#define wistron_suspend NULL +#define wistron_resume NULL +#endif static struct platform_driver wistron_driver = { - .suspend = wistron_suspend, - .resume = wistron_resume, .driver = { .name = "wistron-bios", + .owner = THIS_MODULE, }, + .probe = wistron_probe, + .remove = __devexit_p(wistron_remove), + .suspend = wistron_suspend, + .resume = wistron_resume, }; static int __init wb_module_init(void) @@ -512,55 +565,27 @@ static int __init wb_module_init(void) if (err) return err; - bios_attach(); - cmos_address = bios_get_cmos_address(); - err = platform_driver_register(&wistron_driver); if (err) - goto err_detach_bios; + goto err_unmap_bios; - wistron_device = platform_device_register_simple("wistron-bios", -1, NULL, 0); - if (IS_ERR(wistron_device)) { - err = PTR_ERR(wistron_device); + wistron_device = platform_device_alloc("wistron-bios", -1); + if (!wistron_device) { + err = -ENOMEM; goto err_unregister_driver; } - if (have_wifi) { - u16 wifi = bios_get_default_setting(WIFI); - if (wifi & 1) - wifi_enabled = (wifi & 2) ? 1 : 0; - else - have_wifi = 0; - - if (have_wifi) - bios_set_state(WIFI, wifi_enabled); - } - - if (have_bluetooth) { - u16 bt = bios_get_default_setting(BLUETOOTH); - if (bt & 1) - bluetooth_enabled = (bt & 2) ? 1 : 0; - else - have_bluetooth = 0; - - if (have_bluetooth) - bios_set_state(BLUETOOTH, bluetooth_enabled); - } - - err = setup_input_dev(); + err = platform_device_add(wistron_device); if (err) - goto err_unregister_device; - - poll_bios(1); /* Flush stale event queue and arm timer */ + goto err_free_device; return 0; - err_unregister_device: - platform_device_unregister(wistron_device); + err_free_device: + platform_device_put(wistron_device); err_unregister_driver: platform_driver_unregister(&wistron_driver); - err_detach_bios: - bios_detach(); + err_unmap_bios: unmap_bios(); return err; @@ -568,11 +593,8 @@ static int __init wb_module_init(void) static void __exit wb_module_exit(void) { - del_timer_sync(&poll_timer); - input_unregister_device(input_dev); platform_device_unregister(wistron_device); platform_driver_unregister(&wistron_driver); - bios_detach(); unmap_bios(); } -- cgit v1.2.3 From 41c0d8680f7f24e1abaaeeabc6723277b2e34b81 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 28 Dec 2005 12:43:51 -0500 Subject: [ACPI] document processor.nocst parameter Signed-off-by: Len Brown --- Documentation/kernel-parameters.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5dffcfefc3c7..6e9f1dc26884 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1160,6 +1160,10 @@ running once the system is up. Limit processor to maximum C-state max_cstate=9 overrides any DMI blacklist limit. + processor.nocst [HW,ACPI] + Ignore the _CST method to determine C-states, + instead using the legacy FADT method + prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk before loading. See Documentation/ramdisk.txt. -- cgit v1.2.3 From b697b5372ecfe0c57ee26e0c3787fc2306109228 Mon Sep 17 00:00:00 2001 From: Karol Kozimor Date: Thu, 22 Dec 2005 12:42:00 -0500 Subject: [ASUS_ACPI] work around Samsung P30s oops The code used to rely on a certain method to return a NULL buffer, which is now hardly possible with the implicit return code on by default. This sort of fixes bugs #5067 and #5092 for now. Note: this patch makes the driver unusable on said machines (and on said machines only) iff acpi=strict is specified, but it seems noone really uses that. Signed-off-by: Karol Kozimor Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index fec895af6ae6..582995ef9f34 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -987,9 +987,21 @@ static int __init asus_hotk_get_info(void) printk(KERN_NOTICE " BSTS called, 0x%02x returned\n", bsts_result); - /* Samsung P30 has a device with a valid _HID whose INIT does not - * return anything. Catch this one and any similar here */ - if (buffer.pointer == NULL) { + /* This is unlikely with implicit return */ + if (buffer.pointer == NULL) + return -EINVAL; + + model = (union acpi_object *) buffer.pointer; + /* + * Samsung P30 has a device with a valid _HID whose INIT does not + * return anything. It used to be possible to catch this exception, + * but the implicit return code will now happily confuse the + * driver. We assume that every ACPI_TYPE_STRING is a valid model + * identifier but it's still possible to get completely bogus data. + */ + if (model->type == ACPI_TYPE_STRING) { + printk(KERN_NOTICE " %s model detected, ", model->string.pointer); + } else { if (asus_info && /* Samsung P30 */ strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) { hotk->model = P30; @@ -1002,13 +1014,10 @@ static int __init asus_hotk_get_info(void) "the developers with your DSDT\n"); } hotk->methods = &model_conf[hotk->model]; - return AE_OK; - } + + acpi_os_free(model); - model = (union acpi_object *)buffer.pointer; - if (model->type == ACPI_TYPE_STRING) { - printk(KERN_NOTICE " %s model detected, ", - model->string.pointer); + return AE_OK; } hotk->model = END_MODEL; -- cgit v1.2.3 From 6968e50c2b53805219618203db3d98566dfa1fdd Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 30 Dec 2005 00:32:49 -0500 Subject: [ACPI] linux-acpi@vger.kernel.org replaces acpi-devel@lists.sourceforge.net Signed-off-by: Len Brown --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6af683025ae0..07fd0a23379c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -182,7 +182,7 @@ S: Supported ACPI P: Len Brown M: len.brown@intel.com -L: acpi-devel@lists.sourceforge.net +L: linux-acpi@vger.kernel.org W: http://acpi.sourceforge.net/ T: git kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git S: Maintained -- cgit v1.2.3 From 04348e69e7e78ad69a09b2e1157f628d6c764370 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 30 Dec 2005 02:44:59 -0500 Subject: [ACPI] reduce kernel size: move 5BK .bss to 2.5KB .init.data put __initdata on sdt_entry[], as it is accessed only by __init functions. http://bugzilla.kernel.org/show_bug.cgi?id=1311 Signed-off-by: Len Brown --- drivers/acpi/tables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index a2bf25b05e1c..31d4f3ffc265 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -37,7 +37,7 @@ #define PREFIX "ACPI: " -#define ACPI_MAX_TABLES 256 +#define ACPI_MAX_TABLES 128 static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { [ACPI_TABLE_UNKNOWN] = "????", @@ -74,7 +74,7 @@ struct acpi_table_sdt { static unsigned long sdt_pa; /* Physical Address */ static unsigned long sdt_count; /* Table count */ -static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES]; +static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata; void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr) { -- cgit v1.2.3 From fdf7f2e91981938702ab2f58f44dc5685dd1bdc1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 31 Dec 2005 10:29:42 -0800 Subject: [CIFS] Fix typos in rfc1002pdu.h Pointed out by Leo Comitale Signed-off-by: Steve French --- fs/cifs/rfc1002pdu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h index 9222033cad8e..aede606132aa 100644 --- a/fs/cifs/rfc1002pdu.h +++ b/fs/cifs/rfc1002pdu.h @@ -24,11 +24,11 @@ /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ /* RFC 1002 session packet types */ -#define RFC1002_SESSION_MESASAGE 0x00 +#define RFC1002_SESSION_MESSAGE 0x00 #define RFC1002_SESSION_REQUEST 0x81 #define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 #define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 -#define RFC1002_RETARGET_SESSION_RESPONSE 0x83 +#define RFC1002_RETARGET_SESSION_RESPONSE 0x84 #define RFC1002_SESSION_KEEP_ALIVE 0x85 /* RFC 1002 flags (only one defined */ -- cgit v1.2.3 From a7a2cc315c8a5e51b08538d102ec3229c966ac87 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 13:54:04 +1100 Subject: drm: move ioctl flags to a bit field of flags From: Dave Airlie Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 8 ++- drivers/char/drm/drm_drv.c | 111 ++++++++++++++++++++-------------------- drivers/char/drm/i810_dma.c | 30 +++++------ drivers/char/drm/i830_dma.c | 28 +++++----- drivers/char/drm/i915_dma.c | 24 ++++----- drivers/char/drm/mga_state.c | 26 +++++----- drivers/char/drm/r128_state.c | 34 ++++++------ drivers/char/drm/radeon_state.c | 54 +++++++++---------- drivers/char/drm/savage_bci.c | 8 +-- drivers/char/drm/sis_mm.c | 12 ++--- drivers/char/drm/via_dma.c | 24 ++++----- 11 files changed, 182 insertions(+), 177 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 66814291949a..295de65b7088 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -272,10 +272,13 @@ typedef int drm_ioctl_t(struct inode *inode, struct file *filp, typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, unsigned long arg); +#define DRM_AUTH 0x1 +#define DRM_MASTER 0x2 +#define DRM_ROOT_ONLY 0x4 + typedef struct drm_ioctl_desc { drm_ioctl_t *func; - int auth_needed; - int root_only; + int flags; } drm_ioctl_desc_t; typedef struct drm_devstate { @@ -370,6 +373,7 @@ typedef struct drm_buf_entry { /** File private data */ typedef struct drm_file { int authenticated; + int master; int minor; pid_t pid; uid_t uid; diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 222ae09ae65f..5714d7badc41 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -56,66 +56,66 @@ static int drm_version(struct inode *inode, struct file *filp, /** Ioctl table */ static drm_ioctl_desc_t drm_ioctls[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, 0, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, 0, 1}, - - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, 1, 1}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, 1, 0}, - - [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, 1, 0}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, 1, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, 1, 0}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, 1, 1}, - - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, 1, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, 1, 0}, - - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, 1, 0}, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, 1, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, 1, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, 1, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH}, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH}, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH}, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH}, + + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH}, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH}, /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ + [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, #if __OS_HAS_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, #endif - [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, 1, 1}, - [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, }; #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls ) @@ -496,8 +496,9 @@ int drm_ioctl(struct inode *inode, struct file *filp, if (!func) { DRM_DEBUG("no function\n"); retcode = -EINVAL; - } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) || - (ioctl->auth_needed && !priv->authenticated)) { + } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || + ((ioctl->flags & DRM_AUTH) && !priv->authenticated) || + ((ioctl->flags & DRM_MASTER) && !priv->master)) { retcode = -EACCES; } else { retcode = func(inode, filp, cmd, arg); diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index a7df6147091c..cc1b89086876 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -1357,21 +1357,21 @@ int i810_driver_dma_quiescent(drm_device_t * dev) } drm_ioctl_desc_t i810_ioctls[] = { - [DRM_IOCTL_NR(DRM_I810_INIT)] = {i810_dma_init, 1, 1}, - [DRM_IOCTL_NR(DRM_I810_VERTEX)] = {i810_dma_vertex, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_CLEAR)] = {i810_clear_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_FLUSH)] = {i810_flush_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_GETAGE)] = {i810_getage, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_GETBUF)] = {i810_getbuf, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_SWAP)] = {i810_swap_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_COPY)] = {i810_copybuf, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_DOCOPY)] = {i810_docopy, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = {i810_ov0_info, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = {i810_fstatus, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = {i810_ov0_flip, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_MC)] = {i810_dma_mc, 1, 1}, - [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = {i810_rstatus, 1, 0}, - [DRM_IOCTL_NR(DRM_I810_FLIP)] = {i810_flip_bufs, 1, 0} + [DRM_IOCTL_NR(DRM_I810_INIT)] = {i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_I810_VERTEX)] = {i810_dma_vertex, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_CLEAR)] = {i810_clear_bufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_FLUSH)] = {i810_flush_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_GETAGE)] = {i810_getage, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_GETBUF)] = {i810_getbuf, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_SWAP)] = {i810_swap_bufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_COPY)] = {i810_copybuf, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_DOCOPY)] = {i810_docopy, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = {i810_ov0_info, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = {i810_fstatus, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = {i810_ov0_flip, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_MC)] = {i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = {i810_rstatus, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I810_FLIP)] = {i810_flip_bufs, DRM_AUTH} }; int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index f1e048f10ce8..4fea32aed6d2 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -1555,20 +1555,20 @@ int i830_driver_dma_quiescent(drm_device_t * dev) } drm_ioctl_desc_t i830_ioctls[] = { - [DRM_IOCTL_NR(DRM_I830_INIT)] = {i830_dma_init, 1, 1}, - [DRM_IOCTL_NR(DRM_I830_VERTEX)] = {i830_dma_vertex, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_CLEAR)] = {i830_clear_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_FLUSH)] = {i830_flush_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_GETAGE)] = {i830_getage, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_GETBUF)] = {i830_getbuf, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_SWAP)] = {i830_swap_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_COPY)] = {i830_copybuf, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_DOCOPY)] = {i830_docopy, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_FLIP)] = {i830_flip_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = {i830_irq_emit, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = {i830_irq_wait, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = {i830_getparam, 1, 0}, - [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = {i830_setparam, 1, 0} + [DRM_IOCTL_NR(DRM_I830_INIT)] = {i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_I830_VERTEX)] = {i830_dma_vertex, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_CLEAR)] = {i830_clear_bufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_FLUSH)] = {i830_flush_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_GETAGE)] = {i830_getage, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_GETBUF)] = {i830_getbuf, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_SWAP)] = {i830_swap_bufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_COPY)] = {i830_copybuf, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_DOCOPY)] = {i830_docopy, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_FLIP)] = {i830_flip_bufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = {i830_irq_emit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = {i830_irq_wait, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = {i830_getparam, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = {i830_setparam, DRM_AUTH} }; int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 9ef3be31a812..6cc3584e367f 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -729,18 +729,18 @@ void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) } drm_ioctl_desc_t i915_ioctls[] = { - [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1}, - [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1}, - [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1}, - [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0} + [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH} }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c index 47f54b5ae956..2837e669183a 100644 --- a/drivers/char/drm/mga_state.c +++ b/drivers/char/drm/mga_state.c @@ -1127,19 +1127,19 @@ static int mga_wait_fence(DRM_IOCTL_ARGS) } drm_ioctl_desc_t mga_ioctls[] = { - [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1}, - [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0}, - [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1}, + [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, }; int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 1f04e3372206..6aeeb4b62d03 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -1690,23 +1690,23 @@ void r128_driver_lastclose(drm_device_t * dev) } drm_ioctl_desc_t r128_ioctls[] = { - [DRM_IOCTL_NR(DRM_R128_INIT)] = {r128_cce_init, 1, 1}, - [DRM_IOCTL_NR(DRM_R128_CCE_START)] = {r128_cce_start, 1, 1}, - [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = {r128_cce_stop, 1, 1}, - [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = {r128_cce_reset, 1, 1}, - [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = {r128_cce_idle, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_RESET)] = {r128_engine_reset, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = {r128_fullscreen, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_SWAP)] = {r128_cce_swap, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_FLIP)] = {r128_cce_flip, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_CLEAR)] = {r128_cce_clear, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_VERTEX)] = {r128_cce_vertex, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_INDICES)] = {r128_cce_indices, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_BLIT)] = {r128_cce_blit, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_DEPTH)] = {r128_cce_depth, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = {r128_cce_stipple, 1, 0}, - [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = {r128_cce_indirect, 1, 1}, - [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = {r128_getparam, 1, 0}, + [DRM_IOCTL_NR(DRM_R128_INIT)] = {r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_R128_CCE_START)] = {r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = {r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = {r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = {r128_cce_idle, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_RESET)] = {r128_engine_reset, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = {r128_fullscreen, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_SWAP)] = {r128_cce_swap, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_FLIP)] = {r128_cce_flip, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_CLEAR)] = {r128_cce_clear, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_VERTEX)] = {r128_cce_vertex, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_INDICES)] = {r128_cce_indices, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_BLIT)] = {r128_cce_blit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_DEPTH)] = {r128_cce_depth, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = {r128_cce_stipple, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = {r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = {r128_getparam, DRM_AUTH}, }; int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls); diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 717f546cc448..9e816c63a8a3 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -3116,33 +3116,33 @@ void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv) } drm_ioctl_desc_t radeon_ioctls[] = { - [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, 1, 1}, - [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, 1, 1}, - [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, 1, 1}, - [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, 1, 1}, - [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, 1, 1}, - [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, 1, 1}, - [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, 1, 0} + [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH} }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index c3101702a1fe..00658621b2f6 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -1104,10 +1104,10 @@ void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp) } drm_ioctl_desc_t savage_ioctls[] = { - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, 1, 1}, - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, 1, 0}, - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, 1, 0}, - [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, 1, 0}, + [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, DRM_AUTH}, }; int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls); diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index a8529728fa63..f0488db001a4 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c @@ -403,12 +403,12 @@ int sis_final_context(struct drm_device *dev, int context) } drm_ioctl_desc_t sis_ioctls[] = { - [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, 1, 0}, - [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, 1, 1}, - [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, 1, 0}, - [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, 1, 1} + [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY} }; int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index 1acbeeb28069..fa1cb5062cf7 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -725,18 +725,18 @@ int via_cmdbuf_size(DRM_IOCTL_ARGS) } drm_ioctl_desc_t via_ioctls[] = { - [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}, - [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0} + [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER}, + [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER}, + [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER}, + [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH} }; int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); -- cgit v1.2.3 From 443448d05468277abe99c9b24b9df538dd840f35 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 14:26:20 +1100 Subject: drm: via driver update to CVS version This updates the DRM via driver to the latest CVS version, which contains support for DMA blitting. It also contains some whitespace and other minor fixes From: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/char/drm/via_dma.c | 4 +- drivers/char/drm/via_dmablit.c | 805 +++++++++++++++++++++++++++++++++++++++++ drivers/char/drm/via_dmablit.h | 138 +++++++ drivers/char/drm/via_drm.h | 2 +- drivers/char/drm/via_drv.h | 4 +- drivers/char/drm/via_mm.c | 4 +- 6 files changed, 951 insertions(+), 6 deletions(-) create mode 100644 drivers/char/drm/via_dmablit.c create mode 100644 drivers/char/drm/via_dmablit.h diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index fa1cb5062cf7..593c0b8f650a 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -736,7 +736,9 @@ drm_ioctl_desc_t via_ioctls[] = { [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH}, [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH} + [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH} }; int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c new file mode 100644 index 000000000000..9d5e027dae0e --- /dev/null +++ b/drivers/char/drm/via_dmablit.c @@ -0,0 +1,805 @@ +/* via_dmablit.c -- PCI DMA BitBlt support for the VIA Unichrome/Pro + * + * Copyright (C) 2005 Thomas Hellstrom, All Rights Reserved. + * + * 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, sub license, + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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: + * Thomas Hellstrom. + * Partially based on code obtained from Digeo Inc. + */ + + +/* + * Unmaps the DMA mappings. + * FIXME: Is this a NoOp on x86? Also + * FIXME: What happens if this one is called and a pending blit has previously done + * the same DMA mappings? + */ + +#include "drmP.h" +#include "via_drm.h" +#include "via_drv.h" +#include "via_dmablit.h" + +#include + +#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK) +#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK) +#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT) + +typedef struct _drm_via_descriptor { + uint32_t mem_addr; + uint32_t dev_addr; + uint32_t size; + uint32_t next; +} drm_via_descriptor_t; + + +/* + * Unmap a DMA mapping. + */ + + + +static void +via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg) +{ + int num_desc = vsg->num_desc; + unsigned cur_descriptor_page = num_desc / vsg->descriptors_per_page; + unsigned descriptor_this_page = num_desc % vsg->descriptors_per_page; + drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] + + descriptor_this_page; + dma_addr_t next = vsg->chain_start; + + while(num_desc--) { + if (descriptor_this_page-- == 0) { + cur_descriptor_page--; + descriptor_this_page = vsg->descriptors_per_page - 1; + desc_ptr = vsg->desc_pages[cur_descriptor_page] + + descriptor_this_page; + } + dma_unmap_single(&pdev->dev, next, sizeof(*desc_ptr), DMA_TO_DEVICE); + dma_unmap_page(&pdev->dev, desc_ptr->mem_addr, desc_ptr->size, vsg->direction); + next = (dma_addr_t) desc_ptr->next; + desc_ptr--; + } +} + +/* + * If mode = 0, count how many descriptors are needed. + * If mode = 1, Map the DMA pages for the device, put together and map also the descriptors. + * Descriptors are run in reverse order by the hardware because we are not allowed to update the + * 'next' field without syncing calls when the descriptor is already mapped. + */ + +static void +via_map_blit_for_device(struct pci_dev *pdev, + const drm_via_dmablit_t *xfer, + drm_via_sg_info_t *vsg, + int mode) +{ + unsigned cur_descriptor_page = 0; + unsigned num_descriptors_this_page = 0; + unsigned char *mem_addr = xfer->mem_addr; + unsigned char *cur_mem; + unsigned char *first_addr = (unsigned char *)VIA_PGDN(mem_addr); + uint32_t fb_addr = xfer->fb_addr; + uint32_t cur_fb; + unsigned long line_len; + unsigned remaining_len; + int num_desc = 0; + int cur_line; + dma_addr_t next = 0 | VIA_DMA_DPR_EC; + drm_via_descriptor_t *desc_ptr = 0; + + if (mode == 1) + desc_ptr = vsg->desc_pages[cur_descriptor_page]; + + for (cur_line = 0; cur_line < xfer->num_lines; ++cur_line) { + + line_len = xfer->line_length; + cur_fb = fb_addr; + cur_mem = mem_addr; + + while (line_len > 0) { + + remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); + line_len -= remaining_len; + + if (mode == 1) { + desc_ptr->mem_addr = + dma_map_page(&pdev->dev, + vsg->pages[VIA_PFN(cur_mem) - + VIA_PFN(first_addr)], + VIA_PGOFF(cur_mem), remaining_len, + vsg->direction); + desc_ptr->dev_addr = cur_fb; + + desc_ptr->size = remaining_len; + desc_ptr->next = (uint32_t) next; + next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), + DMA_TO_DEVICE); + desc_ptr++; + if (++num_descriptors_this_page >= vsg->descriptors_per_page) { + num_descriptors_this_page = 0; + desc_ptr = vsg->desc_pages[++cur_descriptor_page]; + } + } + + num_desc++; + cur_mem += remaining_len; + cur_fb += remaining_len; + } + + mem_addr += xfer->mem_stride; + fb_addr += xfer->fb_stride; + } + + if (mode == 1) { + vsg->chain_start = next; + vsg->state = dr_via_device_mapped; + } + vsg->num_desc = num_desc; +} + +/* + * Function that frees up all resources for a blit. It is usable even if the + * blit info has only be partially built as long as the status enum is consistent + * with the actual status of the used resources. + */ + + +void +via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) +{ + struct page *page; + int i; + + switch(vsg->state) { + case dr_via_device_mapped: + via_unmap_blit_from_device(pdev, vsg); + case dr_via_desc_pages_alloc: + for (i=0; inum_desc_pages; ++i) { + if (vsg->desc_pages[i] != NULL) + free_page((unsigned long)vsg->desc_pages[i]); + } + kfree(vsg->desc_pages); + case dr_via_pages_locked: + for (i=0; inum_pages; ++i) { + if ( NULL != (page = vsg->pages[i])) { + if (! PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction)) + SetPageDirty(page); + page_cache_release(page); + } + } + case dr_via_pages_alloc: + vfree(vsg->pages); + default: + vsg->state = dr_via_sg_init; + } + if (vsg->bounce_buffer) { + vfree(vsg->bounce_buffer); + vsg->bounce_buffer = NULL; + } + vsg->free_on_sequence = 0; +} + +/* + * Fire a blit engine. + */ + +static void +via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + + VIA_WRITE(VIA_PCI_DMA_MAR0 + engine*0x10, 0); + VIA_WRITE(VIA_PCI_DMA_DAR0 + engine*0x10, 0); + VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD | + VIA_DMA_CSR_DE); + VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE); + VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0); + VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start); + VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS); +} + +/* + * Obtain a page pointer array and lock all pages into system memory. A segmentation violation will + * occur here if the calling user does not have access to the submitted address. + */ + +static int +via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) +{ + int ret; + unsigned long first_pfn = VIA_PFN(xfer->mem_addr); + vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride -1)) - + first_pfn + 1; + + if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages))) + return DRM_ERR(ENOMEM); + memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages); + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, (unsigned long) xfer->mem_addr, + vsg->num_pages, vsg->direction, 0, vsg->pages, NULL); + + up_read(¤t->mm->mmap_sem); + if (ret != vsg->num_pages) { + if (ret < 0) + return ret; + vsg->state = dr_via_pages_locked; + return DRM_ERR(EINVAL); + } + vsg->state = dr_via_pages_locked; + DRM_DEBUG("DMA pages locked\n"); + return 0; +} + +/* + * Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the + * pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be + * quite large for some blits, and pages don't need to be contingous. + */ + +static int +via_alloc_desc_pages(drm_via_sg_info_t *vsg) +{ + int i; + + vsg->descriptors_per_page = PAGE_SIZE / sizeof( drm_via_descriptor_t); + vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / + vsg->descriptors_per_page; + + if (NULL == (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL))) + return DRM_ERR(ENOMEM); + + memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages); + vsg->state = dr_via_desc_pages_alloc; + for (i=0; inum_desc_pages; ++i) { + if (NULL == (vsg->desc_pages[i] = + (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL))) + return DRM_ERR(ENOMEM); + } + DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages, + vsg->num_desc); + return 0; +} + +static void +via_abort_dmablit(drm_device_t *dev, int engine) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + + VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TA); +} + +static void +via_dmablit_engine_off(drm_device_t *dev, int engine) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + + VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD); +} + + + +/* + * The dmablit part of the IRQ handler. Trying to do only reasonably fast things here. + * The rest, like unmapping and freeing memory for done blits is done in a separate workqueue + * task. Basically the task of the interrupt handler is to submit a new blit to the engine, while + * the workqueue task takes care of processing associated with the old blit. + */ + +void +via_dmablit_handler(drm_device_t *dev, int engine, int from_irq) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; + int cur; + int done_transfer; + unsigned long irqsave=0; + uint32_t status = 0; + + DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n", + engine, from_irq, (unsigned long) blitq); + + if (from_irq) { + spin_lock(&blitq->blit_lock); + } else { + spin_lock_irqsave(&blitq->blit_lock, irqsave); + } + + done_transfer = blitq->is_active && + (( status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD); + done_transfer = done_transfer || ( blitq->aborting && !(status & VIA_DMA_CSR_DE)); + + cur = blitq->cur; + if (done_transfer) { + + blitq->blits[cur]->aborted = blitq->aborting; + blitq->done_blit_handle++; + DRM_WAKEUP(blitq->blit_queue + cur); + + cur++; + if (cur >= VIA_NUM_BLIT_SLOTS) + cur = 0; + blitq->cur = cur; + + /* + * Clear transfer done flag. + */ + + VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD); + + blitq->is_active = 0; + blitq->aborting = 0; + schedule_work(&blitq->wq); + + } else if (blitq->is_active && time_after_eq(jiffies, blitq->end)) { + + /* + * Abort transfer after one second. + */ + + via_abort_dmablit(dev, engine); + blitq->aborting = 1; + blitq->end = jiffies + DRM_HZ; + } + + if (!blitq->is_active) { + if (blitq->num_outstanding) { + via_fire_dmablit(dev, blitq->blits[cur], engine); + blitq->is_active = 1; + blitq->cur = cur; + blitq->num_outstanding--; + blitq->end = jiffies + DRM_HZ; + if (!timer_pending(&blitq->poll_timer)) { + blitq->poll_timer.expires = jiffies+1; + add_timer(&blitq->poll_timer); + } + } else { + if (timer_pending(&blitq->poll_timer)) { + del_timer(&blitq->poll_timer); + } + via_dmablit_engine_off(dev, engine); + } + } + + if (from_irq) { + spin_unlock(&blitq->blit_lock); + } else { + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + } +} + + + +/* + * Check whether this blit is still active, performing necessary locking. + */ + +static int +via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_queue_head_t **queue) +{ + unsigned long irqsave; + uint32_t slot; + int active; + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + /* + * Allow for handle wraparounds. + */ + + active = ((blitq->done_blit_handle - handle) > (1 << 23)) && + ((blitq->cur_blit_handle - handle) <= (1 << 23)); + + if (queue && active) { + slot = handle - blitq->done_blit_handle + blitq->cur -1; + if (slot >= VIA_NUM_BLIT_SLOTS) { + slot -= VIA_NUM_BLIT_SLOTS; + } + *queue = blitq->blit_queue + slot; + } + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + return active; +} + +/* + * Sync. Wait for at least three seconds for the blit to be performed. + */ + +static int +via_dmablit_sync(drm_device_t *dev, uint32_t handle, int engine) +{ + + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; + wait_queue_head_t *queue; + int ret = 0; + + if (via_dmablit_active(blitq, engine, handle, &queue)) { + DRM_WAIT_ON(ret, *queue, 3 * DRM_HZ, + !via_dmablit_active(blitq, engine, handle, NULL)); + } + DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n", + handle, engine, ret); + + return ret; +} + + +/* + * A timer that regularly polls the blit engine in cases where we don't have interrupts: + * a) Broken hardware (typically those that don't have any video capture facility). + * b) Blit abort. The hardware doesn't send an interrupt when a blit is aborted. + * The timer and hardware IRQ's can and do work in parallel. If the hardware has + * irqs, it will shorten the latency somewhat. + */ + + + +static void +via_dmablit_timer(unsigned long data) +{ + drm_via_blitq_t *blitq = (drm_via_blitq_t *) data; + drm_device_t *dev = blitq->dev; + int engine = (int) + (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues); + + DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine, + (unsigned long) jiffies); + + via_dmablit_handler(dev, engine, 0); + + if (!timer_pending(&blitq->poll_timer)) { + blitq->poll_timer.expires = jiffies+1; + add_timer(&blitq->poll_timer); + } + via_dmablit_handler(dev, engine, 0); + +} + + + + +/* + * Workqueue task that frees data and mappings associated with a blit. + * Also wakes up waiting processes. Each of these tasks handles one + * blit engine only and may not be called on each interrupt. + */ + + +static void +via_dmablit_workqueue(void *data) +{ + drm_via_blitq_t *blitq = (drm_via_blitq_t *) data; + drm_device_t *dev = blitq->dev; + unsigned long irqsave; + drm_via_sg_info_t *cur_sg; + int cur_released; + + + DRM_DEBUG("Workqueue task called for blit engine %ld\n",(unsigned long) + (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues)); + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + while(blitq->serviced != blitq->cur) { + + cur_released = blitq->serviced++; + + DRM_DEBUG("Releasing blit slot %d\n", cur_released); + + if (blitq->serviced >= VIA_NUM_BLIT_SLOTS) + blitq->serviced = 0; + + cur_sg = blitq->blits[cur_released]; + blitq->num_free++; + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + DRM_WAKEUP(&blitq->busy_queue); + + via_free_sg_info(dev->pdev, cur_sg); + kfree(cur_sg); + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + } + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); +} + + +/* + * Init all blit engines. Currently we use two, but some hardware have 4. + */ + + +void +via_init_dmablit(drm_device_t *dev) +{ + int i,j; + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_blitq_t *blitq; + + pci_set_master(dev->pdev); + + for (i=0; i< VIA_NUM_BLIT_ENGINES; ++i) { + blitq = dev_priv->blit_queues + i; + blitq->dev = dev; + blitq->cur_blit_handle = 0; + blitq->done_blit_handle = 0; + blitq->head = 0; + blitq->cur = 0; + blitq->serviced = 0; + blitq->num_free = VIA_NUM_BLIT_SLOTS; + blitq->num_outstanding = 0; + blitq->is_active = 0; + blitq->aborting = 0; + blitq->blit_lock = SPIN_LOCK_UNLOCKED; + for (j=0; jblit_queue + j); + } + DRM_INIT_WAITQUEUE(&blitq->busy_queue); + INIT_WORK(&blitq->wq, via_dmablit_workqueue, blitq); + init_timer(&blitq->poll_timer); + blitq->poll_timer.function = &via_dmablit_timer; + blitq->poll_timer.data = (unsigned long) blitq; + } +} + +/* + * Build all info and do all mappings required for a blit. + */ + + +static int +via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) +{ + int draw = xfer->to_fb; + int ret = 0; + + vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + vsg->bounce_buffer = 0; + + vsg->state = dr_via_sg_init; + + if (xfer->num_lines <= 0 || xfer->line_length <= 0) { + DRM_ERROR("Zero size bitblt.\n"); + return DRM_ERR(EINVAL); + } + + /* + * Below check is a driver limitation, not a hardware one. We + * don't want to lock unused pages, and don't want to incoporate the + * extra logic of avoiding them. Make sure there are no. + * (Not a big limitation anyway.) + */ + + if (((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) || + (xfer->mem_stride > 2048*4)) { + DRM_ERROR("Too large system memory stride. Stride: %d, " + "Length: %d\n", xfer->mem_stride, xfer->line_length); + return DRM_ERR(EINVAL); + } + + if (xfer->num_lines > 2048) { + DRM_ERROR("Too many PCI DMA bitblt lines.\n"); + return DRM_ERR(EINVAL); + } + + /* + * we allow a negative fb stride to allow flipping of images in + * transfer. + */ + + if (xfer->mem_stride < xfer->line_length || + abs(xfer->fb_stride) < xfer->line_length) { + DRM_ERROR("Invalid frame-buffer / memory stride.\n"); + return DRM_ERR(EINVAL); + } + + /* + * A hardware bug seems to be worked around if system memory addresses start on + * 16 byte boundaries. This seems a bit restrictive however. VIA is contacted + * about this. Meanwhile, impose the following restrictions: + */ + +#ifdef VIA_BUGFREE + if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || + ((xfer->mem_stride & 3) != (xfer->fb_stride & 3))) { + DRM_ERROR("Invalid DRM bitblt alignment.\n"); + return DRM_ERR(EINVAL); + } +#else + if ((((unsigned long)xfer->mem_addr & 15) || + ((unsigned long)xfer->fb_addr & 3)) || (xfer->mem_stride & 15) || + (xfer->fb_stride & 3)) { + DRM_ERROR("Invalid DRM bitblt alignment.\n"); + return DRM_ERR(EINVAL); + } +#endif + + if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) { + DRM_ERROR("Could not lock DMA pages.\n"); + via_free_sg_info(dev->pdev, vsg); + return ret; + } + + via_map_blit_for_device(dev->pdev, xfer, vsg, 0); + if (0 != (ret = via_alloc_desc_pages(vsg))) { + DRM_ERROR("Could not allocate DMA descriptor pages.\n"); + via_free_sg_info(dev->pdev, vsg); + return ret; + } + via_map_blit_for_device(dev->pdev, xfer, vsg, 1); + + return 0; +} + + +/* + * Reserve one free slot in the blit queue. Will wait for one second for one + * to become available. Otherwise -EBUSY is returned. + */ + +static int +via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine) +{ + int ret=0; + unsigned long irqsave; + + DRM_DEBUG("Num free is %d\n", blitq->num_free); + spin_lock_irqsave(&blitq->blit_lock, irqsave); + while(blitq->num_free == 0) { + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0); + if (ret) { + return (DRM_ERR(EINTR) == ret) ? DRM_ERR(EAGAIN) : ret; + } + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + } + + blitq->num_free--; + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + return 0; +} + +/* + * Hand back a free slot if we changed our mind. + */ + +static void +via_dmablit_release_slot(drm_via_blitq_t *blitq) +{ + unsigned long irqsave; + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + blitq->num_free++; + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + DRM_WAKEUP( &blitq->busy_queue ); +} + +/* + * Grab a free slot. Build blit info and queue a blit. + */ + + +static int +via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_sg_info_t *vsg; + drm_via_blitq_t *blitq; + int ret; + int engine; + unsigned long irqsave; + + if (dev_priv == NULL) { + DRM_ERROR("Called without initialization.\n"); + return DRM_ERR(EINVAL); + } + + engine = (xfer->to_fb) ? 0 : 1; + blitq = dev_priv->blit_queues + engine; + if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) { + return ret; + } + if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) { + via_dmablit_release_slot(blitq); + return DRM_ERR(ENOMEM); + } + if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) { + via_dmablit_release_slot(blitq); + kfree(vsg); + return ret; + } + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + blitq->blits[blitq->head++] = vsg; + if (blitq->head >= VIA_NUM_BLIT_SLOTS) + blitq->head = 0; + blitq->num_outstanding++; + xfer->sync.sync_handle = ++blitq->cur_blit_handle; + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + xfer->sync.engine = engine; + + via_dmablit_handler(dev, engine, 0); + + return 0; +} + +/* + * Sync on a previously submitted blit. Note that the X server use signals extensively, and + * that there is a very big proability that this IOCTL will be interrupted by a signal. In that + * case it returns with -EAGAIN for the signal to be delivered. + * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock(). + */ + +int +via_dma_blit_sync( DRM_IOCTL_ARGS ) +{ + drm_via_blitsync_t sync; + int err; + DRM_DEVICE; + + DRM_COPY_FROM_USER_IOCTL(sync, (drm_via_blitsync_t *)data, sizeof(sync)); + + if (sync.engine >= VIA_NUM_BLIT_ENGINES) + return DRM_ERR(EINVAL); + + err = via_dmablit_sync(dev, sync.sync_handle, sync.engine); + + if (DRM_ERR(EINTR) == err) + err = DRM_ERR(EAGAIN); + + return err; +} + + +/* + * Queue a blit and hand back a handle to be used for sync. This IOCTL may be interrupted by a signal + * while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should + * be reissued. See the above IOCTL code. + */ + +int +via_dma_blit( DRM_IOCTL_ARGS ) +{ + drm_via_dmablit_t xfer; + int err; + DRM_DEVICE; + + DRM_COPY_FROM_USER_IOCTL(xfer, (drm_via_dmablit_t __user *)data, sizeof(xfer)); + + err = via_dmablit(dev, &xfer); + + DRM_COPY_TO_USER_IOCTL((void __user *)data, xfer, sizeof(xfer)); + + return err; +} diff --git a/drivers/char/drm/via_dmablit.h b/drivers/char/drm/via_dmablit.h new file mode 100644 index 000000000000..6486391746b1 --- /dev/null +++ b/drivers/char/drm/via_dmablit.h @@ -0,0 +1,138 @@ +/* via_dmablit.h -- PCI DMA BitBlt support for the VIA Unichrome/Pro + * + * Copyright 2005 Thomas Hellstrom. + * All Rights Reserved. + * + * 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, sub license, + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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: + * Thomas Hellstrom. + * Register info from Digeo Inc. + */ + +#ifndef _VIA_DMABLIT_H +#define _VIA_DMABLIT_H + +#define VIA_NUM_BLIT_ENGINES 2 +#define VIA_NUM_BLIT_SLOTS 8 + +struct _drm_via_descriptor; + +typedef struct _drm_via_sg_info { + struct page **pages; + unsigned long num_pages; + struct _drm_via_descriptor **desc_pages; + int num_desc_pages; + int num_desc; + enum dma_data_direction direction; + unsigned char *bounce_buffer; + dma_addr_t chain_start; + uint32_t free_on_sequence; + unsigned int descriptors_per_page; + int aborted; + enum { + dr_via_device_mapped, + dr_via_desc_pages_alloc, + dr_via_pages_locked, + dr_via_pages_alloc, + dr_via_sg_init + } state; +} drm_via_sg_info_t; + +typedef struct _drm_via_blitq { + drm_device_t *dev; + uint32_t cur_blit_handle; + uint32_t done_blit_handle; + unsigned serviced; + unsigned head; + unsigned cur; + unsigned num_free; + unsigned num_outstanding; + unsigned long end; + int aborting; + int is_active; + drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS]; + spinlock_t blit_lock; + wait_queue_head_t blit_queue[VIA_NUM_BLIT_SLOTS]; + wait_queue_head_t busy_queue; + struct work_struct wq; + struct timer_list poll_timer; +} drm_via_blitq_t; + + +/* + * PCI DMA Registers + * Channels 2 & 3 don't seem to be implemented in hardware. + */ + +#define VIA_PCI_DMA_MAR0 0xE40 /* Memory Address Register of Channel 0 */ +#define VIA_PCI_DMA_DAR0 0xE44 /* Device Address Register of Channel 0 */ +#define VIA_PCI_DMA_BCR0 0xE48 /* Byte Count Register of Channel 0 */ +#define VIA_PCI_DMA_DPR0 0xE4C /* Descriptor Pointer Register of Channel 0 */ + +#define VIA_PCI_DMA_MAR1 0xE50 /* Memory Address Register of Channel 1 */ +#define VIA_PCI_DMA_DAR1 0xE54 /* Device Address Register of Channel 1 */ +#define VIA_PCI_DMA_BCR1 0xE58 /* Byte Count Register of Channel 1 */ +#define VIA_PCI_DMA_DPR1 0xE5C /* Descriptor Pointer Register of Channel 1 */ + +#define VIA_PCI_DMA_MAR2 0xE60 /* Memory Address Register of Channel 2 */ +#define VIA_PCI_DMA_DAR2 0xE64 /* Device Address Register of Channel 2 */ +#define VIA_PCI_DMA_BCR2 0xE68 /* Byte Count Register of Channel 2 */ +#define VIA_PCI_DMA_DPR2 0xE6C /* Descriptor Pointer Register of Channel 2 */ + +#define VIA_PCI_DMA_MAR3 0xE70 /* Memory Address Register of Channel 3 */ +#define VIA_PCI_DMA_DAR3 0xE74 /* Device Address Register of Channel 3 */ +#define VIA_PCI_DMA_BCR3 0xE78 /* Byte Count Register of Channel 3 */ +#define VIA_PCI_DMA_DPR3 0xE7C /* Descriptor Pointer Register of Channel 3 */ + +#define VIA_PCI_DMA_MR0 0xE80 /* Mode Register of Channel 0 */ +#define VIA_PCI_DMA_MR1 0xE84 /* Mode Register of Channel 1 */ +#define VIA_PCI_DMA_MR2 0xE88 /* Mode Register of Channel 2 */ +#define VIA_PCI_DMA_MR3 0xE8C /* Mode Register of Channel 3 */ + +#define VIA_PCI_DMA_CSR0 0xE90 /* Command/Status Register of Channel 0 */ +#define VIA_PCI_DMA_CSR1 0xE94 /* Command/Status Register of Channel 1 */ +#define VIA_PCI_DMA_CSR2 0xE98 /* Command/Status Register of Channel 2 */ +#define VIA_PCI_DMA_CSR3 0xE9C /* Command/Status Register of Channel 3 */ + +#define VIA_PCI_DMA_PTR 0xEA0 /* Priority Type Register */ + +/* Define for DMA engine */ +/* DPR */ +#define VIA_DMA_DPR_EC (1<<1) /* end of chain */ +#define VIA_DMA_DPR_DDIE (1<<2) /* descriptor done interrupt enable */ +#define VIA_DMA_DPR_DT (1<<3) /* direction of transfer (RO) */ + +/* MR */ +#define VIA_DMA_MR_CM (1<<0) /* chaining mode */ +#define VIA_DMA_MR_TDIE (1<<1) /* transfer done interrupt enable */ +#define VIA_DMA_MR_HENDMACMD (1<<7) /* ? */ + +/* CSR */ +#define VIA_DMA_CSR_DE (1<<0) /* DMA enable */ +#define VIA_DMA_CSR_TS (1<<1) /* transfer start */ +#define VIA_DMA_CSR_TA (1<<2) /* transfer abort */ +#define VIA_DMA_CSR_TD (1<<3) /* transfer done */ +#define VIA_DMA_CSR_DD (1<<4) /* descriptor done */ +#define VIA_DMA_DPR_EC (1<<1) /* end of chain */ + + + +#endif diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h index 556d80722fd0..47f0b5b26379 100644 --- a/drivers/char/drm/via_drm.h +++ b/drivers/char/drm/via_drm.h @@ -200,7 +200,7 @@ typedef struct _drm_via_sarea { unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS]; unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */ - /* Used bt the 3d driver only at this point, for pageflipping: + /* Used by the 3d driver only at this point, for pageflipping: */ unsigned int pfCurrentOffset; } drm_via_sarea_t; diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index 0606c752dccb..aad4f99f5405 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -28,11 +28,11 @@ #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20051022" +#define DRIVER_DATE "20051116" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 7 -#define DRIVER_PATCHLEVEL 2 +#define DRIVER_PATCHLEVEL 4 #include "via_verifier.h" diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c index 62e692556a1d..33e0cb12e4c3 100644 --- a/drivers/char/drm/via_mm.c +++ b/drivers/char/drm/via_mm.c @@ -42,7 +42,7 @@ static int via_agp_free(drm_via_mem_t * mem); static int via_fb_alloc(drm_via_mem_t * mem); static int via_fb_free(drm_via_mem_t * mem); -static int add_alloc_set(int context, int type, unsigned int val) +static int add_alloc_set(int context, int type, unsigned long val) { int i, retval = 0; @@ -56,7 +56,7 @@ static int add_alloc_set(int context, int type, unsigned int val) return retval; } -static int del_alloc_set(int context, int type, unsigned int val) +static int del_alloc_set(int context, int type, unsigned long val) { int i, retval = 0; -- cgit v1.2.3 From 952d751a140e961f7ac67f743cf94d1a37c736e8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 14:44:12 +1100 Subject: drm: bring sis + tdfx up to latest CVS Cleanup SIS + TDFX drivers with latest changes from CVS. From: Eric Anholt Signed-off-by: Dave Airlie --- drivers/char/drm/sis_drm.h | 25 +++++++++++++++++++++++++ drivers/char/drm/sis_drv.h | 4 ++-- drivers/char/drm/sis_ds.h | 7 ++++--- drivers/char/drm/sis_mm.c | 18 +++++++++--------- drivers/char/drm/tdfx_drv.h | 3 ++- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/drivers/char/drm/sis_drm.h b/drivers/char/drm/sis_drm.h index 8f273da76ddb..30f7b3827466 100644 --- a/drivers/char/drm/sis_drm.h +++ b/drivers/char/drm/sis_drm.h @@ -1,3 +1,28 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- */ +/* + * Copyright 2005 Eric Anholt + * All Rights Reserved. + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + */ #ifndef __SIS_DRM_H__ #define __SIS_DRM_H__ diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h index b1fddad83a93..e218e5269503 100644 --- a/drivers/char/drm/sis_drv.h +++ b/drivers/char/drm/sis_drv.h @@ -1,5 +1,5 @@ -/* sis_drv.h -- Private header for sis driver -*- linux-c -*- - * +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- */ +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h index da850b4f5440..94f2b4728b63 100644 --- a/drivers/char/drm/sis_ds.h +++ b/drivers/char/drm/sis_ds.h @@ -1,6 +1,7 @@ -/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- +/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw - * + */ +/* * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. * All rights reserved. * @@ -35,7 +36,7 @@ #define SET_SIZE 5000 -typedef unsigned int ITEM_TYPE; +typedef unsigned long ITEM_TYPE; typedef struct { ITEM_TYPE val; diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index f0488db001a4..6774d2fe3452 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c @@ -86,7 +86,7 @@ static int sis_fb_alloc(DRM_IOCTL_ARGS) { drm_sis_mem_t fb; struct sis_memreq req; - drm_sis_mem_t __user *argp = (void __user *)data; + drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data; int retval = 0; DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb)); @@ -110,7 +110,7 @@ static int sis_fb_alloc(DRM_IOCTL_ARGS) DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb)); - DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset); + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); return retval; } @@ -127,9 +127,9 @@ static int sis_fb_free(DRM_IOCTL_ARGS) if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) retval = DRM_ERR(EINVAL); - sis_free((u32) fb.free); + sis_free(fb.free); - DRM_DEBUG("free fb, offset = %lu\n", fb.free); + DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free); return retval; } @@ -176,7 +176,7 @@ static int sis_fb_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_sis_private_t *dev_priv = dev->dev_private; - drm_sis_mem_t __user *argp = (void __user *)data; + drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data; drm_sis_mem_t fb; PMemBlock block; int retval = 0; @@ -267,7 +267,7 @@ static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_sis_private_t *dev_priv = dev->dev_private; - drm_sis_mem_t __user *argp = (void __user *)data; + drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data; drm_sis_mem_t agp; PMemBlock block; int retval = 0; @@ -367,7 +367,7 @@ int sis_final_context(struct drm_device *dev, int context) if (i < MAX_CONTEXT) { set_t *set; - unsigned int item; + ITEM_TYPE item; int retval; DRM_DEBUG("find socket %d, context = %d\n", i, context); @@ -376,7 +376,7 @@ int sis_final_context(struct drm_device *dev, int context) set = global_ppriv[i].sets[0]; retval = setFirst(set, &item); while (retval) { - DRM_DEBUG("free video memory 0x%x\n", item); + DRM_DEBUG("free video memory 0x%lx\n", item); #if defined(__linux__) && defined(CONFIG_FB_SIS) sis_free(item); #else @@ -390,7 +390,7 @@ int sis_final_context(struct drm_device *dev, int context) set = global_ppriv[i].sets[1]; retval = setFirst(set, &item); while (retval) { - DRM_DEBUG("free agp memory 0x%x\n", item); + DRM_DEBUG("free agp memory 0x%lx\n", item); mmFreeMem((PMemBlock) item); retval = setNext(set, &item); } diff --git a/drivers/char/drm/tdfx_drv.h b/drivers/char/drm/tdfx_drv.h index 857be434379f..84204ec1b046 100644 --- a/drivers/char/drm/tdfx_drv.h +++ b/drivers/char/drm/tdfx_drv.h @@ -1,6 +1,7 @@ /* tdfx.h -- 3dfx DRM template customization -*- linux-c -*- * Created: Wed Feb 14 12:32:32 2001 by gareth@valinux.com - * + */ +/* * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * -- cgit v1.2.3 From 3528af1b189d0fbb4c7a3f121f46d9987b9af5b6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 16:11:44 +1100 Subject: drm: fix a LOR issue on FreeBSD for savage driver Correct a LOR issue on FreeBSD by allocating temporary space and doing a single DRM_COPY_FROM_USER rather than DRM_VERIFYAREA_READ followed by tons of DRM_COPY_FROM_USER_UNCHECKED. I don't like the look of the temporary space allocation, but I like the simplification in the rest of the file. Tested with glxgears, tuxracer, and q3 on a savage4. From: Eric Anholt Signed-off-by: Dave Airlie --- drivers/char/drm/savage_drv.h | 23 +-- drivers/char/drm/savage_state.c | 324 ++++++++++++++++++++-------------------- 2 files changed, 171 insertions(+), 176 deletions(-) diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h index 2f73558fb9cf..dd46cb85439c 100644 --- a/drivers/char/drm/savage_drv.h +++ b/drivers/char/drm/savage_drv.h @@ -1,5 +1,5 @@ -/* savage_drv.h -- Private header for the savage driver - * +/* savage_drv.h -- Private header for the savage driver */ +/* * Copyright 2004 Felix Kuehling * All Rights Reserved. * @@ -192,7 +192,7 @@ typedef struct drm_savage_private { /* Err, there is a macro wait_event in include/linux/wait.h. * Avoid unwanted macro expansion. */ void (*emit_clip_rect) (struct drm_savage_private * dev_priv, - drm_clip_rect_t * pbox); + const drm_clip_rect_t * pbox); void (*dma_flush) (struct drm_savage_private * dev_priv); } drm_savage_private_t; @@ -217,9 +217,9 @@ extern void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp); /* state functions */ extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, - drm_clip_rect_t * pbox); + const drm_clip_rect_t * pbox); extern void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, - drm_clip_rect_t * pbox); + const drm_clip_rect_t * pbox); #define SAVAGE_FB_SIZE_S3 0x01000000 /* 16MB */ #define SAVAGE_FB_SIZE_S4 0x02000000 /* 32MB */ @@ -502,15 +502,6 @@ extern void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, #define BCI_WRITE( val ) *bci_ptr++ = (uint32_t)(val) -#define BCI_COPY_FROM_USER(src,n) do { \ - unsigned int i; \ - for (i = 0; i < n; ++i) { \ - uint32_t val; \ - DRM_GET_USER_UNCHECKED(val, &((uint32_t*)(src))[i]); \ - BCI_WRITE(val); \ - } \ -} while(0) - /* * command DMA support */ @@ -536,8 +527,8 @@ extern void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, #define DMA_WRITE( val ) *dma_ptr++ = (uint32_t)(val) -#define DMA_COPY_FROM_USER(src,n) do { \ - DRM_COPY_FROM_USER_UNCHECKED(dma_ptr, (src), (n)*4); \ +#define DMA_COPY(src, n) do { \ + memcpy(dma_ptr, (src), (n)*4); \ dma_ptr += n; \ } while(0) diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c index e87a5d59b99c..ef2581d16146 100644 --- a/drivers/char/drm/savage_state.c +++ b/drivers/char/drm/savage_state.c @@ -27,7 +27,7 @@ #include "savage_drv.h" void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, - drm_clip_rect_t * pbox) + const drm_clip_rect_t * pbox) { uint32_t scstart = dev_priv->state.s3d.new_scstart; uint32_t scend = dev_priv->state.s3d.new_scend; @@ -53,7 +53,7 @@ void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, } void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, - drm_clip_rect_t * pbox) + const drm_clip_rect_t * pbox) { uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0; uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1; @@ -115,18 +115,19 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit, #define SAVE_STATE(reg,where) \ if(start <= reg && start+count > reg) \ - DRM_GET_USER_UNCHECKED(dev_priv->state.where, ®s[reg-start]) + dev_priv->state.where = regs[reg - start] #define SAVE_STATE_MASK(reg,where,mask) do { \ if(start <= reg && start+count > reg) { \ uint32_t tmp; \ - DRM_GET_USER_UNCHECKED(tmp, ®s[reg-start]); \ + tmp = regs[reg - start]; \ dev_priv->state.where = (tmp & (mask)) | \ (dev_priv->state.where & ~(mask)); \ } \ } while (0) + static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, unsigned int start, unsigned int count, - const uint32_t __user * regs) + const uint32_t *regs) { if (start < SAVAGE_TEXPALADDR_S3D || start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { @@ -148,8 +149,7 @@ static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr); if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK) return savage_verify_texaddr(dev_priv, 0, - dev_priv->state.s3d. - texaddr); + dev_priv->state.s3d.texaddr); } return 0; @@ -157,7 +157,7 @@ static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, static int savage_verify_state_s4(drm_savage_private_t * dev_priv, unsigned int start, unsigned int count, - const uint32_t __user * regs) + const uint32_t *regs) { int ret = 0; @@ -174,19 +174,18 @@ static int savage_verify_state_s4(drm_savage_private_t * dev_priv, ~SAVAGE_SCISSOR_MASK_S4); /* if any texture regs were changed ... */ - if (start <= SAVAGE_TEXDESCR_S4 && start + count > SAVAGE_TEXPALADDR_S4) { + if (start <= SAVAGE_TEXDESCR_S4 && + start + count > SAVAGE_TEXPALADDR_S4) { /* ... check texture state */ SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr); SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0); SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1); if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK) - ret |= - savage_verify_texaddr(dev_priv, 0, - dev_priv->state.s4.texaddr0); + ret |= savage_verify_texaddr(dev_priv, 0, + dev_priv->state.s4.texaddr0); if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK) - ret |= - savage_verify_texaddr(dev_priv, 1, - dev_priv->state.s4.texaddr1); + ret |= savage_verify_texaddr(dev_priv, 1, + dev_priv->state.s4.texaddr1); } return ret; @@ -197,7 +196,7 @@ static int savage_verify_state_s4(drm_savage_private_t * dev_priv, static int savage_dispatch_state(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, - const uint32_t __user * regs) + const uint32_t *regs) { unsigned int count = cmd_header->state.count; unsigned int start = cmd_header->state.start; @@ -209,9 +208,6 @@ static int savage_dispatch_state(drm_savage_private_t * dev_priv, if (!count) return 0; - if (DRM_VERIFYAREA_READ(regs, count * 4)) - return DRM_ERR(EFAULT); - if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { ret = savage_verify_state_s3d(dev_priv, start, count, regs); if (ret != 0) @@ -236,8 +232,8 @@ static int savage_dispatch_state(drm_savage_private_t * dev_priv, /* scissor regs are emitted in savage_dispatch_draw */ if (start < SAVAGE_DRAWCTRL0_S4) { if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) - count2 = - count - (SAVAGE_DRAWCTRL1_S4 + 1 - start); + count2 = count - + (SAVAGE_DRAWCTRL1_S4 + 1 - start); if (start + count > SAVAGE_DRAWCTRL0_S4) count = SAVAGE_DRAWCTRL0_S4 - start; } else if (start <= SAVAGE_DRAWCTRL1_S4) { @@ -263,7 +259,7 @@ static int savage_dispatch_state(drm_savage_private_t * dev_priv, while (count > 0) { unsigned int n = count < 255 ? count : 255; DMA_SET_REGISTERS(start, n); - DMA_COPY_FROM_USER(regs, n); + DMA_COPY(regs, n); count -= n; start += n; regs += n; @@ -421,8 +417,8 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, - const uint32_t __user * vtxbuf, - unsigned int vb_size, unsigned int vb_stride) + const uint32_t *vtxbuf, unsigned int vb_size, + unsigned int vb_stride) { unsigned char reorder = 0; unsigned int prim = cmd_header->prim.prim; @@ -507,8 +503,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, for (i = start; i < start + count; ++i) { unsigned int j = i + reorder[i % 3]; - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * j], - vtx_size); + DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); } DMA_COMMIT(); @@ -517,13 +512,12 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, DMA_DRAW_PRIMITIVE(count, prim, skip); if (vb_stride == vtx_size) { - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * start], - vtx_size * count); + DMA_COPY(&vtxbuf[vb_stride * start], + vtx_size * count); } else { for (i = start; i < start + count; ++i) { - DMA_COPY_FROM_USER(&vtxbuf - [vb_stride * i], - vtx_size); + DMA_COPY(&vtxbuf [vb_stride * i], + vtx_size); } } @@ -541,7 +535,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, - const uint16_t __user * usr_idx, + const uint16_t *idx, const drm_buf_t * dmabuf) { unsigned char reorder = 0; @@ -628,11 +622,8 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, while (n != 0) { /* Can emit up to 255 indices (85 triangles) at once. */ unsigned int count = n > 255 ? 255 : n; - /* Is it ok to allocate 510 bytes on the stack in an ioctl? */ - uint16_t idx[255]; - /* Copy and check indices */ - DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count * 2); + /* check indices */ for (i = 0; i < count; ++i) { if (idx[i] > dmabuf->total / 32) { DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", @@ -652,8 +643,8 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, for (i = 1; i + 1 < count; i += 2) BCI_WRITE(idx[i + reorder[i % 3]] | - (idx[i + 1 + reorder[(i + 1) % 3]] << - 16)); + (idx[i + 1 + + reorder[(i + 1) % 3]] << 16)); if (i < count) BCI_WRITE(idx[i + reorder[i % 3]]); } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { @@ -674,7 +665,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, BCI_WRITE(idx[i]); } - usr_idx += count; + idx += count; n -= count; prim |= BCI_CMD_DRAW_CONT; @@ -685,8 +676,8 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, - const uint16_t __user * usr_idx, - const uint32_t __user * vtxbuf, + const uint16_t *idx, + const uint32_t *vtxbuf, unsigned int vb_size, unsigned int vb_stride) { unsigned char reorder = 0; @@ -751,11 +742,8 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, while (n != 0) { /* Can emit up to 255 vertices (85 triangles) at once. */ unsigned int count = n > 255 ? 255 : n; - /* Is it ok to allocate 510 bytes on the stack in an ioctl? */ - uint16_t idx[255]; - - /* Copy and check indices */ - DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count * 2); + + /* Check indices */ for (i = 0; i < count; ++i) { if (idx[i] > vb_size / (vb_stride * 4)) { DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", @@ -775,8 +763,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, for (i = 0; i < count; ++i) { unsigned int j = idx[i + reorder[i % 3]]; - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * j], - vtx_size); + DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); } DMA_COMMIT(); @@ -786,14 +773,13 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, for (i = 0; i < count; ++i) { unsigned int j = idx[i]; - DMA_COPY_FROM_USER(&vtxbuf[vb_stride * j], - vtx_size); + DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); } DMA_COMMIT(); } - usr_idx += count; + idx += count; n -= count; prim |= BCI_CMD_DRAW_CONT; @@ -804,11 +790,11 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, static int savage_dispatch_clear(drm_savage_private_t * dev_priv, const drm_savage_cmd_header_t * cmd_header, - const drm_savage_cmd_header_t __user * data, + const drm_savage_cmd_header_t *data, unsigned int nbox, - const drm_clip_rect_t __user * usr_boxes) + const drm_clip_rect_t *boxes) { - unsigned int flags = cmd_header->clear0.flags, mask, value; + unsigned int flags = cmd_header->clear0.flags; unsigned int clear_cmd; unsigned int i, nbufs; DMA_LOCALS; @@ -816,9 +802,6 @@ static int savage_dispatch_clear(drm_savage_private_t * dev_priv, if (nbox == 0) return 0; - DRM_GET_USER_UNCHECKED(mask, &data->clear1.mask); - DRM_GET_USER_UNCHECKED(value, &data->clear1.value); - clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW; BCI_CMD_SET_ROP(clear_cmd, 0xCC); @@ -828,21 +811,19 @@ static int savage_dispatch_clear(drm_savage_private_t * dev_priv, if (nbufs == 0) return 0; - if (mask != 0xffffffff) { + if (data->clear1.mask != 0xffffffff) { /* set mask */ BEGIN_DMA(2); DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); - DMA_WRITE(mask); + DMA_WRITE(data->clear1.mask); DMA_COMMIT(); } for (i = 0; i < nbox; ++i) { - drm_clip_rect_t box; unsigned int x, y, w, h; unsigned int buf; - DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box)); - x = box.x1, y = box.y1; - w = box.x2 - box.x1; - h = box.y2 - box.y1; + x = boxes[i].x1, y = boxes[i].y1; + w = boxes[i].x2 - boxes[i].x1; + h = boxes[i].y2 - boxes[i].y1; BEGIN_DMA(nbufs * 6); for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) { if (!(flags & buf)) @@ -862,13 +843,13 @@ static int savage_dispatch_clear(drm_savage_private_t * dev_priv, DMA_WRITE(dev_priv->depth_bd); break; } - DMA_WRITE(value); + DMA_WRITE(data->clear1.value); DMA_WRITE(BCI_X_Y(x, y)); DMA_WRITE(BCI_W_H(w, h)); } DMA_COMMIT(); } - if (mask != 0xffffffff) { + if (data->clear1.mask != 0xffffffff) { /* reset mask */ BEGIN_DMA(2); DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); @@ -880,8 +861,7 @@ static int savage_dispatch_clear(drm_savage_private_t * dev_priv, } static int savage_dispatch_swap(drm_savage_private_t * dev_priv, - unsigned int nbox, - const drm_clip_rect_t __user * usr_boxes) + unsigned int nbox, const drm_clip_rect_t *boxes) { unsigned int swap_cmd; unsigned int i; @@ -895,16 +875,14 @@ static int savage_dispatch_swap(drm_savage_private_t * dev_priv, BCI_CMD_SET_ROP(swap_cmd, 0xCC); for (i = 0; i < nbox; ++i) { - drm_clip_rect_t box; - DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box)); - BEGIN_DMA(6); DMA_WRITE(swap_cmd); DMA_WRITE(dev_priv->back_offset); DMA_WRITE(dev_priv->back_bd); - DMA_WRITE(BCI_X_Y(box.x1, box.y1)); - DMA_WRITE(BCI_X_Y(box.x1, box.y1)); - DMA_WRITE(BCI_W_H(box.x2 - box.x1, box.y2 - box.y1)); + DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); + DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); + DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1, + boxes[i].y2 - boxes[i].y1)); DMA_COMMIT(); } @@ -912,68 +890,52 @@ static int savage_dispatch_swap(drm_savage_private_t * dev_priv, } static int savage_dispatch_draw(drm_savage_private_t * dev_priv, - const drm_savage_cmd_header_t __user * start, - const drm_savage_cmd_header_t __user * end, + const drm_savage_cmd_header_t *start, + const drm_savage_cmd_header_t *end, const drm_buf_t * dmabuf, - const unsigned int __user * usr_vtxbuf, + const unsigned int *vtxbuf, unsigned int vb_size, unsigned int vb_stride, unsigned int nbox, - const drm_clip_rect_t __user * usr_boxes) + const drm_clip_rect_t *boxes) { unsigned int i, j; int ret; for (i = 0; i < nbox; ++i) { - drm_clip_rect_t box; - const drm_savage_cmd_header_t __user *usr_cmdbuf; - DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box)); - dev_priv->emit_clip_rect(dev_priv, &box); + const drm_savage_cmd_header_t *cmdbuf; + dev_priv->emit_clip_rect(dev_priv, &boxes[i]); - usr_cmdbuf = start; - while (usr_cmdbuf < end) { + cmdbuf = start; + while (cmdbuf < end) { drm_savage_cmd_header_t cmd_header; - DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf, - sizeof(cmd_header)); - usr_cmdbuf++; + cmd_header = *cmdbuf; + cmdbuf++; switch (cmd_header.cmd.cmd) { case SAVAGE_CMD_DMA_PRIM: - ret = - savage_dispatch_dma_prim(dev_priv, - &cmd_header, - dmabuf); + ret = savage_dispatch_dma_prim( + dev_priv, &cmd_header, dmabuf); break; case SAVAGE_CMD_VB_PRIM: - ret = - savage_dispatch_vb_prim(dev_priv, - &cmd_header, - (const uint32_t - __user *) - usr_vtxbuf, vb_size, - vb_stride); + ret = savage_dispatch_vb_prim( + dev_priv, &cmd_header, + vtxbuf, vb_size, vb_stride); break; case SAVAGE_CMD_DMA_IDX: j = (cmd_header.idx.count + 3) / 4; /* j was check in savage_bci_cmdbuf */ - ret = - savage_dispatch_dma_idx(dev_priv, - &cmd_header, - (const uint16_t - __user *) - usr_cmdbuf, dmabuf); - usr_cmdbuf += j; + ret = savage_dispatch_dma_idx(dev_priv, + &cmd_header, (const uint16_t *)cmdbuf, + dmabuf); + cmdbuf += j; break; case SAVAGE_CMD_VB_IDX: j = (cmd_header.idx.count + 3) / 4; /* j was check in savage_bci_cmdbuf */ - ret = - savage_dispatch_vb_idx(dev_priv, - &cmd_header, - (const uint16_t - __user *)usr_cmdbuf, - (const uint32_t - __user *)usr_vtxbuf, - vb_size, vb_stride); - usr_cmdbuf += j; + ret = savage_dispatch_vb_idx(dev_priv, + &cmd_header, (const uint16_t *)cmdbuf, + (const uint32_t *)vtxbuf, vb_size, + vb_stride); + cmdbuf += j; break; default: /* What's the best return code? EFAULT? */ @@ -998,10 +960,10 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) drm_device_dma_t *dma = dev->dma; drm_buf_t *dmabuf; drm_savage_cmdbuf_t cmdbuf; - drm_savage_cmd_header_t __user *usr_cmdbuf; - drm_savage_cmd_header_t __user *first_draw_cmd; - unsigned int __user *usr_vtxbuf; - drm_clip_rect_t __user *usr_boxes; + drm_savage_cmd_header_t *kcmd_addr = NULL; + drm_savage_cmd_header_t *first_draw_cmd; + unsigned int *kvb_addr = NULL; + drm_clip_rect_t *kbox_addr = NULL; unsigned int i, j; int ret = 0; @@ -1024,15 +986,53 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) dmabuf = NULL; } - usr_cmdbuf = (drm_savage_cmd_header_t __user *) cmdbuf.cmd_addr; - usr_vtxbuf = (unsigned int __user *)cmdbuf.vb_addr; - usr_boxes = (drm_clip_rect_t __user *) cmdbuf.box_addr; - if ((cmdbuf.size && DRM_VERIFYAREA_READ(usr_cmdbuf, cmdbuf.size * 8)) || - (cmdbuf.vb_size && DRM_VERIFYAREA_READ(usr_vtxbuf, cmdbuf.vb_size)) - || (cmdbuf.nbox - && DRM_VERIFYAREA_READ(usr_boxes, - cmdbuf.nbox * sizeof(drm_clip_rect_t)))) - return DRM_ERR(EFAULT); + /* Copy the user buffers into kernel temporary areas. This hasn't been + * a performance loss compared to VERIFYAREA_READ/ + * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct + * for locking on FreeBSD. + */ + if (cmdbuf.size) { + kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER); + if (kcmd_addr == NULL) + return ENOMEM; + + if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr, + cmdbuf.size * 8)) + { + drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); + return DRM_ERR(EFAULT); + } + cmdbuf.cmd_addr = kcmd_addr; + } + if (cmdbuf.vb_size) { + kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER); + if (kvb_addr == NULL) { + ret = DRM_ERR(ENOMEM); + goto done; + } + + if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr, + cmdbuf.vb_size)) { + ret = DRM_ERR(EFAULT); + goto done; + } + cmdbuf.vb_addr = kvb_addr; + } + if (cmdbuf.nbox) { + kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(drm_clip_rect_t), + DRM_MEM_DRIVER); + if (kbox_addr == NULL) { + ret = DRM_ERR(ENOMEM); + goto done; + } + + if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr, + cmdbuf.nbox * sizeof(drm_clip_rect_t))) { + ret = DRM_ERR(EFAULT); + goto done; + } + cmdbuf.box_addr = kbox_addr; + } /* Make sure writes to DMA buffers are finished before sending * DMA commands to the graphics hardware. */ @@ -1046,9 +1046,8 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) first_draw_cmd = NULL; while (i < cmdbuf.size) { drm_savage_cmd_header_t cmd_header; - DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf, - sizeof(cmd_header)); - usr_cmdbuf++; + cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr; + cmdbuf.cmd_addr++; i++; /* Group drawing commands with same state to minimize @@ -1068,21 +1067,18 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) case SAVAGE_CMD_DMA_PRIM: case SAVAGE_CMD_VB_PRIM: if (!first_draw_cmd) - first_draw_cmd = usr_cmdbuf - 1; - usr_cmdbuf += j; + first_draw_cmd = cmdbuf.cmd_addr - 1; + cmdbuf.cmd_addr += j; i += j; break; default: if (first_draw_cmd) { - ret = - savage_dispatch_draw(dev_priv, - first_draw_cmd, - usr_cmdbuf - 1, dmabuf, - usr_vtxbuf, - cmdbuf.vb_size, - cmdbuf.vb_stride, - cmdbuf.nbox, - usr_boxes); + ret = savage_dispatch_draw( + dev_priv, first_draw_cmd, + cmdbuf.cmd_addr - 1, + dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size, + cmdbuf.vb_stride, + cmdbuf.nbox, cmdbuf.box_addr); if (ret != 0) return ret; first_draw_cmd = NULL; @@ -1098,12 +1094,12 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) DRM_ERROR("command SAVAGE_CMD_STATE extends " "beyond end of command buffer\n"); DMA_FLUSH(); - return DRM_ERR(EINVAL); + ret = DRM_ERR(EINVAL); + goto done; } ret = savage_dispatch_state(dev_priv, &cmd_header, - (uint32_t __user *) - usr_cmdbuf); - usr_cmdbuf += j; + (const uint32_t *)cmdbuf.cmd_addr); + cmdbuf.cmd_addr += j; i += j; break; case SAVAGE_CMD_CLEAR: @@ -1111,39 +1107,40 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) DRM_ERROR("command SAVAGE_CMD_CLEAR extends " "beyond end of command buffer\n"); DMA_FLUSH(); - return DRM_ERR(EINVAL); + ret = DRM_ERR(EINVAL); + goto done; } ret = savage_dispatch_clear(dev_priv, &cmd_header, - usr_cmdbuf, - cmdbuf.nbox, usr_boxes); - usr_cmdbuf++; + cmdbuf.cmd_addr, + cmdbuf.nbox, cmdbuf.box_addr); + cmdbuf.cmd_addr++; i++; break; case SAVAGE_CMD_SWAP: - ret = savage_dispatch_swap(dev_priv, - cmdbuf.nbox, usr_boxes); + ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox, + cmdbuf.box_addr); break; default: DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd); DMA_FLUSH(); - return DRM_ERR(EINVAL); + ret = DRM_ERR(EINVAL); + goto done; } if (ret != 0) { DMA_FLUSH(); - return ret; + goto done; } } if (first_draw_cmd) { - ret = - savage_dispatch_draw(dev_priv, first_draw_cmd, usr_cmdbuf, - dmabuf, usr_vtxbuf, cmdbuf.vb_size, - cmdbuf.vb_stride, cmdbuf.nbox, - usr_boxes); + ret = savage_dispatch_draw ( + dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf, + cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride, + cmdbuf.nbox, cmdbuf.box_addr); if (ret != 0) { DMA_FLUSH(); - return ret; + goto done; } } @@ -1157,5 +1154,12 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS) savage_freelist_put(dev, dmabuf); } - return 0; +done: + /* If we didn't need to allocate them, these'll be NULL */ + drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER); + drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER); + drm_free(kbox_addr, cmdbuf.nbox * sizeof(drm_clip_rect_t), + DRM_MEM_DRIVER); + + return ret; } -- cgit v1.2.3 From 269dc51296f4e985741d2fd567e7be4e7a0a9f29 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 16:23:01 +1100 Subject: drm: bring savage inline with latest CVS apply some whitespace cleanup and add wrappers for MTRR for OS calls From: Eric Anholt + Dave Airlie Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 15 +++++++++++++++ drivers/char/drm/savage_bci.c | 29 ++++++++++++----------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 295de65b7088..a3ad85e05bd3 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -750,6 +750,21 @@ static inline int drm_core_has_MTRR(struct drm_device *dev) { return drm_core_check_feature(dev, DRIVER_USE_MTRR); } + +#define DRM_MTRR_WC MTRR_TYPE_WRCOMB + +static inline int drm_mtrr_add(unsigned long offset, unsigned long size, + unsigned int flags) +{ + return mtrr_add(offset, size, flags, 1); +} + +static inline int drm_mtrr_del(int handle, unsigned long offset, + unsigned long size, unsigned int flags) +{ + return mtrr_del(handle, offset, size); +} + #else #define drm_core_has_MTRR(dev) (0) #endif diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c index 00658621b2f6..0d426deeefec 100644 --- a/drivers/char/drm/savage_bci.c +++ b/drivers/char/drm/savage_bci.c @@ -584,21 +584,18 @@ int savage_driver_firstopen(drm_device_t *dev) dev_priv->mtrr[0].base = fb_base; dev_priv->mtrr[0].size = 0x01000000; dev_priv->mtrr[0].handle = - mtrr_add(dev_priv->mtrr[0].base, - dev_priv->mtrr[0].size, MTRR_TYPE_WRCOMB, - 1); + drm_mtrr_add(dev_priv->mtrr[0].base, + dev_priv->mtrr[0].size, DRM_MTRR_WC); dev_priv->mtrr[1].base = fb_base + 0x02000000; dev_priv->mtrr[1].size = 0x02000000; dev_priv->mtrr[1].handle = - mtrr_add(dev_priv->mtrr[1].base, - dev_priv->mtrr[1].size, MTRR_TYPE_WRCOMB, - 1); + drm_mtrr_add(dev_priv->mtrr[1].base, + dev_priv->mtrr[1].size, DRM_MTRR_WC); dev_priv->mtrr[2].base = fb_base + 0x04000000; dev_priv->mtrr[2].size = 0x04000000; dev_priv->mtrr[2].handle = - mtrr_add(dev_priv->mtrr[2].base, - dev_priv->mtrr[2].size, MTRR_TYPE_WRCOMB, - 1); + drm_mtrr_add(dev_priv->mtrr[2].base, + dev_priv->mtrr[2].size, DRM_MTRR_WC); } else { DRM_ERROR("strange pci_resource_len %08lx\n", drm_get_resource_len(dev, 0)); @@ -618,9 +615,8 @@ int savage_driver_firstopen(drm_device_t *dev) dev_priv->mtrr[0].base = fb_base; dev_priv->mtrr[0].size = 0x08000000; dev_priv->mtrr[0].handle = - mtrr_add(dev_priv->mtrr[0].base, - dev_priv->mtrr[0].size, MTRR_TYPE_WRCOMB, - 1); + drm_mtrr_add(dev_priv->mtrr[0].base, + dev_priv->mtrr[0].size, DRM_MTRR_WC); } else { DRM_ERROR("strange pci_resource_len %08lx\n", drm_get_resource_len(dev, 1)); @@ -664,9 +660,9 @@ void savage_driver_lastclose(drm_device_t *dev) for (i = 0; i < 3; ++i) if (dev_priv->mtrr[i].handle >= 0) - mtrr_del(dev_priv->mtrr[i].handle, + drm_mtrr_del(dev_priv->mtrr[i].handle, dev_priv->mtrr[i].base, - dev_priv->mtrr[i].size); + dev_priv->mtrr[i].size, DRM_MTRR_WC); } int savage_driver_unload(drm_device_t *dev) @@ -1008,8 +1004,7 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS) * DMA buffer management */ -static int savage_bci_get_buffers(DRMFILE filp, drm_device_t * dev, - drm_dma_t * d) +static int savage_bci_get_buffers(DRMFILE filp, drm_device_t *dev, drm_dma_t *d) { drm_buf_t *buf; int i; @@ -1071,7 +1066,7 @@ int savage_bci_buffers(DRM_IOCTL_ARGS) return ret; } -void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp) +void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp) { drm_device_dma_t *dma = dev->dma; drm_savage_private_t *dev_priv = dev->dev_private; -- cgit v1.2.3 From 0a406877e638a6f43ed4591bb08d528415d7d53a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 16:49:02 +1100 Subject: drm: remove old reclaim_buffers from ix0 drivers From: Dave Airlie Signed-off-by: Dave Airlie --- drivers/char/drm/i810_drv.c | 1 - drivers/char/drm/i830_drv.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c index e73b731c3be9..dfe6ad2b6a6e 100644 --- a/drivers/char/drm/i810_drv.c +++ b/drivers/char/drm/i810_drv.c @@ -53,7 +53,6 @@ static struct drm_driver driver = { .device_is_agp = i810_driver_device_is_agp, .reclaim_buffers_locked = i810_driver_reclaim_buffers_locked, .dma_quiescent = i810_driver_dma_quiescent, - .reclaim_buffers = i810_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, .ioctls = i810_ioctls, diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c index 49fd2816de95..722658188f5f 100644 --- a/drivers/char/drm/i830_drv.c +++ b/drivers/char/drm/i830_drv.c @@ -58,7 +58,6 @@ static struct drm_driver driver = { .device_is_agp = i830_driver_device_is_agp, .reclaim_buffers_locked = i830_driver_reclaim_buffers_locked, .dma_quiescent = i830_driver_dma_quiescent, - .reclaim_buffers = i830_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, #if USE_IRQS -- cgit v1.2.3 From f26c473cdf557ea6e8f267d34eee82d30473a363 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 17:18:39 +1100 Subject: drm: update PCIGART support from CVS In order to work on FreeBSD the gart needed to use a local mapping This patch moves the mainline to the new code and aligns some comment changes From: Eric Anholt Signed-off-by: Dave Airlie --- drivers/char/drm/ati_pcigart.c | 23 +++++++++++------------ drivers/char/drm/drmP.h | 3 ++- drivers/char/drm/r128_cce.c | 15 +++++++++------ drivers/char/drm/r128_drm.h | 4 ++-- drivers/char/drm/r128_drv.h | 4 ++-- drivers/char/drm/r128_irq.c | 4 ++-- drivers/char/drm/r128_state.c | 4 ++-- drivers/char/drm/radeon_cp.c | 24 +++++++++++++----------- 8 files changed, 43 insertions(+), 38 deletions(-) diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index efff0eec618c..5485382cadec 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c @@ -52,7 +52,7 @@ # define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -static unsigned long drm_ati_alloc_pcigart_table(void) +static void *drm_ati_alloc_pcigart_table(void) { unsigned long address; struct page *page; @@ -72,27 +72,26 @@ static unsigned long drm_ati_alloc_pcigart_table(void) } DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address); - return address; + return (void *)address; } -static void drm_ati_free_pcigart_table(unsigned long address) +static void drm_ati_free_pcigart_table(void *address) { struct page *page; int i; DRM_DEBUG("%s\n", __FUNCTION__); - page = virt_to_page(address); + page = virt_to_page((unsigned long)address); for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) { __put_page(page); ClearPageReserved(page); } - free_pages(address, ATI_PCIGART_TABLE_ORDER); + free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); } -int drm_ati_pcigart_cleanup(drm_device_t * dev, - drm_ati_pcigart_info * gart_info) +int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) { drm_sg_mem_t *entry = dev->sg; unsigned long pages; @@ -136,10 +135,10 @@ int drm_ati_pcigart_cleanup(drm_device_t * dev, EXPORT_SYMBOL(drm_ati_pcigart_cleanup); -int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info * gart_info) +int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) { drm_sg_mem_t *entry = dev->sg; - unsigned long address = 0; + void *address = NULL; unsigned long pages; u32 *pci_gart, page_base, bus_address = 0; int i, j, ret = 0; @@ -163,7 +162,7 @@ int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info * gart_info) goto done; } - bus_address = pci_map_single(dev->pdev, (void *)address, + bus_address = pci_map_single(dev->pdev, address, ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, PCI_DMA_TODEVICE); if (bus_address == 0) { @@ -176,7 +175,7 @@ int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info * gart_info) address = gart_info->addr; bus_address = gart_info->bus_addr; DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", - bus_address, address); + bus_address, (unsigned long)address); } pci_gart = (u32 *) address; @@ -195,7 +194,7 @@ int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info * gart_info) if (entry->busaddr[i] == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); drm_ati_pcigart_cleanup(dev, gart_info); - address = 0; + address = NULL; bus_address = 0; goto done; } diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index a3ad85e05bd3..43c49ad3069b 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -522,8 +522,9 @@ typedef struct drm_vbl_sig { typedef struct ati_pcigart_info { int gart_table_location; int is_pcie; - unsigned long addr; + void *addr; dma_addr_t bus_addr; + drm_local_map_t mapping; } drm_ati_pcigart_info; /** diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c index 7452753d4d01..db5a60450e68 100644 --- a/drivers/char/drm/r128_cce.c +++ b/drivers/char/drm/r128_cce.c @@ -1,6 +1,7 @@ -/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*- +/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*- * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com - * + */ +/* * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -559,7 +560,8 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init) if (dev_priv->is_pci) { #endif dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; - dev_priv->gart_info.addr = dev_priv->gart_info.bus_addr = 0; + dev_priv->gart_info.addr = NULL; + dev_priv->gart_info.bus_addr = 0; dev_priv->gart_info.is_pcie = 0; if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { DRM_ERROR("failed to init PCI GART!\n"); @@ -601,15 +603,16 @@ int r128_do_cleanup_cce(drm_device_t * dev) drm_core_ioremapfree(dev_priv->cce_ring, dev); if (dev_priv->ring_rptr != NULL) drm_core_ioremapfree(dev_priv->ring_rptr, dev); - if (dev->agp_buffer_map != NULL) + if (dev->agp_buffer_map != NULL) { drm_core_ioremapfree(dev->agp_buffer_map, dev); + dev->agp_buffer_map = NULL; + } } else #endif { if (dev_priv->gart_info.bus_addr) if (!drm_ati_pcigart_cleanup(dev, - &dev_priv-> - gart_info)) + &dev_priv->gart_info)) DRM_ERROR ("failed to cleanup PCI GART!\n"); } diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h index 5ddc03202411..5d835b006f55 100644 --- a/drivers/char/drm/r128_drm.h +++ b/drivers/char/drm/r128_drm.h @@ -1,7 +1,7 @@ /* r128_drm.h -- Public header for the r128 driver -*- linux-c -*- * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com - * - * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + */ +/* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. * diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index 9a779bad3da3..94abffb2cca5 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -1,7 +1,7 @@ /* r128_drv.h -- Private header for r128 driver -*- linux-c -*- * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + */ +/* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. * diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c index 27eb0e31bd3b..87f8ca2b0685 100644 --- a/drivers/char/drm/r128_irq.c +++ b/drivers/char/drm/r128_irq.c @@ -1,5 +1,5 @@ -/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*- - * +/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*- */ +/* * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * * The Weather Channel (TM) funded Tungsten Graphics to develop the diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 6aeeb4b62d03..caeecc2c36da 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -1,7 +1,7 @@ /* r128_state.c -- State support for r128 -*- linux-c -*- * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com - * - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + */ +/* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index dc3a15a1819a..eaa0e2b7c2f8 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -1,5 +1,5 @@ -/* radeon_cp.c -- CP support for Radeon -*- linux-c -*- - * +/* radeon_cp.c -- CP support for Radeon -*- linux-c -*- */ +/* * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Fremont, California. * All Rights Reserved. @@ -1561,25 +1561,28 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if (dev_priv->pcigart_offset) { dev_priv->gart_info.bus_addr = dev_priv->pcigart_offset + dev_priv->fb_location; + dev_priv->gart_info.mapping.offset = + dev_priv->gart_info.bus_addr; + dev_priv->gart_info.mapping.size = + RADEON_PCIGART_TABLE_SIZE; + + drm_core_ioremap(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = - (unsigned long)drm_ioremap(dev_priv->gart_info. - bus_addr, - RADEON_PCIGART_TABLE_SIZE, - dev); + dev_priv->gart_info.mapping.handle; dev_priv->gart_info.is_pcie = !!(dev_priv->flags & CHIP_IS_PCIE); dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; - DRM_DEBUG("Setting phys_pci_gart to %08lX %08lX\n", + DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", dev_priv->gart_info.addr, dev_priv->pcigart_offset); } else { dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; - dev_priv->gart_info.addr = - dev_priv->gart_info.bus_addr = 0; + dev_priv->gart_info.addr = NULL; + dev_priv->gart_info.bus_addr = 0; if (dev_priv->flags & CHIP_IS_PCIE) { DRM_ERROR ("Cannot use PCI Express without GART in FB memory\n"); @@ -1641,8 +1644,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) DRM_ERROR("failed to cleanup PCI GART!\n"); if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { - drm_ioremapfree((void *)dev_priv->gart_info.addr, - RADEON_PCIGART_TABLE_SIZE, dev); + drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = 0; } } -- cgit v1.2.3 From b5e9fc13dd0f25a2f422000c185f491bfd4f7335 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 19:23:44 +1100 Subject: drm: fix issue with contexts running out of RAM Signed-off-by: Dave Airlie --- drivers/char/drm/drm_context.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index bdd168d88f49..7a7bcef2aa84 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -432,6 +432,10 @@ int drm_addctx(struct inode *inode, struct file *filp, if (ctx.handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_ctor) + if (dev->driver->context_ctor(dev, ctx.handle)) { + DRM_DEBUG("Running out of ctxs or memory.\n"); + return -ENOMEM; + } dev->driver->context_ctor(dev, ctx.handle); } -- cgit v1.2.3 From 1e7d51902a8bd08e37113aaf182d12233b157151 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 19:25:35 +1100 Subject: drm: proper fix for drm_context Bad patch in last version Signed-off-by: Dave Airlie --- drivers/char/drm/drm_context.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index 7a7bcef2aa84..f84254526949 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -432,11 +432,10 @@ int drm_addctx(struct inode *inode, struct file *filp, if (ctx.handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_ctor) - if (dev->driver->context_ctor(dev, ctx.handle)) { + if (!dev->driver->context_ctor(dev, ctx.handle)) { DRM_DEBUG("Running out of ctxs or memory.\n"); return -ENOMEM; } - dev->driver->context_ctor(dev, ctx.handle); } ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST); -- cgit v1.2.3 From f0c408b564ddefa0959ada4e2c2248f4a57f1842 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 19:52:09 +1100 Subject: drm: update drm_memory_debug.h Update from DRM CVS for drm memory debug From: Jon Smirl Signed-off-by: Dave Airlie --- drivers/char/drm/drm_memory_debug.h | 269 ++++++++++++++++++------------------ 1 file changed, 134 insertions(+), 135 deletions(-) diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 4542353195bd..706b75251ea1 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -1,5 +1,5 @@ /** - * \file drm_memory.h + * \file drm_memory_debug.h * Memory management wrappers for DRM. * * \author Rickard E. (Rik) Faith @@ -43,42 +43,41 @@ typedef struct drm_mem_stats { unsigned long bytes_freed; } drm_mem_stats_t; -static DEFINE_SPINLOCK(DRM(mem_lock)); -static unsigned long DRM(ram_available) = 0; /* In pages */ -static unsigned long DRM(ram_used) = 0; -static drm_mem_stats_t DRM(mem_stats)[] = +static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; +static unsigned long drm_ram_available = 0; /* In pages */ +static unsigned long drm_ram_used = 0; +static drm_mem_stats_t drm_mem_stats[] = { - [DRM_MEM_DMA] = { - "dmabufs"},[DRM_MEM_SAREA] = { - "sareas"},[DRM_MEM_DRIVER] = { - "driver"},[DRM_MEM_MAGIC] = { - "magic"},[DRM_MEM_IOCTLS] = { - "ioctltab"},[DRM_MEM_MAPS] = { - "maplist"},[DRM_MEM_VMAS] = { - "vmalist"},[DRM_MEM_BUFS] = { - "buflist"},[DRM_MEM_SEGS] = { - "seglist"},[DRM_MEM_PAGES] = { - "pagelist"},[DRM_MEM_FILES] = { - "files"},[DRM_MEM_QUEUES] = { - "queues"},[DRM_MEM_CMDS] = { - "commands"},[DRM_MEM_MAPPINGS] = { - "mappings"},[DRM_MEM_BUFLISTS] = { - "buflists"},[DRM_MEM_AGPLISTS] = { - "agplist"},[DRM_MEM_SGLISTS] = { - "sglist"},[DRM_MEM_TOTALAGP] = { - "totalagp"},[DRM_MEM_BOUNDAGP] = { - "boundagp"},[DRM_MEM_CTXBITMAP] = { - "ctxbitmap"},[DRM_MEM_CTXLIST] = { - "ctxlist"},[DRM_MEM_STUB] = { - "stub"}, { - NULL, 0,} /* Last entry must be null */ + [DRM_MEM_DMA] = {"dmabufs"}, + [DRM_MEM_SAREA] = {"sareas"}, + [DRM_MEM_DRIVER] = {"driver"}, + [DRM_MEM_MAGIC] = {"magic"}, + [DRM_MEM_IOCTLS] = {"ioctltab"}, + [DRM_MEM_MAPS] = {"maplist"}, + [DRM_MEM_VMAS] = {"vmalist"}, + [DRM_MEM_BUFS] = {"buflist"}, + [DRM_MEM_SEGS] = {"seglist"}, + [DRM_MEM_PAGES] = {"pagelist"}, + [DRM_MEM_FILES] = {"files"}, + [DRM_MEM_QUEUES] = {"queues"}, + [DRM_MEM_CMDS] = {"commands"}, + [DRM_MEM_MAPPINGS] = {"mappings"}, + [DRM_MEM_BUFLISTS] = {"buflists"}, + [DRM_MEM_AGPLISTS] = {"agplist"}, + [DRM_MEM_SGLISTS] = {"sglist"}, + [DRM_MEM_TOTALAGP] = {"totalagp"}, + [DRM_MEM_BOUNDAGP] = {"boundagp"}, + [DRM_MEM_CTXBITMAP] = {"ctxbitmap"}, + [DRM_MEM_CTXLIST] = {"ctxlist"}, + [DRM_MEM_STUB] = {"stub"}, + {NULL, 0,} /* Last entry must be null */ }; -void DRM(mem_init) (void) { +void drm_mem_init (void) { drm_mem_stats_t *mem; struct sysinfo si; - for (mem = DRM(mem_stats); mem->name; ++mem) { + for (mem = drm_mem_stats; mem->name; ++mem) { mem->succeed_count = 0; mem->free_count = 0; mem->fail_count = 0; @@ -87,13 +86,13 @@ void DRM(mem_init) (void) { } si_meminfo(&si); - DRM(ram_available) = si.totalram; - DRM(ram_used) = 0; + drm_ram_available = si.totalram; + drm_ram_used = 0; } /* drm_mem_info is called whenever a process reads /dev/drm/mem. */ -static int DRM(_mem_info) (char *buf, char **start, off_t offset, +static int drm__mem_info (char *buf, char **start, off_t offset, int request, int *eof, void *data) { drm_mem_stats_t *pt; int len = 0; @@ -112,11 +111,11 @@ static int DRM(_mem_info) (char *buf, char **start, off_t offset, " | allocs bytes\n\n"); DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", "system", 0, 0, 0, - DRM(ram_available) << (PAGE_SHIFT - 10)); + drm_ram_available << (PAGE_SHIFT - 10)); DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", - "locked", 0, 0, 0, DRM(ram_used) >> 10); + "locked", 0, 0, 0, drm_ram_used >> 10); DRM_PROC_PRINT("\n"); - for (pt = DRM(mem_stats); pt->name; pt++) { + for (pt = drm_mem_stats; pt->name; pt++) { DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", pt->name, pt->succeed_count, @@ -135,17 +134,17 @@ static int DRM(_mem_info) (char *buf, char **start, off_t offset, return len - offset; } -int DRM(mem_info) (char *buf, char **start, off_t offset, +int drm_mem_info (char *buf, char **start, off_t offset, int len, int *eof, void *data) { int ret; - spin_lock(&DRM(mem_lock)); - ret = DRM(_mem_info) (buf, start, offset, len, eof, data); - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ret = drm__mem_info (buf, start, offset, len, eof, data); + spin_unlock(&drm_mem_lock); return ret; } -void *DRM(alloc) (size_t size, int area) { +void *drm_alloc (size_t size, int area) { void *pt; if (!size) { @@ -154,41 +153,41 @@ void *DRM(alloc) (size_t size, int area) { } if (!(pt = kmalloc(size, GFP_KERNEL))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].fail_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].fail_count; + spin_unlock(&drm_mem_lock); return NULL; } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].succeed_count; - DRM(mem_stats)[area].bytes_allocated += size; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_allocated += size; + spin_unlock(&drm_mem_lock); return pt; } -void *DRM(calloc) (size_t nmemb, size_t size, int area) { +void *drm_calloc (size_t nmemb, size_t size, int area) { void *addr; - addr = DRM(alloc) (nmemb * size, area); + addr = drm_alloc (nmemb * size, area); if (addr != NULL) memset((void *)addr, 0, size * nmemb); return addr; } -void *DRM(realloc) (void *oldpt, size_t oldsize, size_t size, int area) { +void *drm_realloc (void *oldpt, size_t oldsize, size_t size, int area) { void *pt; - if (!(pt = DRM(alloc) (size, area))) + if (!(pt = drm_alloc (size, area))) return NULL; if (oldpt && oldsize) { memcpy(pt, oldpt, oldsize); - DRM(free) (oldpt, oldsize, area); + drm_free (oldpt, oldsize, area); } return pt; } -void DRM(free) (void *pt, size_t size, int area) { +void drm_free (void *pt, size_t size, int area) { int alloc_count; int free_count; @@ -196,43 +195,43 @@ void DRM(free) (void *pt, size_t size, int area) { DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); else kfree(pt); - spin_lock(&DRM(mem_lock)); - DRM(mem_stats)[area].bytes_freed += size; - free_count = ++DRM(mem_stats)[area].free_count; - alloc_count = DRM(mem_stats)[area].succeed_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + drm_mem_stats[area].bytes_freed += size; + free_count = ++drm_mem_stats[area].free_count; + alloc_count = drm_mem_stats[area].succeed_count; + spin_unlock(&drm_mem_lock); if (free_count > alloc_count) { DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", free_count, alloc_count); } } -unsigned long DRM(alloc_pages) (int order, int area) { +unsigned long drm_alloc_pages (int order, int area) { unsigned long address; unsigned long bytes = PAGE_SIZE << order; unsigned long addr; unsigned int sz; - spin_lock(&DRM(mem_lock)); - if ((DRM(ram_used) >> PAGE_SHIFT) - > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) { - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + if ((drm_ram_used >> PAGE_SHIFT) + > (DRM_RAM_PERCENT * drm_ram_available) / 100) { + spin_unlock(&drm_mem_lock); return 0; } - spin_unlock(&DRM(mem_lock)); + spin_unlock(&drm_mem_lock); address = __get_free_pages(GFP_KERNEL, order); if (!address) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].fail_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].fail_count; + spin_unlock(&drm_mem_lock); return 0; } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].succeed_count; - DRM(mem_stats)[area].bytes_allocated += bytes; - DRM(ram_used) += bytes; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_allocated += bytes; + drm_ram_used += bytes; + spin_unlock(&drm_mem_lock); /* Zero outside the lock */ memset((void *)address, 0, bytes); @@ -246,7 +245,7 @@ unsigned long DRM(alloc_pages) (int order, int area) { return address; } -void DRM(free_pages) (unsigned long address, int order, int area) { +void drm_free_pages (unsigned long address, int order, int area) { unsigned long bytes = PAGE_SIZE << order; int alloc_count; int free_count; @@ -264,12 +263,12 @@ void DRM(free_pages) (unsigned long address, int order, int area) { free_pages(address, order); } - spin_lock(&DRM(mem_lock)); - free_count = ++DRM(mem_stats)[area].free_count; - alloc_count = DRM(mem_stats)[area].succeed_count; - DRM(mem_stats)[area].bytes_freed += bytes; - DRM(ram_used) -= bytes; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[area].free_count; + alloc_count = drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_freed += bytes; + drm_ram_used -= bytes; + spin_unlock(&drm_mem_lock); if (free_count > alloc_count) { DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", @@ -277,7 +276,7 @@ void DRM(free_pages) (unsigned long address, int order, int area) { } } -void *DRM(ioremap) (unsigned long offset, unsigned long size, +void *drm_ioremap (unsigned long offset, unsigned long size, drm_device_t * dev) { void *pt; @@ -288,19 +287,19 @@ void *DRM(ioremap) (unsigned long offset, unsigned long size, } if (!(pt = drm_ioremap(offset, size, dev))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&drm_mem_lock); return NULL; } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; - DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&drm_mem_lock); return pt; } -void *DRM(ioremap_nocache) (unsigned long offset, unsigned long size, +void *drm_ioremap_nocache (unsigned long offset, unsigned long size, drm_device_t * dev) { void *pt; @@ -311,19 +310,19 @@ void *DRM(ioremap_nocache) (unsigned long offset, unsigned long size, } if (!(pt = drm_ioremap_nocache(offset, size, dev))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&drm_mem_lock); return NULL; } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; - DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&drm_mem_lock); return pt; } -void DRM(ioremapfree) (void *pt, unsigned long size, drm_device_t * dev) { +void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) { int alloc_count; int free_count; @@ -333,11 +332,11 @@ void DRM(ioremapfree) (void *pt, unsigned long size, drm_device_t * dev) { else drm_ioremapfree(pt, size, dev); - spin_lock(&DRM(mem_lock)); - DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; - free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; - alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size; + free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count; + alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + spin_unlock(&drm_mem_lock); if (free_count > alloc_count) { DRM_MEM_ERROR(DRM_MEM_MAPPINGS, "Excess frees: %d frees, %d allocs\n", @@ -347,7 +346,7 @@ void DRM(ioremapfree) (void *pt, unsigned long size, drm_device_t * dev) { #if __OS_HAS_AGP -DRM_AGP_MEM *DRM(alloc_agp) (int pages, u32 type) { +DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) { DRM_AGP_MEM *handle; if (!pages) { @@ -355,21 +354,21 @@ DRM_AGP_MEM *DRM(alloc_agp) (int pages, u32 type) { return NULL; } - if ((handle = DRM(agp_allocate_memory) (pages, type))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_allocated + if ((handle = drm_agp_allocate_memory (pages, type))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated += pages << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); + spin_unlock(&drm_mem_lock); return handle; } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_TOTALAGP].fail_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count; + spin_unlock(&drm_mem_lock); return NULL; } -int DRM(free_agp) (DRM_AGP_MEM * handle, int pages) { +int drm_free_agp (DRM_AGP_MEM * handle, int pages) { int alloc_count; int free_count; int retval = -EINVAL; @@ -380,13 +379,13 @@ int DRM(free_agp) (DRM_AGP_MEM * handle, int pages) { return retval; } - if (DRM(agp_free_memory) (handle)) { - spin_lock(&DRM(mem_lock)); - free_count = ++DRM(mem_stats)[DRM_MEM_TOTALAGP].free_count; - alloc_count = DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_freed + if (drm_agp_free_memory (handle)) { + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count; + alloc_count = drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed += pages << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); + spin_unlock(&drm_mem_lock); if (free_count > alloc_count) { DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Excess frees: %d frees, %d allocs\n", @@ -397,7 +396,7 @@ int DRM(free_agp) (DRM_AGP_MEM * handle, int pages) { return retval; } -int DRM(bind_agp) (DRM_AGP_MEM * handle, unsigned int start) { +int drm_bind_agp (DRM_AGP_MEM * handle, unsigned int start) { int retcode = -EINVAL; if (!handle) { @@ -406,21 +405,21 @@ int DRM(bind_agp) (DRM_AGP_MEM * handle, unsigned int start) { return retcode; } - if (!(retcode = DRM(agp_bind_memory) (handle, start))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_allocated + if (!(retcode = drm_agp_bind_memory (handle, start))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated += handle->page_count << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); + spin_unlock(&drm_mem_lock); return retcode; } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].fail_count; - spin_unlock(&DRM(mem_lock)); + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count; + spin_unlock(&drm_mem_lock); return retcode; } -int DRM(unbind_agp) (DRM_AGP_MEM * handle) { +int drm_unbind_agp (DRM_AGP_MEM * handle) { int alloc_count; int free_count; int retcode = -EINVAL; @@ -431,14 +430,14 @@ int DRM(unbind_agp) (DRM_AGP_MEM * handle) { return retcode; } - if ((retcode = DRM(agp_unbind_memory) (handle))) + if ((retcode = drm_agp_unbind_memory (handle))) return retcode; - spin_lock(&DRM(mem_lock)); - free_count = ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].free_count; - alloc_count = DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_freed + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count; + alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed += handle->page_count << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); + spin_unlock(&drm_mem_lock); if (free_count > alloc_count) { DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, "Excess frees: %d frees, %d allocs\n", -- cgit v1.2.3 From 0d6aa60b4ac9689b750e35cd66f5d7c053aff0f4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 20:14:23 +1100 Subject: drm: update to i915 1.3.0 Add support for vblank ioctls to i915 driver From: Dave Airlie Signed-off-by: Dave Airlie --- drivers/char/drm/i915_dma.c | 12 +++++++----- drivers/char/drm/i915_drm.h | 6 +++--- drivers/char/drm/i915_drv.c | 7 ++++--- drivers/char/drm/i915_drv.h | 39 +++++++++++++++++++++--------------- drivers/char/drm/i915_irq.c | 48 ++++++++++++++++++++++++++++++++++++--------- drivers/char/drm/i915_mem.c | 5 ++--- 6 files changed, 78 insertions(+), 39 deletions(-) diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 6cc3584e367f..9140703da1ba 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -1,7 +1,6 @@ /* i915_dma.c -- DMA support for the I915 -*- linux-c -*- */ -/************************************************************************** - * +/* * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * @@ -25,7 +24,7 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - **************************************************************************/ + */ #include "drmP.h" #include "drm.h" @@ -196,7 +195,7 @@ static int i915_initialize(drm_device_t * dev, return 0; } -static int i915_resume(drm_device_t * dev) +static int i915_dma_resume(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -253,7 +252,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS) retcode = i915_dma_cleanup(dev); break; case I915_RESUME_DMA: - retcode = i915_resume(dev); + retcode = i915_dma_resume(dev); break; default: retcode = -EINVAL; @@ -654,6 +653,9 @@ static int i915_getparam(DRM_IOCTL_ARGS) case I915_PARAM_ALLOW_BATCHBUFFER: value = dev_priv->allow_batchbuffer ? 1 : 0; break; + case I915_PARAM_LAST_DISPATCH: + value = READ_BREADCRUMB(dev_priv); + break; default: DRM_ERROR("Unkown parameter %d\n", param.param); return DRM_ERR(EINVAL); diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 23e027d29080..77412ddac007 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h @@ -1,5 +1,4 @@ -/************************************************************************** - * +/* * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * @@ -23,7 +22,7 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - **************************************************************************/ + */ #ifndef _I915_DRM_H_ #define _I915_DRM_H_ @@ -152,6 +151,7 @@ typedef struct drm_i915_irq_wait { */ #define I915_PARAM_IRQ_ACTIVE 1 #define I915_PARAM_ALLOW_BATCHBUFFER 2 +#define I915_PARAM_LAST_DISPATCH 3 typedef struct drm_i915_getparam { int param; diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index e88d32d286f5..8e2e6095c4b3 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -1,6 +1,6 @@ /* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- */ -/************************************************************************** +/* * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -25,7 +25,7 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - **************************************************************************/ + */ #include "drmP.h" #include "drm.h" @@ -44,11 +44,12 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, .load = i915_driver_load, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, + .vblank_wait = i915_driver_vblank_wait, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index cd4f5227d0ea..c6c71b45f101 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -1,6 +1,6 @@ /* i915_drv.h -- Private header for the I915 driver -*- linux-c -*- */ -/************************************************************************** +/* * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -25,7 +25,7 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - **************************************************************************/ + */ #ifndef _I915_DRV_H_ #define _I915_DRV_H_ @@ -37,21 +37,18 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20040405" +#define DRIVER_DATE "20051209" /* Interface history: * * 1.1: Original. + * 1.2: Add Power Management + * 1.3: Add vblank support */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 1 +#define DRIVER_MINOR 3 #define DRIVER_PATCHLEVEL 0 -/* We use our own dma mechanisms, not the drm template code. However, - * the shared IRQ code is useful to us: - */ -#define __HAVE_PM 1 - typedef struct _drm_i915_ring_buffer { int tail_mask; unsigned long Start; @@ -97,6 +94,7 @@ typedef struct drm_i915_private { int tex_lru_log_granularity; int allow_batchbuffer; struct mem_block *agp_heap; + unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -108,11 +106,14 @@ extern int i915_driver_load(struct drm_device *, unsigned long flags); extern void i915_driver_lastclose(drm_device_t * dev); extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); +extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); /* i915_irq.c */ extern int i915_irq_emit(DRM_IOCTL_ARGS); extern int i915_irq_wait(DRM_IOCTL_ARGS); +extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(drm_device_t * dev); extern void i915_driver_irq_postinstall(drm_device_t * dev); @@ -126,13 +127,10 @@ extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); -extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg); - -#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) -#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val) -#define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) -#define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val) +#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) +#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) +#define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) +#define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, (reg), (val)) #define I915_VERBOSE 0 @@ -196,6 +194,13 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define PPCR 0x61204 #define PPCR_ON (1<<0) +#define DVOB 0x61140 +#define DVOB_ON (1<<31) +#define DVOC 0x61160 +#define DVOC_ON (1<<31) +#define LVDS 0x61180 +#define LVDS_ON (1<<31) + #define ADPA 0x61100 #define ADPA_DPMS_MASK (~(3<<10)) #define ADPA_DPMS_ON (0<<10) @@ -259,4 +264,6 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) +#define READ_BREADCRUMB(dev_priv) (((u32 *)(dev_priv->hw_status_page))[5]) + #endif diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 4fa448ee846b..a1381c61aa63 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -1,7 +1,6 @@ -/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- +/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- */ -/************************************************************************** - * +/* * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * @@ -25,16 +24,18 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - **************************************************************************/ + */ #include "drmP.h" #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" -#define USER_INT_FLAG 0x2 +#define USER_INT_FLAG (1<<1) +#define VSYNC_PIPEB_FLAG (1<<5) +#define VSYNC_PIPEA_FLAG (1<<7) + #define MAX_NOPID ((u32)~0) -#define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { @@ -43,7 +44,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) u16 temp; temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= USER_INT_FLAG; + temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG); DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); @@ -51,7 +52,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - DRM_WAKEUP(&dev_priv->irq_queue); + + if (temp & USER_INT_FLAG) + DRM_WAKEUP(&dev_priv->irq_queue); + + if (temp & VSYNC_PIPEA_FLAG) { + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); + } return IRQ_HANDLED; } @@ -102,6 +111,27 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return ret; } +int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned int cur_vblank; + int ret = 0; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(&dev->vbl_received)) + - *sequence) <= (1<<23))); + + *sequence = cur_vblank; + + return ret; +} + + /* Needs the lock as it touches the ring. */ int i915_irq_emit(DRM_IOCTL_ARGS) @@ -165,7 +195,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG); + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | VSYNC_PIPEA_FLAG); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c index 13176d136a99..ba87ff17ff64 100644 --- a/drivers/char/drm/i915_mem.c +++ b/drivers/char/drm/i915_mem.c @@ -1,7 +1,6 @@ /* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*- */ -/************************************************************************** - * +/* * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * @@ -25,7 +24,7 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - **************************************************************************/ + */ #include "drmP.h" #include "drm.h" -- cgit v1.2.3 From b3a80a223d5f1af1e1713383376e5472cec4e20c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 21:15:01 +1100 Subject: drm: update lock flags from userspace Signed-off-by: Dave Airlie --- drivers/char/drm/drm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 64d6237fdd0b..9da0ddb892b5 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -90,8 +90,8 @@ #define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ #define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */ -#define _DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */ -#define _DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */ +#define _DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */ #define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) #define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) -- cgit v1.2.3 From fe34765be1ee9465b10406e6e5dddbd43ddc4fbe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 21:19:39 +1100 Subject: drm: drm_ioctl.c sync with fixes from CVS Apply the fixes from CVS that were outstanding for this file Signed-off-by: Dave Airlie --- drivers/char/drm/drm_ioctl.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c index a654ac17a900..bcd4e604d3ec 100644 --- a/drivers/char/drm/drm_ioctl.c +++ b/drivers/char/drm/drm_ioctl.c @@ -137,17 +137,22 @@ int drm_setunique(struct inode *inode, struct file *filp, static int drm_set_busid(drm_device_t * dev) { + int len; + if (dev->unique != NULL) return EBUSY; - dev->unique_len = 20; + dev->unique_len = 40; dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); if (dev->unique == NULL) return ENOMEM; - snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", + len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); + if (len > dev->unique_len) + DRM_ERROR("Unique buffer overflowed\n"); + dev->devname = drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + 2, DRM_MEM_DRIVER); @@ -239,7 +244,7 @@ int drm_getclient(struct inode *inode, struct file *filp, { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; - drm_client_t __user *argp = (void __user *)arg; + drm_client_t __user *argp = (drm_client_t __user *)arg; drm_client_t client; drm_file_t *pt; int idx; @@ -262,7 +267,7 @@ int drm_getclient(struct inode *inode, struct file *filp, client.iocs = pt->ioctl_count; up(&dev->struct_sem); - if (copy_to_user((drm_client_t __user *) arg, &client, sizeof(client))) + if (copy_to_user(argp, &client, sizeof(client))) return -EFAULT; return 0; } @@ -339,7 +344,7 @@ int drm_setversion(DRM_IOCTL_ARGS) if (sv.drm_di_major != DRM_IF_MAJOR || sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) return EINVAL; - if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor); + if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor); dev->if_version = DRM_MAX(if_version, dev->if_version); if (sv.drm_di_minor >= 1) { /* -- cgit v1.2.3 From b0cae664ebc85f2431c5a7c9e192a2a2ef72ecc7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 21:23:07 +1100 Subject: drm: update drm pci ids list Signed-off-by: Dave Airlie --- drivers/char/drm/drm_pciids.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index d66dc55e29a0..5b1d3a04458d 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -46,6 +46,7 @@ {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ @@ -69,6 +70,7 @@ {0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ {0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \ @@ -82,10 +84,13 @@ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ {0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \ {0x1002, 0x5c62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \ {0x1002, 0x5c64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \ {0, 0, 0} #define r128_PCI_IDS \ @@ -176,7 +181,7 @@ #define viadrv_PCI_IDS \ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -196,6 +201,10 @@ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} +#define gamma_PCI_IDS \ + {0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + #define savage_PCI_IDS \ {0x5333, 0x8a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \ {0x5333, 0x8a21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \ @@ -234,3 +243,4 @@ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} + -- cgit v1.2.3 From d985c1088146607532093d9eaaaf99758f6a4d21 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jan 2006 21:32:48 +1100 Subject: drm: major update from CVS for radeon and core This patch pull in a lot of changes from CVS to the main core DRM, and updates the radeon driver to 1.21.0 that supports r300 texrect and radeon card type ioctl. Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 18 +-- drivers/char/drm/drm_agpsupport.c | 10 +- drivers/char/drm/drm_bufs.c | 47 +++++-- drivers/char/drm/drm_fops.c | 289 ++++++++++++++++++++++---------------- drivers/char/drm/drm_lock.c | 18 +-- drivers/char/drm/drm_stub.c | 37 ----- drivers/char/drm/r300_cmdbuf.c | 38 ++--- drivers/char/drm/r300_reg.h | 1 + drivers/char/drm/radeon_cp.c | 75 +++++----- drivers/char/drm/radeon_drm.h | 6 + drivers/char/drm/radeon_drv.h | 24 ++-- drivers/char/drm/radeon_state.c | 184 ++++++++++-------------- 12 files changed, 366 insertions(+), 381 deletions(-) diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 43c49ad3069b..307254da7d08 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -550,7 +550,7 @@ struct drm_driver { int (*kernel_context_switch) (struct drm_device * dev, int old, int new); void (*kernel_context_switch_unlock) (struct drm_device * dev, - drm_lock_t * lock); + drm_lock_t *lock); int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); int (*dri_library_name) (struct drm_device *dev, char *buf); @@ -574,12 +574,11 @@ struct drm_driver { void (*irq_postinstall) (struct drm_device * dev); void (*irq_uninstall) (struct drm_device * dev); void (*reclaim_buffers) (struct drm_device * dev, struct file * filp); - void (*reclaim_buffers_locked) (struct drm_device *drv, + void (*reclaim_buffers_locked) (struct drm_device *dev, struct file *filp); unsigned long (*get_map_ofs) (drm_map_t * map); unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); - int (*version) (drm_version_t * version); int major; int minor; @@ -774,10 +773,6 @@ static inline int drm_mtrr_del(int handle, unsigned long offset, /** \name Internal function definitions */ /*@{*/ - /* Misc. support (drm_init.h) */ -extern int drm_flags; -extern void drm_parse_options(char *s); - /* Driver support (drm_drv.h) */ extern int drm_init(struct drm_driver *driver); extern void drm_exit(struct drm_driver *driver); @@ -831,6 +826,8 @@ extern int drm_getstats(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_setversion(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_noop(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); /* Context IOCTL support (drm_context.h) */ extern int drm_resctx(struct inode *inode, struct file *filp, @@ -869,10 +866,6 @@ extern int drm_getmagic(struct inode *inode, struct file *filp, extern int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); - /* Placeholder for ioctls past */ -extern int drm_noop(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); - /* Locking IOCTL support (drm_lock.h) */ extern int drm_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); @@ -885,6 +878,7 @@ extern int drm_lock_free(drm_device_t * dev, /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request); +extern int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request); extern int drm_addmap(drm_device_t * dev, unsigned int offset, unsigned int size, drm_map_type_t type, drm_map_flags_t flags, drm_local_map_t ** map_ptr); @@ -920,8 +914,8 @@ extern void drm_core_reclaim_buffers(drm_device_t * dev, struct file *filp); /* IRQ support (drm_irq.h) */ extern int drm_control(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int drm_irq_uninstall(drm_device_t * dev); extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS); +extern int drm_irq_uninstall(drm_device_t * dev); extern void drm_driver_irq_preinstall(drm_device_t * dev); extern void drm_driver_irq_postinstall(drm_device_t * dev); extern void drm_driver_irq_uninstall(drm_device_t * dev); diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c index b80e61a4c40b..fabc930c67a2 100644 --- a/drivers/char/drm/drm_agpsupport.c +++ b/drivers/char/drm/drm_agpsupport.c @@ -1,5 +1,5 @@ /** - * \file drm_agpsupport.h + * \file drm_agpsupport.c * DRM support for AGP/GART backend * * \author Rickard E. (Rik) Faith @@ -91,7 +91,7 @@ int drm_agp_info_ioctl(struct inode *inode, struct file *filp, /** * Acquire the AGP device. * - * \param dev DRM device that is to acquire AGP + * \param dev DRM device that is to acquire AGP. * \return zero on success or a negative number on failure. * * Verifies the AGP device hasn't been acquired before and calls @@ -134,7 +134,7 @@ int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp, /** * Release the AGP device. * - * \param dev DRM device that is to release AGP + * \param dev DRM device that is to release AGP. * \return zero on success or a negative number on failure. * * Verifies the AGP device has been acquired and calls \c agp_backend_release. @@ -147,7 +147,6 @@ int drm_agp_release(drm_device_t * dev) dev->agp->acquired = 0; return 0; } - EXPORT_SYMBOL(drm_agp_release); int drm_agp_release_ioctl(struct inode *inode, struct file *filp, @@ -447,6 +446,9 @@ int drm_agp_free_ioctl(struct inode *inode, struct file *filp, * * \return pointer to a drm_agp_head structure. * + * Gets the drm_agp_t structure which is made available by the agpgart module + * via the inter_module_* functions. Creates and initializes a drm_agp_head + * structure. */ drm_agp_head_t *drm_agp_init(drm_device_t * dev) { diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 319bdea8de8a..1845dd062816 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -36,22 +36,21 @@ #include #include "drmP.h" -unsigned long drm_get_resource_start(drm_device_t * dev, unsigned int resource) +unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource) { return pci_resource_start(dev->pdev, resource); } - EXPORT_SYMBOL(drm_get_resource_start); -unsigned long drm_get_resource_len(drm_device_t * dev, unsigned int resource) +unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource) { return pci_resource_len(dev->pdev, resource); } EXPORT_SYMBOL(drm_get_resource_len); -static drm_map_list_t *drm_find_matching_map(drm_device_t * dev, - drm_local_map_t * map) +static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, + drm_local_map_t *map) { struct list_head *list; @@ -74,7 +73,7 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t * dev, #ifdef _LP64 static __inline__ unsigned int HandleID(unsigned long lhandle, - drm_device_t * dev) + drm_device_t *dev) { static unsigned int map32_handle = START_RANGE; unsigned int hash; @@ -301,6 +300,9 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, return -EFAULT; } + if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP)) + return -EPERM; + err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags, &maplist); @@ -332,7 +334,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, * * \sa drm_addmap */ -int drm_rmmap_locked(drm_device_t * dev, drm_local_map_t * map) +int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) { struct list_head *list; drm_map_list_t *r_list = NULL; @@ -384,10 +386,9 @@ int drm_rmmap_locked(drm_device_t * dev, drm_local_map_t * map) return 0; } - EXPORT_SYMBOL(drm_rmmap_locked); -int drm_rmmap(drm_device_t * dev, drm_local_map_t * map) +int drm_rmmap(drm_device_t *dev, drm_local_map_t *map) { int ret; @@ -397,7 +398,6 @@ int drm_rmmap(drm_device_t * dev, drm_local_map_t * map) return ret; } - EXPORT_SYMBOL(drm_rmmap); /* The rmmap ioctl appears to be unnecessary. All mappings are torn down on @@ -548,7 +548,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) DRM_DEBUG("count: %d\n", count); DRM_DEBUG("order: %d\n", order); DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %lu\n", agp_offset); + DRM_DEBUG("agp_offset: %lx\n", agp_offset); DRM_DEBUG("alignment: %d\n", alignment); DRM_DEBUG("page_order: %d\n", page_order); DRM_DEBUG("total: %d\n", total); @@ -649,6 +649,8 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) } dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; dma->byte_count += byte_count; DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); @@ -664,7 +666,6 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return 0; } - EXPORT_SYMBOL(drm_addbufs_agp); #endif /* __OS_HAS_AGP */ @@ -689,9 +690,13 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL; + if (!dma) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + count = request->count; order = drm_order(request->size); size = 1 << order; @@ -882,7 +887,6 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) return 0; } - EXPORT_SYMBOL(drm_addbufs_pci); static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) @@ -908,6 +912,9 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) if (!dma) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + count = request->count; order = drm_order(request->size); size = 1 << order; @@ -1026,6 +1033,8 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) } dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; dma->byte_count += byte_count; DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); @@ -1042,7 +1051,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request) return 0; } -static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) +int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; @@ -1065,6 +1074,9 @@ static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) if (!dma) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + count = request->count; order = drm_order(request->size); size = 1 << order; @@ -1181,6 +1193,8 @@ static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) } dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; dma->byte_count += byte_count; DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); @@ -1196,6 +1210,8 @@ static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return 0; } +EXPORT_SYMBOL(drm_addbufs_fb); + /** * Add buffers for DMA transfers (ioctl). @@ -1577,5 +1593,6 @@ int drm_order(unsigned long size) return order; } - EXPORT_SYMBOL(drm_order); + + diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index b73543c694a9..403f44a1bf01 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -35,6 +35,7 @@ */ #include "drmP.h" +#include "drm_sarea.h" #include static int drm_open_helper(struct inode *inode, struct file *filp, @@ -42,6 +43,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, static int drm_setup(drm_device_t * dev) { + drm_local_map_t *map; int i; int ret; @@ -51,6 +53,11 @@ static int drm_setup(drm_device_t * dev) return ret; } + /* prebuild the SAREA */ + i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); + if (i != 0) + return i; + atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); dev->buf_use = 0; @@ -152,9 +159,167 @@ int drm_open(struct inode *inode, struct file *filp) return retcode; } - EXPORT_SYMBOL(drm_open); +/** + * File \c open operation. + * + * \param inode device inode. + * \param filp file pointer. + * + * Puts the dev->fops corresponding to the device minor number into + * \p filp, call the \c open method, and restore the file operations. + */ +int drm_stub_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = NULL; + int minor = iminor(inode); + int err = -ENODEV; + struct file_operations *old_fops; + + DRM_DEBUG("\n"); + + if (!((minor >= 0) && (minor < drm_cards_limit))) + return -ENODEV; + + if (!drm_heads[minor]) + return -ENODEV; + + if (!(dev = drm_heads[minor]->dev)) + return -ENODEV; + + old_fops = filp->f_op; + filp->f_op = fops_get(&dev->driver->fops); + if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { + fops_put(filp->f_op); + filp->f_op = fops_get(old_fops); + } + fops_put(old_fops); + + return err; +} + +/** + * Check whether DRI will run on this CPU. + * + * \return non-zero if the DRI will run on this CPU, or zero otherwise. + */ +static int drm_cpu_valid(void) +{ +#if defined(__i386__) + if (boot_cpu_data.x86 == 3) + return 0; /* No cmpxchg on a 386 */ +#endif +#if defined(__sparc__) && !defined(__sparc_v9__) + return 0; /* No cmpxchg before v9 sparc. */ +#endif + return 1; +} + +/** + * Called whenever a process opens /dev/drm. + * + * \param inode device inode. + * \param filp file pointer. + * \param dev device. + * \return zero on success or a negative number on failure. + * + * Creates and initializes a drm_file structure for the file private data in \p + * filp and add it into the double linked list in \p dev. + */ +static int drm_open_helper(struct inode *inode, struct file *filp, + drm_device_t * dev) +{ + int minor = iminor(inode); + drm_file_t *priv; + int ret; + + if (filp->f_flags & O_EXCL) + return -EBUSY; /* No exclusive opens */ + if (!drm_cpu_valid()) + return -EINVAL; + + DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); + + priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); + if (!priv) + return -ENOMEM; + + memset(priv, 0, sizeof(*priv)); + filp->private_data = priv; + priv->uid = current->euid; + priv->pid = current->pid; + priv->minor = minor; + priv->head = drm_heads[minor]; + priv->ioctl_count = 0; + /* for compatibility root is always authenticated */ + priv->authenticated = capable(CAP_SYS_ADMIN); + priv->lock_count = 0; + + if (dev->driver->open) { + ret = dev->driver->open(dev, priv); + if (ret < 0) + goto out_free; + } + + down(&dev->struct_sem); + if (!dev->file_last) { + priv->next = NULL; + priv->prev = NULL; + dev->file_first = priv; + dev->file_last = priv; + /* first opener automatically becomes master */ + priv->master = 1; + } else { + priv->next = NULL; + priv->prev = dev->file_last; + dev->file_last->next = priv; + dev->file_last = priv; + } + up(&dev->struct_sem); + +#ifdef __alpha__ + /* + * Default the hose + */ + if (!dev->hose) { + struct pci_dev *pci_dev; + pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); + if (pci_dev) { + dev->hose = pci_dev->sysdata; + pci_dev_put(pci_dev); + } + if (!dev->hose) { + struct pci_bus *b = pci_bus_b(pci_root_buses.next); + if (b) + dev->hose = b->sysdata; + } + } +#endif + + return 0; + out_free: + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + filp->private_data = NULL; + return ret; +} + +/** No-op. */ +int drm_fasync(int fd, struct file *filp, int on) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + int retcode; + + DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, + (long)old_encode_dev(priv->head->device)); + retcode = fasync_helper(fd, filp, on, &dev->buf_async); + if (retcode < 0) + return retcode; + return 0; +} +EXPORT_SYMBOL(drm_fasync); + /** * Release file. * @@ -291,7 +456,6 @@ int drm_release(struct inode *inode, struct file *filp) if (dev->driver->postclose) dev->driver->postclose(dev, priv); - drm_free(priv, sizeof(*priv), DRM_MEM_FILES); /* ======================================================== @@ -318,132 +482,11 @@ int drm_release(struct inode *inode, struct file *filp) return retcode; } - EXPORT_SYMBOL(drm_release); -/** - * Check whether DRI will run on this CPU. - * - * \return non-zero if the DRI will run on this CPU, or zero otherwise. - */ -static int drm_cpu_valid(void) -{ -#if defined(__i386__) - if (boot_cpu_data.x86 == 3) - return 0; /* No cmpxchg on a 386 */ -#endif -#if defined(__sparc__) && !defined(__sparc_v9__) - return 0; /* No cmpxchg before v9 sparc. */ -#endif - return 1; -} - -/** - * Called whenever a process opens /dev/drm. - * - * \param inode device inode. - * \param filp file pointer. - * \param dev device. - * \return zero on success or a negative number on failure. - * - * Creates and initializes a drm_file structure for the file private data in \p - * filp and add it into the double linked list in \p dev. - */ -static int drm_open_helper(struct inode *inode, struct file *filp, - drm_device_t * dev) -{ - int minor = iminor(inode); - drm_file_t *priv; - int ret; - - if (filp->f_flags & O_EXCL) - return -EBUSY; /* No exclusive opens */ - if (!drm_cpu_valid()) - return -EINVAL; - - DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); - - priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); - if (!priv) - return -ENOMEM; - - memset(priv, 0, sizeof(*priv)); - filp->private_data = priv; - priv->uid = current->euid; - priv->pid = current->pid; - priv->minor = minor; - priv->head = drm_heads[minor]; - priv->ioctl_count = 0; - priv->authenticated = capable(CAP_SYS_ADMIN); - priv->lock_count = 0; - - if (dev->driver->open) { - ret = dev->driver->open(dev, priv); - if (ret < 0) - goto out_free; - } - - down(&dev->struct_sem); - if (!dev->file_last) { - priv->next = NULL; - priv->prev = NULL; - dev->file_first = priv; - dev->file_last = priv; - } else { - priv->next = NULL; - priv->prev = dev->file_last; - dev->file_last->next = priv; - dev->file_last = priv; - } - up(&dev->struct_sem); - -#ifdef __alpha__ - /* - * Default the hose - */ - if (!dev->hose) { - struct pci_dev *pci_dev; - pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); - if (pci_dev) { - dev->hose = pci_dev->sysdata; - pci_dev_put(pci_dev); - } - if (!dev->hose) { - struct pci_bus *b = pci_bus_b(pci_root_buses.next); - if (b) - dev->hose = b->sysdata; - } - } -#endif - - return 0; - out_free: - drm_free(priv, sizeof(*priv), DRM_MEM_FILES); - filp->private_data = NULL; - return ret; -} - -/** No-op. */ -int drm_fasync(int fd, struct file *filp, int on) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->head->dev; - int retcode; - - DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, - (long)old_encode_dev(priv->head->device)); - retcode = fasync_helper(fd, filp, on, &dev->buf_async); - if (retcode < 0) - return retcode; - return 0; -} - -EXPORT_SYMBOL(drm_fasync); - /** No-op. */ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) { return 0; } - EXPORT_SYMBOL(drm_poll); diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index b276ae8a6633..f970dc36c18f 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -104,6 +104,9 @@ int drm_lock(struct inode *inode, struct file *filp, __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); + DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); + if (ret) return ret; + sigemptyset(&dev->sigmask); sigaddset(&dev->sigmask, SIGSTOP); sigaddset(&dev->sigmask, SIGTSTP); @@ -116,21 +119,20 @@ int drm_lock(struct inode *inode, struct file *filp, if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY)) dev->driver->dma_ready(dev); - if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) - return dev->driver->dma_quiescent(dev); - - /* dev->driver->kernel_context_switch isn't used by any of the x86 - * drivers but is used by the Sparc driver. - */ + if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) { + if (dev->driver->dma_quiescent(dev)) { + DRM_DEBUG( "%d waiting for DMA quiescent\n", lock.context); + return DRM_ERR(EBUSY); + } + } if (dev->driver->kernel_context_switch && dev->last_context != lock.context) { dev->driver->kernel_context_switch(dev, dev->last_context, lock.context); } - DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - return ret; + return 0; } /** diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index b7f2a851f45c..42d766359caa 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -128,43 +128,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, return retcode; } -/** - * File \c open operation. - * - * \param inode device inode. - * \param filp file pointer. - * - * Puts the dev->fops corresponding to the device minor number into - * \p filp, call the \c open method, and restore the file operations. - */ -int drm_stub_open(struct inode *inode, struct file *filp) -{ - drm_device_t *dev = NULL; - int minor = iminor(inode); - int err = -ENODEV; - struct file_operations *old_fops; - - DRM_DEBUG("\n"); - - if (!((minor >= 0) && (minor < drm_cards_limit))) - return -ENODEV; - - if (!drm_heads[minor]) - return -ENODEV; - - if (!(dev = drm_heads[minor]->dev)) - return -ENODEV; - - old_fops = filp->f_op; - filp->f_op = fops_get(&dev->driver->fops); - if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { - fops_put(filp->f_op); - filp->f_op = fops_get(old_fops); - } - fops_put(old_fops); - - return err; -} /** * Get a secondary minor number. diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index 3a1ac5f78b43..291dbf4c8186 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -52,8 +52,8 @@ static const int r300_cliprect_cntl[4] = { * Emit up to R300_SIMULTANEOUS_CLIPRECTS cliprects from the given command * buffer, starting with index n. */ -static int r300_emit_cliprects(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf, int n) +static int r300_emit_cliprects(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf, int n) { drm_clip_rect_t box; int nr; @@ -216,6 +216,7 @@ void r300_init_reg_flags(void) ADD_RANGE(R300_TX_UNK1_0, 16); ADD_RANGE(R300_TX_SIZE_0, 16); ADD_RANGE(R300_TX_FORMAT_0, 16); + ADD_RANGE(R300_TX_PITCH_0, 16); /* Texture offset is dangerous and needs more checking */ ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET); ADD_RANGE(R300_TX_UNK4_0, 16); @@ -242,7 +243,7 @@ static __inline__ int r300_check_range(unsigned reg, int count) /* we expect offsets passed to the framebuffer to be either within video memory or within AGP space */ -static __inline__ int r300_check_offset(drm_radeon_private_t * dev_priv, +static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, u32 offset) { /* we realy want to check against end of video aperture @@ -317,8 +318,8 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * * * Note that checks are performed on contents and addresses of the registers */ -static __inline__ int r300_emit_packet0(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf, +static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf, drm_r300_cmd_header_t header) { int reg; @@ -363,8 +364,8 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t * dev_priv, * the graphics card. * Called by r300_do_cp_cmdbuf. */ -static __inline__ int r300_emit_vpu(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf, +static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf, drm_r300_cmd_header_t header) { int sz; @@ -400,8 +401,8 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t * dev_priv, * Emit a clear packet from userspace. * Called by r300_emit_packet3. */ -static __inline__ int r300_emit_clear(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf) +static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) { RING_LOCALS; @@ -421,8 +422,8 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t * dev_priv, return 0; } -static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf, +static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf, u32 header) { int count, i, k; @@ -489,8 +490,8 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t * dev_priv, return 0; } -static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf) +static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) { u32 header; int count; @@ -554,8 +555,8 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t * dev_priv, * Emit a rendering packet3 from userspace. * Called by r300_do_cp_cmdbuf. */ -static __inline__ int r300_emit_packet3(drm_radeon_private_t * dev_priv, - drm_radeon_kcmd_buffer_t * cmdbuf, +static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf, drm_r300_cmd_header_t header) { int n; @@ -623,7 +624,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t * dev_priv, /** * Emit the sequence to pacify R300. */ -static __inline__ void r300_pacify(drm_radeon_private_t * dev_priv) +static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) { RING_LOCALS; @@ -657,9 +658,10 @@ static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf) * commands on the DMA ring buffer. * Called by the ioctl handler function radeon_cp_cmdbuf. */ -int r300_do_cp_cmdbuf(drm_device_t * dev, +int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp, - drm_file_t * filp_priv, drm_radeon_kcmd_buffer_t * cmdbuf) + drm_file_t *filp_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h index e5b73c002394..a0ed20e25221 100644 --- a/drivers/char/drm/r300_reg.h +++ b/drivers/char/drm/r300_reg.h @@ -797,6 +797,7 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_TX_FORMAT_YUV_MODE 0x00800000 +#define R300_TX_PITCH_0 0x4500 #define R300_TX_OFFSET_0 0x4540 /* BEGIN: Guess from R200 */ # define R300_TXO_ENDIAN_NO_SWAP (0 << 0) diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index eaa0e2b7c2f8..915665c7fe7c 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -824,7 +824,7 @@ static int RADEON_READ_PLL(drm_device_t * dev, int addr) return RADEON_READ(RADEON_CLOCK_CNTL_DATA); } -static int RADEON_READ_PCIE(drm_radeon_private_t * dev_priv, int addr) +static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) { RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff); return RADEON_READ(RADEON_PCIE_DATA); @@ -1125,7 +1125,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | (dev_priv->fb_location >> 16)); #if __OS_HAS_AGP - if (!dev_priv->is_pci) { + if (dev_priv->flags & CHIP_IS_AGP) { RADEON_WRITE(RADEON_MC_AGP_LOCATION, (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | @@ -1152,7 +1152,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, dev_priv->ring.tail = cur_read_ptr; #if __OS_HAS_AGP - if (!dev_priv->is_pci) { + if (dev_priv->flags & CHIP_IS_AGP) { /* set RADEON_AGP_BASE here instead of relying on X from user space */ RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, @@ -1278,13 +1278,15 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) /* Enable or disable PCI GART on the chip */ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { - u32 tmp = RADEON_READ(RADEON_AIC_CNTL); + u32 tmp; if (dev_priv->flags & CHIP_IS_PCIE) { radeon_set_pciegart(dev_priv, on); return; } + tmp = RADEON_READ(RADEON_AIC_CNTL); + if (on) { RADEON_WRITE(RADEON_AIC_CNTL, tmp | RADEON_PCIGART_TRANSLATE_EN); @@ -1311,14 +1313,18 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) { - drm_radeon_private_t *dev_priv = dev->dev_private;; + drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG("\n"); - dev_priv->is_pci = init->is_pci; + if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP)) + { + DRM_DEBUG("Forcing AGP card to PCI mode\n"); + dev_priv->flags &= ~CHIP_IS_AGP; + } - if (dev_priv->is_pci && !dev->sg) { + if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) { DRM_ERROR("PCI GART memory not allocated!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } @@ -1327,12 +1333,11 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if (dev_priv->usec_timeout < 1 || dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) { DRM_DEBUG("TIMEOUT problem!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - switch (init->func) { + switch(init->func) { case RADEON_INIT_R200_CP: dev_priv->microcode_version = UCODE_R200; break; @@ -1353,7 +1358,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if ((init->cp_mode != RADEON_CSQ_PRIBM_INDDIS) && (init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) { DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } @@ -1416,8 +1420,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) DRM_GETSAREA(); - dev_priv->fb_offset = init->fb_offset; - dev_priv->mmio_offset = init->mmio_offset; dev_priv->ring_offset = init->ring_offset; dev_priv->ring_rptr_offset = init->ring_rptr_offset; dev_priv->buffers_offset = init->buffers_offset; @@ -1425,29 +1427,19 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if (!dev_priv->sarea) { DRM_ERROR("could not find sarea!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); - if (!dev_priv->mmio) { - DRM_ERROR("could not find mmio region!\n"); - dev->dev_private = (void *)dev_priv; - radeon_do_cleanup_cp(dev); - return DRM_ERR(EINVAL); - } dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset); if (!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); if (!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } @@ -1455,7 +1447,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { DRM_ERROR("could not find dma buffer region!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } @@ -1465,7 +1456,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) drm_core_findmap(dev, init->gart_textures_offset); if (!dev_priv->gart_textures) { DRM_ERROR("could not find GART texture region!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } @@ -1476,7 +1466,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) init->sarea_priv_offset); #if __OS_HAS_AGP - if (!dev_priv->is_pci) { + if (dev_priv->flags & CHIP_IS_AGP) { drm_core_ioremap(dev_priv->cp_ring, dev); drm_core_ioremap(dev_priv->ring_rptr, dev); drm_core_ioremap(dev->agp_buffer_map, dev); @@ -1484,7 +1474,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) !dev_priv->ring_rptr->handle || !dev->agp_buffer_map->handle) { DRM_ERROR("could not find ioremap agp regions!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } @@ -1525,7 +1514,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) + RADEON_READ(RADEON_CONFIG_APER_SIZE); #if __OS_HAS_AGP - if (!dev_priv->is_pci) + if (dev_priv->flags & CHIP_IS_AGP) dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->agp->base + dev_priv->gart_vm_start); @@ -1551,7 +1540,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; #if __OS_HAS_AGP - if (!dev_priv->is_pci) { + if (dev_priv->flags & CHIP_IS_AGP) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); } else @@ -1593,7 +1582,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { DRM_ERROR("failed to init PCI GART!\n"); - dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); return DRM_ERR(ENOMEM); } @@ -1607,8 +1595,6 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->last_buf = 0; - dev->dev_private = (void *)dev_priv; - radeon_do_engine_reset(dev); return 0; @@ -1627,11 +1613,15 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) drm_irq_uninstall(dev); #if __OS_HAS_AGP - if (!dev_priv->is_pci) { - if (dev_priv->cp_ring != NULL) + if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->cp_ring != NULL) { drm_core_ioremapfree(dev_priv->cp_ring, dev); - if (dev_priv->ring_rptr != NULL) + dev_priv->cp_ring = NULL; + } + if (dev_priv->ring_rptr != NULL) { drm_core_ioremapfree(dev_priv->ring_rptr, dev); + dev_priv->ring_rptr = NULL; + } if (dev->agp_buffer_map != NULL) { drm_core_ioremapfree(dev->agp_buffer_map, dev); dev->agp_buffer_map = NULL; @@ -1639,16 +1629,20 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) } else #endif { - if (dev_priv->gart_info.bus_addr) + + if (dev_priv->gart_info.bus_addr) { + /* Turn off PCI GART */ + radeon_set_pcigart(dev_priv, 0); if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info)) DRM_ERROR("failed to cleanup PCI GART!\n"); + } - if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { + if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) + { drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = 0; } } - /* only clear to the start of flags */ memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags)); @@ -1674,7 +1668,7 @@ static int radeon_do_resume_cp(drm_device_t * dev) DRM_DEBUG("Starting radeon_do_resume_cp()\n"); #if __OS_HAS_AGP - if (!dev_priv->is_pci) { + if (dev_priv->flags & CHIP_IS_AGP) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); } else @@ -2138,7 +2132,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->flags |= CHIP_IS_PCIE; DRM_DEBUG("%s card detected\n", - ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : "PCI")); + ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI")))); return ret; } @@ -2171,7 +2165,6 @@ int radeon_driver_unload(struct drm_device *dev) drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 1cd81a671a36..9c177a6b2a4c 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -624,6 +624,11 @@ typedef struct drm_radeon_indirect { int discard; } drm_radeon_indirect_t; +/* enum for card type parameters */ +#define RADEON_CARD_PCI 0 +#define RADEON_CARD_AGP 1 +#define RADEON_CARD_PCIE 2 + /* 1.3: An ioctl to get parameters that aren't available to the 3d * client any other way. */ @@ -640,6 +645,7 @@ typedef struct drm_radeon_indirect { #define RADEON_PARAM_SAREA_HANDLE 9 #define RADEON_PARAM_GART_TEX_HANDLE 10 #define RADEON_PARAM_SCRATCH_OFFSET 11 +#define RADEON_PARAM_CARD_TYPE 12 typedef struct drm_radeon_getparam { int param; diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index c37f2ea20783..498b19b1d641 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -38,7 +38,7 @@ #define DRIVER_NAME "radeon" #define DRIVER_DESC "ATI Radeon" -#define DRIVER_DATE "20050911" +#define DRIVER_DATE "20051229" /* Interface history: * @@ -73,7 +73,7 @@ * 1.11- Add packet R200_EMIT_RB3D_BLENDCOLOR to support GL_EXT_blend_color * and GL_EXT_blend_[func|equation]_separate on r200 * 1.12- Add R300 CP microcode support - this just loads the CP on r300 - * (No 3D support yet - just microcode loading) + * (No 3D support yet - just microcode loading). * 1.13- Add packet R200_EMIT_TCL_POINT_SPRITE_CNTL for ARB_point_parameters * - Add hyperz support, add hyperz flags to clear ioctl. * 1.14- Add support for color tiling @@ -88,14 +88,13 @@ * R200_EMIT_PP_TXFILTER_0-5, 2 more regs) and R200_EMIT_ATF_TFACTOR * (replaces R200_EMIT_TFACTOR_0 (8 consts instead of 6) * 1.19- Add support for gart table in FB memory and PCIE r300 + * 1.20- Add support for r300 texrect + * 1.21- Add support for card type getparam */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 19 +#define DRIVER_MINOR 21 #define DRIVER_PATCHLEVEL 0 -#define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) -#define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) - /* * Radeon chip families */ @@ -138,6 +137,9 @@ enum radeon_chip_flags { CHIP_IS_PCIE = 0x00200000UL, }; +#define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) +#define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) + typedef struct drm_radeon_freelist { unsigned int age; drm_buf_t *buf; @@ -214,8 +216,6 @@ typedef struct drm_radeon_private { int microcode_version; - int is_pci; - struct { u32 boxes; int freelist_timeouts; @@ -247,8 +247,6 @@ typedef struct drm_radeon_private { drm_radeon_depth_clear_t depth_clear; - unsigned long fb_offset; - unsigned long mmio_offset; unsigned long ring_offset; unsigned long ring_rptr_offset; unsigned long buffers_offset; @@ -362,6 +360,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, */ #define RADEON_AGP_COMMAND 0x0f60 +#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config */ +# define RADEON_AGP_ENABLE (1<<8) #define RADEON_AUX_SCISSOR_CNTL 0x26f0 # define RADEON_EXCLUSIVE_SCISSOR_0 (1 << 24) # define RADEON_EXCLUSIVE_SCISSOR_1 (1 << 25) @@ -377,6 +377,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, # define RADEON_PLL_WR_EN (1 << 7) #define RADEON_CLOCK_CNTL_INDEX 0x0008 #define RADEON_CONFIG_APER_SIZE 0x0108 +#define RADEON_CONFIG_MEMSIZE 0x00f8 #define RADEON_CRTC_OFFSET 0x0224 #define RADEON_CRTC_OFFSET_CNTL 0x0228 # define RADEON_CRTC_TILE_EN (1 << 15) @@ -648,6 +649,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp, #define RADEON_WAIT_UNTIL 0x1720 # define RADEON_WAIT_CRTC_PFLIP (1 << 0) +# define RADEON_WAIT_2D_IDLE (1 << 14) +# define RADEON_WAIT_3D_IDLE (1 << 15) # define RADEON_WAIT_2D_IDLECLEAN (1 << 16) # define RADEON_WAIT_3D_IDLECLEAN (1 << 17) # define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) @@ -1102,7 +1105,6 @@ do { \ write = 0; \ _tab += _i; \ } \ - \ while (_size > 0) { \ *(ring + write) = *_tab++; \ write++; \ diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 9e816c63a8a3..e9d8ec3a0994 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -1,5 +1,5 @@ -/* radeon_state.c -- State support for Radeon -*- linux-c -*- - * +/* radeon_state.c -- State support for Radeon -*- linux-c -*- */ +/* * Copyright 2000 VA Linux Systems, Inc., Fremont, California. * All Rights Reserved. * @@ -72,10 +72,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case RADEON_EMIT_PP_MISC: if (radeon_check_and_fixup_offset(dev_priv, filp_priv, - &data[(RADEON_RB3D_DEPTHOFFSET - - - RADEON_PP_MISC) / - 4])) { + &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) { DRM_ERROR("Invalid depth buffer offset\n"); return DRM_ERR(EINVAL); } @@ -83,10 +80,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case RADEON_EMIT_PP_CNTL: if (radeon_check_and_fixup_offset(dev_priv, filp_priv, - &data[(RADEON_RB3D_COLOROFFSET - - - RADEON_PP_CNTL) / - 4])) { + &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) { DRM_ERROR("Invalid colour buffer offset\n"); return DRM_ERR(EINVAL); } @@ -109,10 +103,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case RADEON_EMIT_PP_TXFILTER_1: case RADEON_EMIT_PP_TXFILTER_2: if (radeon_check_and_fixup_offset(dev_priv, filp_priv, - &data[(RADEON_PP_TXOFFSET_0 - - - RADEON_PP_TXFILTER_0) / - 4])) { + &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) { DRM_ERROR("Invalid R100 texture offset\n"); return DRM_ERR(EINVAL); } @@ -126,8 +117,9 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case R200_EMIT_PP_CUBIC_OFFSETS_5:{ int i; for (i = 0; i < 5; i++) { - if (radeon_check_and_fixup_offset - (dev_priv, filp_priv, &data[i])) { + if (radeon_check_and_fixup_offset(dev_priv, + filp_priv, + &data[i])) { DRM_ERROR ("Invalid R200 cubic texture offset\n"); return DRM_ERR(EINVAL); @@ -239,8 +231,9 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * dev_priv, - drm_file_t * filp_priv, - drm_radeon_kcmd_buffer_t *cmdbuf, + drm_file_t *filp_priv, + drm_radeon_kcmd_buffer_t * + cmdbuf, unsigned int *cmdsz) { u32 *cmd = (u32 *) cmdbuf->buf; @@ -555,7 +548,8 @@ static struct { {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"}, {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"}, {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"}, - {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1, "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"}, + {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1, + "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"}, {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"}, {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"}, {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"}, @@ -569,7 +563,7 @@ static struct { {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4, "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"}, {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */ - {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */ + {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */ {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"}, {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"}, {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"}, @@ -592,7 +586,7 @@ static struct { {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"}, {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"}, {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"}, - {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */ + {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */ {R200_PP_AFS_1, 32, "R200_PP_AFS_1"}, {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"}, {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"}, @@ -985,8 +979,8 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, * rendering a quad into just those buffers. Thus, we have to * make sure the 3D engine is configured correctly. */ - if ((dev_priv->microcode_version == UCODE_R200) && - (flags & (RADEON_DEPTH | RADEON_STENCIL))) { + else if ((dev_priv->microcode_version == UCODE_R200) && + (flags & (RADEON_DEPTH | RADEON_STENCIL))) { int tempPP_CNTL; int tempRE_CNTL; @@ -1637,6 +1631,14 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset); dwords = size / 4; +#define RADEON_COPY_MT(_buf, _data, _width) \ + do { \ + if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\ + DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \ + return DRM_ERR(EFAULT); \ + } \ + } while(0) + if (microtile) { /* texture micro tiling in use, minimum texture width is thus 16 bytes. however, we cannot use blitter directly for texture width < 64 bytes, @@ -1648,46 +1650,19 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, from user space. */ if (tex->height == 1) { if (tex_width >= 64 || tex_width <= 16) { - if (DRM_COPY_FROM_USER(buffer, data, - tex_width * - sizeof(u32))) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, + tex_width * sizeof(u32)); } else if (tex_width == 32) { - if (DRM_COPY_FROM_USER - (buffer, data, 16)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } - if (DRM_COPY_FROM_USER - (buffer + 8, data + 16, 16)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, 16); + RADEON_COPY_MT(buffer + 8, + data + 16, 16); } } else if (tex_width >= 64 || tex_width == 16) { - if (DRM_COPY_FROM_USER(buffer, data, - dwords * sizeof(u32))) { - DRM_ERROR("EFAULT on data, %d dwords\n", - dwords); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, + dwords * sizeof(u32)); } else if (tex_width < 16) { for (i = 0; i < tex->height; i++) { - if (DRM_COPY_FROM_USER - (buffer, data, tex_width)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, tex_width); buffer += 4; data += tex_width; } @@ -1695,37 +1670,13 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, /* TODO: make sure this works when not fitting in one buffer (i.e. 32bytes x 2048...) */ for (i = 0; i < tex->height; i += 2) { - if (DRM_COPY_FROM_USER - (buffer, data, 16)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, 16); data += 16; - if (DRM_COPY_FROM_USER - (buffer + 8, data, 16)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer + 8, data, 16); data += 16; - if (DRM_COPY_FROM_USER - (buffer + 4, data, 16)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer + 4, data, 16); data += 16; - if (DRM_COPY_FROM_USER - (buffer + 12, data, 16)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer + 12, data, 16); data += 16; buffer += 16; } @@ -1735,31 +1686,22 @@ static int radeon_cp_dispatch_texture(DRMFILE filp, /* Texture image width is larger than the minimum, so we * can upload it directly. */ - if (DRM_COPY_FROM_USER(buffer, data, - dwords * sizeof(u32))) { - DRM_ERROR("EFAULT on data, %d dwords\n", - dwords); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, + dwords * sizeof(u32)); } else { /* Texture image width is less than the minimum, so we * need to pad out each image scanline to the minimum * width. */ for (i = 0; i < tex->height; i++) { - if (DRM_COPY_FROM_USER - (buffer, data, tex_width)) { - DRM_ERROR - ("EFAULT on pad, %d bytes\n", - tex_width); - return DRM_ERR(EFAULT); - } + RADEON_COPY_MT(buffer, data, tex_width); buffer += 8; data += tex_width; } } } +#undef RADEON_COPY_MT buf->filp = filp; buf->used = size; offset = dev_priv->gart_buffers_offset + buf->offset; @@ -1821,7 +1763,7 @@ static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple) } static void radeon_apply_surface_regs(int surf_index, - drm_radeon_private_t * dev_priv) + drm_radeon_private_t *dev_priv) { if (!dev_priv->mmio) return; @@ -1847,8 +1789,8 @@ static void radeon_apply_surface_regs(int surf_index, * freed, we suddenly need two surfaces to store A and C, which might * not always be available. */ -static int alloc_surface(drm_radeon_surface_alloc_t * new, - drm_radeon_private_t * dev_priv, DRMFILE filp) +static int alloc_surface(drm_radeon_surface_alloc_t *new, + drm_radeon_private_t *dev_priv, DRMFILE filp) { struct radeon_virt_surface *s; int i; @@ -2158,6 +2100,11 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN(dev, filp); + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data, @@ -2596,9 +2543,9 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv, return 0; } -static __inline__ int radeon_emit_scalars(drm_radeon_private_t * dev_priv, +static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv, drm_radeon_cmd_header_t header, - drm_radeon_kcmd_buffer_t * cmdbuf) + drm_radeon_kcmd_buffer_t *cmdbuf) { int sz = header.scalars.count; int start = header.scalars.offset; @@ -2618,9 +2565,9 @@ static __inline__ int radeon_emit_scalars(drm_radeon_private_t * dev_priv, /* God this is ugly */ -static __inline__ int radeon_emit_scalars2(drm_radeon_private_t * dev_priv, +static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv, drm_radeon_cmd_header_t header, - drm_radeon_kcmd_buffer_t * cmdbuf) + drm_radeon_kcmd_buffer_t *cmdbuf) { int sz = header.scalars.count; int start = ((unsigned int)header.scalars.offset) + 0x100; @@ -2638,9 +2585,9 @@ static __inline__ int radeon_emit_scalars2(drm_radeon_private_t * dev_priv, return 0; } -static __inline__ int radeon_emit_vectors(drm_radeon_private_t * dev_priv, +static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv, drm_radeon_cmd_header_t header, - drm_radeon_kcmd_buffer_t * cmdbuf) + drm_radeon_kcmd_buffer_t *cmdbuf) { int sz = header.vectors.count; int start = header.vectors.offset; @@ -2685,8 +2632,8 @@ static int radeon_emit_packet3(drm_device_t * dev, return 0; } -static int radeon_emit_packet3_cliprect(drm_device_t * dev, - drm_file_t * filp_priv, +static int radeon_emit_packet3_cliprect(drm_device_t *dev, + drm_file_t *filp_priv, drm_radeon_kcmd_buffer_t *cmdbuf, int orig_nbox) { @@ -2818,7 +2765,8 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER); if (kbuf == NULL) return DRM_ERR(ENOMEM); - if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf, cmdbuf.bufsz)) { + if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf, + cmdbuf.bufsz)) { drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); return DRM_ERR(EFAULT); } @@ -2981,7 +2929,7 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) value = dev_priv->gart_vm_start; break; case RADEON_PARAM_REGISTER_HANDLE: - value = dev_priv->mmio_offset; + value = dev_priv->mmio->offset; break; case RADEON_PARAM_STATUS_HANDLE: value = dev_priv->ring_rptr_offset; @@ -3004,6 +2952,15 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) case RADEON_PARAM_GART_TEX_HANDLE: value = dev_priv->gart_textures_offset; break; + + case RADEON_PARAM_CARD_TYPE: + if (dev_priv->flags & CHIP_IS_PCIE) + value = RADEON_CARD_PCIE; + else if (dev_priv->flags & CHIP_IS_AGP) + value = RADEON_CARD_AGP; + else + value = RADEON_CARD_PCI; + break; default: return DRM_ERR(EINVAL); } @@ -3066,6 +3023,7 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) /* When a client dies: * - Check for and clean up flipped page state * - Free any alloced GART memory. + * - Free any alloced radeon surfaces. * * DRM infrastructure takes care of reclaiming dma buffers. */ @@ -3092,6 +3050,7 @@ int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv) drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_radeon_driver_file_fields *radeon_priv; + DRM_DEBUG("\n"); radeon_priv = (struct drm_radeon_driver_file_fields *) drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES); @@ -3100,6 +3059,7 @@ int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv) return -ENOMEM; filp_priv->driver_priv = radeon_priv; + if (dev_priv) radeon_priv->radeon_fb_delta = dev_priv->fb_location; else -- cgit v1.2.3 From 4e4c62bd45c40e8e04d09a5f383bffb149abaa63 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Jan 2006 22:25:29 +1100 Subject: drm: remove is_pci flag completely... this snuck back in, in the last merge. Signed-off-by: Dave Airlie --- drivers/char/drm/radeon_drv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index fac0d5196ce3..498b19b1d641 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -273,7 +273,6 @@ typedef struct drm_radeon_private { /* starting from here on, data is preserved accross an open */ uint32_t flags; /* see radeon_chip_flags */ - int is_pci; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { -- cgit v1.2.3 From 9d4f13e531b4722fe40cc8e28c02a495bdd49267 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 3 Jan 2006 17:28:33 +0000 Subject: [ARM] Make kernel link address depend on PAGE_OFFSET We are coding the kernel link address into the makefiles, which is invisibly dependent on PAGE_OFFSET. If PAGE_OFFSET is changed, the makefiles also need to be changed. Make adjustments such that the makefiles encode just the offset from PAGE_OFFSET for the kernel link address, and use PAGE_OFFSET in the linker scripts directly. Signed-off-by: Russell King --- arch/arm/Makefile | 15 +++++++-------- arch/arm/boot/Makefile | 2 +- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/head.S | 2 ++ arch/arm/kernel/vmlinux.lds.S | 12 +++++------- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 81bd2193fe6d..afaf3a1e903c 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -8,7 +8,7 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=-p --no-undefined -X -CPPFLAGS_vmlinux.lds = -DKERNEL_RAM_ADDR=$(TEXTADDR) +CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) OBJCOPYFLAGS :=-O binary -R .note -R .comment -S GZFLAGS :=-9 #CFLAGS +=-pipe @@ -65,7 +65,7 @@ CHECKFLAGS += -D__arm__ #Default value head-y := arch/arm/kernel/head.o arch/arm/kernel/init_task.o -textaddr-y := 0xC0008000 +textofs-y := 0x00008000 machine-$(CONFIG_ARCH_RPC) := rpc machine-$(CONFIG_ARCH_EBSA110) := ebsa110 @@ -73,22 +73,20 @@ textaddr-y := 0xC0008000 incdir-$(CONFIG_ARCH_CLPS7500) := cl7500 machine-$(CONFIG_FOOTBRIDGE) := footbridge incdir-$(CONFIG_FOOTBRIDGE) := ebsa285 -textaddr-$(CONFIG_ARCH_CO285) := 0x60008000 machine-$(CONFIG_ARCH_CO285) := footbridge incdir-$(CONFIG_ARCH_CO285) := ebsa285 machine-$(CONFIG_ARCH_SHARK) := shark machine-$(CONFIG_ARCH_SA1100) := sa1100 ifeq ($(CONFIG_ARCH_SA1100),y) # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory -textaddr-$(CONFIG_SA1111) := 0xc0208000 + textofs-$(CONFIG_SA1111) := 0x00208000 endif machine-$(CONFIG_ARCH_PXA) := pxa machine-$(CONFIG_ARCH_L7200) := l7200 machine-$(CONFIG_ARCH_INTEGRATOR) := integrator machine-$(CONFIG_ARCH_CAMELOT) := epxa10db -textaddr-$(CONFIG_ARCH_CLPS711X) := 0xc0028000 + textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 machine-$(CONFIG_ARCH_CLPS711X) := clps711x -textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 machine-$(CONFIG_ARCH_IOP3XX) := iop3xx machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx machine-$(CONFIG_ARCH_IXP2000) := ixp2000 @@ -110,7 +108,8 @@ CFLAGS_3c589_cs.o :=-DISA_SIXTEEN_BIT_PERIPHERAL export CFLAGS_3c589_cs.o endif -TEXTADDR := $(textaddr-y) +# The byte offset of the kernel image in RAM from the start of RAM. +TEXT_OFFSET := $(textofs-y) ifeq ($(incdir-y),) incdir-y := $(machine-y) @@ -123,7 +122,7 @@ else MACHINE := endif -export TEXTADDR GZFLAGS +export TEXT_OFFSET GZFLAGS # Do we have FASTFPE? FASTFPE :=arch/arm/fastfpe diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 937a353bc37c..a174d63395ea 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -15,7 +15,7 @@ include $(srctree)/$(MACHINE)/Makefile.boot endif # Note: the following conditions must always be true: -# ZRELADDR == virt_to_phys(TEXTADDR) +# ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET) # PARAMS_PHYS must be within 4MB of ZRELADDR # INITRD_PHYS must be in RAM ZRELADDR := $(zreladdr-y) diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index c11169b5ed9a..25b14c3fdc4a 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -AFLAGS_head.o := -DKERNEL_RAM_ADDR=$(TEXTADDR) +AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Object file lists. diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index d7d69fd7039f..1e985f2cd70f 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -33,6 +33,8 @@ #define MACHINFO_PGOFFIO 12 #define MACHINFO_NAME 16 +#define KERNEL_RAM_ADDR (PAGE_OFFSET + TEXT_OFFSET) + /* * swapper_pg_dir is the virtual address of the initial page table. * We place the page tables 16K below KERNEL_RAM_ADDR. Therefore, we must diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 9a47770114d4..2b254e88595c 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -17,15 +17,13 @@ jiffies = jiffies_64; jiffies = jiffies_64 + 4; #endif +SECTIONS +{ #ifdef CONFIG_XIP_KERNEL -#define TEXTADDR XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR) + . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR); #else -#define TEXTADDR KERNEL_RAM_ADDR + . = PAGE_OFFSET + TEXT_OFFSET; #endif - -SECTIONS -{ - . = TEXTADDR; .init : { /* Init code and data */ _stext = .; _sinittext = .; @@ -104,7 +102,7 @@ SECTIONS #ifdef CONFIG_XIP_KERNEL __data_loc = ALIGN(4); /* location in binary */ - . = KERNEL_RAM_ADDR; + . = PAGE_OFFSET + TEXT_OFFSET; #else . = ALIGN(THREAD_SIZE); __data_loc = .; -- cgit v1.2.3 From 78ff18a412da24a4b79c6a97000ef5e467e813da Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 3 Jan 2006 17:39:34 +0000 Subject: [ARM] Cleanup ARM includes arch/arm/kernel/entry-armv.S has contained a comment suggesting that asm/hardware.h and asm/arch/irqs.h should be moved into the asm/arch/entry-macro.S include. So move the includes to these two files as required. Add missing includes (asm/hardware.h, asm/io.h) to asm/arch/system.h includes which use those facilities, and remove asm/io.h from kernel/process.c. Remove other unnecessary includes from arch/arm/kernel, arch/arm/mm and arch/arm/mach-footbridge. Signed-off-by: Russell King --- arch/arm/kernel/dma.c | 2 -- arch/arm/kernel/entry-armv.S | 2 -- arch/arm/kernel/process.c | 3 +-- arch/arm/kernel/setup.c | 2 -- arch/arm/kernel/time.c | 3 --- arch/arm/kernel/traps.c | 1 - arch/arm/mach-footbridge/dma.c | 1 + arch/arm/mm/consistent.c | 1 - arch/arm/mm/discontig.c | 4 +--- arch/arm/mm/mm-armv.c | 1 - include/asm-arm/arch-cl7500/entry-macro.S | 2 +- include/asm-arm/arch-clps711x/entry-macro.S | 1 + include/asm-arm/arch-clps711x/system.h | 2 ++ include/asm-arm/arch-ebsa285/entry-macro.S | 2 ++ include/asm-arm/arch-imx/entry-macro.S | 2 ++ include/asm-arm/arch-integrator/entry-macro.S | 2 ++ include/asm-arm/arch-iop3xx/entry-macro.S | 1 + include/asm-arm/arch-ixp2000/entry-macro.S | 1 + include/asm-arm/arch-ixp4xx/entry-macro.S | 1 + include/asm-arm/arch-l7200/system.h | 2 ++ include/asm-arm/arch-lh7a40x/entry-macro.S | 2 ++ include/asm-arm/arch-omap/entry-macro.S | 2 ++ include/asm-arm/arch-pxa/entry-macro.S | 2 ++ include/asm-arm/arch-realview/entry-macro.S | 2 +- include/asm-arm/arch-rpc/entry-macro.S | 2 +- include/asm-arm/arch-s3c2410/entry-macro.S | 2 ++ include/asm-arm/arch-versatile/entry-macro.S | 4 +++- include/asm-arm/cacheflush.h | 1 - 28 files changed, 31 insertions(+), 22 deletions(-) diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 2b7883884234..8d6381cd8915 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -12,8 +12,6 @@ * DMA facilities. */ #include -#include -#include #include #include #include diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2a8d27e18fa7..a52baedf6262 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -18,8 +18,6 @@ #include #include #include -#include /* should be moved into entry-macro.S */ -#include /* should be moved into entry-macro.S */ #include #include "entry-header.S" diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 30494aab829a..54a21bdcba5c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -28,10 +28,9 @@ #include #include -#include -#include #include #include +#include #include #include diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 85774165e9fd..2cab741ad0f8 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -26,8 +26,6 @@ #include #include -#include -#include #include #include #include diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index fc4729106a32..d7d932c02866 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -29,9 +29,6 @@ #include #include -#include -#include -#include #include #include #include diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 45e9ea6cd2a5..c9fe6f5f7ee3 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-footbridge/dma.c b/arch/arm/mach-footbridge/dma.c index a6b1396b0951..7a54578b51af 100644 --- a/arch/arm/mach-footbridge/dma.c +++ b/arch/arm/mach-footbridge/dma.c @@ -15,6 +15,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index dbfe9e891f01..0513ed1b2fcf 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -19,7 +19,6 @@ #include #include -#include #include #define CONSISTENT_BASE (0xffc00000) diff --git a/arch/arm/mm/discontig.c b/arch/arm/mm/discontig.c index 0d097bb1bc4d..1e5602189507 100644 --- a/arch/arm/mm/discontig.c +++ b/arch/arm/mm/discontig.c @@ -9,10 +9,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - #include -#include -#include +#include #include #if MAX_NUMNODES != 4 && MAX_NUMNODES != 16 diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 9e50127be635..d0245a31d4dd 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -19,7 +19,6 @@ #include #include -#include #include #include diff --git a/include/asm-arm/arch-cl7500/entry-macro.S b/include/asm-arm/arch-cl7500/entry-macro.S index 686f413f82d6..c9e5395e5106 100644 --- a/include/asm-arm/arch-cl7500/entry-macro.S +++ b/include/asm-arm/arch-cl7500/entry-macro.S @@ -1,3 +1,3 @@ - +#include #include diff --git a/include/asm-arm/arch-clps711x/entry-macro.S b/include/asm-arm/arch-clps711x/entry-macro.S index b31079a1d4a9..21f6ee485819 100644 --- a/include/asm-arm/arch-clps711x/entry-macro.S +++ b/include/asm-arm/arch-clps711x/entry-macro.S @@ -7,6 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include #include .macro disable_fiq diff --git a/include/asm-arm/arch-clps711x/system.h b/include/asm-arm/arch-clps711x/system.h index 2ab981fee37f..11e1491535a8 100644 --- a/include/asm-arm/arch-clps711x/system.h +++ b/include/asm-arm/arch-clps711x/system.h @@ -20,7 +20,9 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H +#include #include +#include static inline void arch_idle(void) { diff --git a/include/asm-arm/arch-ebsa285/entry-macro.S b/include/asm-arm/arch-ebsa285/entry-macro.S index db5729ff6349..cf10ac96fdde 100644 --- a/include/asm-arm/arch-ebsa285/entry-macro.S +++ b/include/asm-arm/arch-ebsa285/entry-macro.S @@ -7,6 +7,8 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include +#include #include .macro disable_fiq diff --git a/include/asm-arm/arch-imx/entry-macro.S b/include/asm-arm/arch-imx/entry-macro.S index b40ea7cf88ec..3b9ef6914627 100644 --- a/include/asm-arm/arch-imx/entry-macro.S +++ b/include/asm-arm/arch-imx/entry-macro.S @@ -7,6 +7,8 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include + .macro disable_fiq .endm #define AITC_NIVECSR 0x40 diff --git a/include/asm-arm/arch-integrator/entry-macro.S b/include/asm-arm/arch-integrator/entry-macro.S index 44f7ee613194..69838d04f90b 100644 --- a/include/asm-arm/arch-integrator/entry-macro.S +++ b/include/asm-arm/arch-integrator/entry-macro.S @@ -7,6 +7,8 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include +#include .macro disable_fiq .endm diff --git a/include/asm-arm/arch-iop3xx/entry-macro.S b/include/asm-arm/arch-iop3xx/entry-macro.S index e2ce7f5467c8..926668c098a5 100644 --- a/include/asm-arm/arch-iop3xx/entry-macro.S +++ b/include/asm-arm/arch-iop3xx/entry-macro.S @@ -7,6 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include #if defined(CONFIG_ARCH_IOP321) .macro disable_fiq diff --git a/include/asm-arm/arch-ixp2000/entry-macro.S b/include/asm-arm/arch-ixp2000/entry-macro.S index e3a4e4121298..16e1e6124b31 100644 --- a/include/asm-arm/arch-ixp2000/entry-macro.S +++ b/include/asm-arm/arch-ixp2000/entry-macro.S @@ -7,6 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include .macro disable_fiq .endm diff --git a/include/asm-arm/arch-ixp4xx/entry-macro.S b/include/asm-arm/arch-ixp4xx/entry-macro.S index 323b0bc4a39c..27e124132e4c 100644 --- a/include/asm-arm/arch-ixp4xx/entry-macro.S +++ b/include/asm-arm/arch-ixp4xx/entry-macro.S @@ -7,6 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include .macro disable_fiq .endm diff --git a/include/asm-arm/arch-l7200/system.h b/include/asm-arm/arch-l7200/system.h index cb4ff29059b8..18825cf071ba 100644 --- a/include/asm-arm/arch-l7200/system.h +++ b/include/asm-arm/arch-l7200/system.h @@ -12,6 +12,8 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H +#include + static inline void arch_idle(void) { *(unsigned long *)(IO_BASE + 0x50004) = 1; /* idle mode */ diff --git a/include/asm-arm/arch-lh7a40x/entry-macro.S b/include/asm-arm/arch-lh7a40x/entry-macro.S index 865f396aa63c..a2f67c06d9c9 100644 --- a/include/asm-arm/arch-lh7a40x/entry-macro.S +++ b/include/asm-arm/arch-lh7a40x/entry-macro.S @@ -7,6 +7,8 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include +#include # if defined (CONFIG_ARCH_LH7A400) && defined (CONFIG_ARCH_LH7A404) # error "LH7A400 and LH7A404 are mutually exclusive" diff --git a/include/asm-arm/arch-omap/entry-macro.S b/include/asm-arm/arch-omap/entry-macro.S index f8814a84910e..0ffb1185f1ac 100644 --- a/include/asm-arm/arch-omap/entry-macro.S +++ b/include/asm-arm/arch-omap/entry-macro.S @@ -7,6 +7,8 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include +#include #if defined(CONFIG_ARCH_OMAP1) diff --git a/include/asm-arm/arch-pxa/entry-macro.S b/include/asm-arm/arch-pxa/entry-macro.S index 2abfc8bb3ee5..4985e33afc12 100644 --- a/include/asm-arm/arch-pxa/entry-macro.S +++ b/include/asm-arm/arch-pxa/entry-macro.S @@ -7,6 +7,8 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include +#include .macro disable_fiq .endm diff --git a/include/asm-arm/arch-realview/entry-macro.S b/include/asm-arm/arch-realview/entry-macro.S index 6288fad0dc41..1a6eec86bd47 100644 --- a/include/asm-arm/arch-realview/entry-macro.S +++ b/include/asm-arm/arch-realview/entry-macro.S @@ -7,7 +7,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ - +#include #include .macro disable_fiq diff --git a/include/asm-arm/arch-rpc/entry-macro.S b/include/asm-arm/arch-rpc/entry-macro.S index 686f413f82d6..c9e5395e5106 100644 --- a/include/asm-arm/arch-rpc/entry-macro.S +++ b/include/asm-arm/arch-rpc/entry-macro.S @@ -1,3 +1,3 @@ - +#include #include diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S index b7d4d7f4422d..cc06b1bd37b2 100644 --- a/include/asm-arm/arch-s3c2410/entry-macro.S +++ b/include/asm-arm/arch-s3c2410/entry-macro.S @@ -10,6 +10,8 @@ * Modifications: * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ +#include +#include .macro get_irqnr_and_base, irqnr, irqstat, base, tmp diff --git a/include/asm-arm/arch-versatile/entry-macro.S b/include/asm-arm/arch-versatile/entry-macro.S index 90e4e970d253..58f0d71759f6 100644 --- a/include/asm-arm/arch-versatile/entry-macro.S +++ b/include/asm-arm/arch-versatile/entry-macro.S @@ -7,7 +7,9 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ - .macro disable_fiq +#include + + .macro disable_fiq .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index e81baff4f54b..09e19a783a51 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -14,7 +14,6 @@ #include #include -#include #include #include -- cgit v1.2.3 From f47fc0ac7ead5ed91a11fcabfad6ee44c17ee934 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 3 Jan 2006 18:34:20 +0000 Subject: [ARM] Add additional documentation to the clock source framework It seems that there's some confusion over how the clock source framework should be used. Add some additional comments to explain the ambiguous areas. Signed-off-by: Russell King --- include/asm-arm/hardware/clock.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h index 19da861e523d..5c5689409a4b 100644 --- a/include/asm-arm/hardware/clock.h +++ b/include/asm-arm/hardware/clock.h @@ -33,6 +33,8 @@ struct clk; * uses @dev and @id to determine the clock consumer, and thereby * the clock producer. (IOW, @id may be identical strings, but * clk_get may return different clock producers depending on @dev.) + * + * Drivers must assume that the clock source is not enabled. */ struct clk *clk_get(struct device *dev, const char *id); @@ -49,6 +51,14 @@ int clk_enable(struct clk *clk); /** * clk_disable - inform the system when the clock source is no longer required. * @clk: clock source + * + * Inform the system that a clock source is no longer required by + * a driver and may be shut down. + * + * Implementation detail: if the clock source is shared between + * multiple drivers, clk_enable() calls must be balanced by the + * same number of clk_disable() calls for the clock source to be + * disabled. */ void clk_disable(struct clk *clk); @@ -76,6 +86,10 @@ unsigned long clk_get_rate(struct clk *clk); /** * clk_put - "free" the clock source * @clk: clock source + * + * Note: drivers must ensure that all clk_enable calls made on this + * clock source are balanced by clk_disable calls prior to calling + * this function. */ void clk_put(struct clk *clk); -- cgit v1.2.3 From a8d3584a2df28827094f6338cde1303c467bc1f0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 3 Jan 2006 18:41:37 +0000 Subject: [ARM] Remove clk_use()/clk_unuse() It seems that clk_use() and clk_unuse() are additional complexity which isn't required anymore. Remove them from the clock framework to avoid the additional confusion which they cause, and update all ARM machine types except for OMAP. Signed-off-by: Russell King --- arch/arm/mach-aaec2000/clock.c | 11 ----------- arch/arm/mach-integrator/clock.c | 11 ----------- arch/arm/mach-realview/clock.c | 11 ----------- arch/arm/mach-s3c2410/clock.c | 15 --------------- arch/arm/mach-s3c2410/clock.h | 1 - arch/arm/mach-s3c2410/time.c | 1 - arch/arm/mach-versatile/clock.c | 11 ----------- drivers/char/watchdog/s3c2410_wdt.c | 2 -- drivers/i2c/busses/i2c-s3c2410.c | 2 -- drivers/input/serio/ambakmi.c | 9 +-------- drivers/mmc/mmci.c | 9 +-------- drivers/mtd/nand/s3c2410.c | 2 -- drivers/serial/amba-pl011.c | 7 ------- drivers/serial/s3c2410.c | 5 ----- drivers/usb/host/ohci-s3c2410.c | 2 -- drivers/video/amba-clcd.c | 9 +-------- drivers/video/s3c2410fb.c | 3 --- include/asm-arm/hardware/clock.h | 14 -------------- 18 files changed, 3 insertions(+), 122 deletions(-) diff --git a/arch/arm/mach-aaec2000/clock.c b/arch/arm/mach-aaec2000/clock.c index 0340ddc4824e..828208348b76 100644 --- a/arch/arm/mach-aaec2000/clock.c +++ b/arch/arm/mach-aaec2000/clock.c @@ -58,17 +58,6 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); -int clk_use(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_use); - -void clk_unuse(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_unuse); - unsigned long clk_get_rate(struct clk *clk) { return clk->rate; diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c index 73c360685cad..bbfe46cd91fe 100644 --- a/arch/arm/mach-integrator/clock.c +++ b/arch/arm/mach-integrator/clock.c @@ -58,17 +58,6 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); -int clk_use(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_use); - -void clk_unuse(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_unuse); - unsigned long clk_get_rate(struct clk *clk) { return clk->rate; diff --git a/arch/arm/mach-realview/clock.c b/arch/arm/mach-realview/clock.c index 002635c97bb6..331e1b483aa7 100644 --- a/arch/arm/mach-realview/clock.c +++ b/arch/arm/mach-realview/clock.c @@ -57,17 +57,6 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); -int clk_use(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_use); - -void clk_unuse(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_unuse); - unsigned long clk_get_rate(struct clk *clk) { return clk->rate; diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index 82e8253b1fa0..77f321fac281 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -151,18 +151,6 @@ void clk_disable(struct clk *clk) } -int clk_use(struct clk *clk) -{ - atomic_inc(&clk->used); - return 0; -} - - -void clk_unuse(struct clk *clk) -{ - atomic_dec(&clk->used); -} - unsigned long clk_get_rate(struct clk *clk) { if (IS_ERR(clk)) @@ -196,8 +184,6 @@ EXPORT_SYMBOL(clk_get); EXPORT_SYMBOL(clk_put); EXPORT_SYMBOL(clk_enable); EXPORT_SYMBOL(clk_disable); -EXPORT_SYMBOL(clk_use); -EXPORT_SYMBOL(clk_unuse); EXPORT_SYMBOL(clk_get_rate); EXPORT_SYMBOL(clk_round_rate); EXPORT_SYMBOL(clk_set_rate); @@ -370,7 +356,6 @@ static struct clk init_clocks[] = { int s3c24xx_register_clock(struct clk *clk) { clk->owner = THIS_MODULE; - atomic_set(&clk->used, 0); if (clk->enable == NULL) clk->enable = clk_null_enable; diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h index 7953b6f397b9..177d5c8decf7 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/arch/arm/mach-s3c2410/clock.h @@ -16,7 +16,6 @@ struct clk { struct clk *parent; const char *name; int id; - atomic_t used; unsigned long rate; unsigned long ctrlbit; int (*enable)(struct clk *, int enable); diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c index 8a00e3c3cd08..9acda44b25a6 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/mach-s3c2410/time.c @@ -191,7 +191,6 @@ static void s3c2410_timer_setup (void) if (IS_ERR(clk)) panic("failed to get clock for system timer"); - clk_use(clk); clk_enable(clk); pclk = clk_get_rate(clk); diff --git a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c index b96a2ea15d41..ada3142da8dc 100644 --- a/arch/arm/mach-versatile/clock.c +++ b/arch/arm/mach-versatile/clock.c @@ -58,17 +58,6 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); -int clk_use(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_use); - -void clk_unuse(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_unuse); - unsigned long clk_get_rate(struct clk *clk) { return clk->rate; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index eb667daee19b..621e8a99e733 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -397,7 +397,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) return -ENOENT; } - clk_use(wdt_clock); clk_enable(wdt_clock); /* see if we can actually set the requested timer margin, and if @@ -444,7 +443,6 @@ static int s3c2410wdt_remove(struct platform_device *dev) if (wdt_clock != NULL) { clk_disable(wdt_clock); - clk_unuse(wdt_clock); clk_put(wdt_clock); wdt_clock = NULL; } diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 58cfd3111ef6..2a2f86d8c2d8 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -738,7 +738,6 @@ static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c) { if (i2c->clk != NULL && !IS_ERR(i2c->clk)) { clk_disable(i2c->clk); - clk_unuse(i2c->clk); clk_put(i2c->clk); i2c->clk = NULL; } @@ -778,7 +777,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); - clk_use(i2c->clk); clk_enable(i2c->clk); /* map the registers */ diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 9b1ab5e7a98d..d847ed51cfb1 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -72,13 +72,9 @@ static int amba_kmi_open(struct serio *io) unsigned int divisor; int ret; - ret = clk_use(kmi->clk); - if (ret) - goto out; - ret = clk_enable(kmi->clk); if (ret) - goto clk_unuse; + goto out; divisor = clk_get_rate(kmi->clk) / 8000000 - 1; writeb(divisor, KMICLKDIV); @@ -97,8 +93,6 @@ static int amba_kmi_open(struct serio *io) clk_disable: clk_disable(kmi->clk); - clk_unuse: - clk_unuse(kmi->clk); out: return ret; } @@ -111,7 +105,6 @@ static void amba_kmi_close(struct serio *io) free_irq(kmi->irq, kmi); clk_disable(kmi->clk); - clk_unuse(kmi->clk); } static int amba_kmi_probe(struct amba_device *dev, void *id) diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 166c9b0ad04e..31b0b6d612bf 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -479,13 +479,9 @@ static int mmci_probe(struct amba_device *dev, void *id) goto host_free; } - ret = clk_use(host->clk); - if (ret) - goto clk_free; - ret = clk_enable(host->clk); if (ret) - goto clk_unuse; + goto clk_free; host->plat = plat; host->mclk = clk_get_rate(host->clk); @@ -558,8 +554,6 @@ static int mmci_probe(struct amba_device *dev, void *id) iounmap(host->base); clk_disable: clk_disable(host->clk); - clk_unuse: - clk_unuse(host->clk); clk_free: clk_put(host->clk); host_free: @@ -594,7 +588,6 @@ static int mmci_remove(struct amba_device *dev) iounmap(host->base); clk_disable(host->clk); - clk_unuse(host->clk); clk_put(host->clk); mmc_free_host(mmc); diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d209214b1318..b796a9a6b924 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -460,7 +460,6 @@ static int s3c2410_nand_remove(struct platform_device *pdev) if (info->clk != NULL && !IS_ERR(info->clk)) { clk_disable(info->clk); - clk_unuse(info->clk); clk_put(info->clk); } @@ -598,7 +597,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440) goto exit_error; } - clk_use(info->clk); clk_enable(info->clk); /* allocate and map the resource */ diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index d84476ee6592..531b0e4f25e5 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -761,10 +761,6 @@ static int pl011_probe(struct amba_device *dev, void *id) goto unmap; } - ret = clk_use(uap->clk); - if (ret) - goto putclk; - uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; @@ -782,8 +778,6 @@ static int pl011_probe(struct amba_device *dev, void *id) if (ret) { amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; - clk_unuse(uap->clk); - putclk: clk_put(uap->clk); unmap: iounmap(base); @@ -808,7 +802,6 @@ static int pl011_remove(struct amba_device *dev) amba_ports[i] = NULL; iounmap(uap->port.membase); - clk_unuse(uap->clk); clk_put(uap->clk); kfree(uap); return 0; diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 47681c4654e4..eb47f5b71aeb 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -782,11 +782,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { clk_disable(ourport->baudclk); - clk_unuse(ourport->baudclk); ourport->baudclk = NULL; } - clk_use(clk); clk_enable(clk); ourport->clksrc = clksrc; @@ -1077,9 +1075,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->clk = clk_get(&platdev->dev, "uart"); - if (ourport->clk != NULL && !IS_ERR(ourport->clk)) - clk_use(ourport->clk); - dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n", port->mapbase, port->membase, port->irq, port->uartclk); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 35cc9402adc0..add198a4be79 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -363,7 +363,6 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver, goto err1; } - clk_use(clk); s3c2410_start_hc(dev, hcd); hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); @@ -384,7 +383,6 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver, err2: s3c2410_stop_hc(dev); iounmap(hcd->regs); - clk_unuse(clk); clk_put(clk); err1: diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index a3c2c45e29e0..69421c86252c 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -346,10 +346,6 @@ static int clcdfb_register(struct clcd_fb *fb) goto out; } - ret = clk_use(fb->clk); - if (ret) - goto free_clk; - fb->fb.fix.mmio_start = fb->dev->res.start; fb->fb.fix.mmio_len = SZ_4K; @@ -357,7 +353,7 @@ static int clcdfb_register(struct clcd_fb *fb) if (!fb->regs) { printk(KERN_ERR "CLCD: unable to remap registers\n"); ret = -ENOMEM; - goto unuse_clk; + goto free_clk; } fb->fb.fbops = &clcdfb_ops; @@ -427,8 +423,6 @@ static int clcdfb_register(struct clcd_fb *fb) printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); iounmap(fb->regs); - unuse_clk: - clk_unuse(fb->clk); free_clk: clk_put(fb->clk); out: @@ -489,7 +483,6 @@ static int clcdfb_remove(struct amba_device *dev) clcdfb_disable(fb); unregister_framebuffer(&fb->fb); iounmap(fb->regs); - clk_unuse(fb->clk); clk_put(fb->clk); fb->board->remove(fb); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ce6e749db3a7..d9c08cc7ac44 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -746,7 +746,6 @@ int __init s3c2410fb_probe(struct platform_device *pdev) goto release_irq; } - clk_use(info->clk); clk_enable(info->clk); dprintk("got and enabled clock\n"); @@ -783,7 +782,6 @@ free_video_memory: s3c2410fb_unmap_video_memory(info); release_clock: clk_disable(info->clk); - clk_unuse(info->clk); clk_put(info->clk); release_irq: free_irq(irq,info); @@ -828,7 +826,6 @@ static int s3c2410fb_remove(struct platform_device *pdev) if (info->clk) { clk_disable(info->clk); - clk_unuse(info->clk); clk_put(info->clk); info->clk = NULL; } diff --git a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h index 5c5689409a4b..69f33215e437 100644 --- a/include/asm-arm/hardware/clock.h +++ b/include/asm-arm/hardware/clock.h @@ -62,20 +62,6 @@ int clk_enable(struct clk *clk); */ void clk_disable(struct clk *clk); -/** - * clk_use - increment the use count - * @clk: clock source - * - * Returns success (0) or negative errno. - */ -int clk_use(struct clk *clk); - -/** - * clk_unuse - decrement the use count - * @clk: clock source - */ -void clk_unuse(struct clk *clk); - /** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. -- cgit v1.2.3 From dacd9b80355525be0e3c519687868410e304ad1c Mon Sep 17 00:00:00 2001 From: Yu Luming Date: Sat, 31 Dec 2005 01:45:00 -0500 Subject: [ACPI] fix acpi_os_wait_sempahore() finite timeout case (AE_TIME warning) Before this fix, the finite timeout case behaved like the no-timeout (trylock) case. http://bugzilla.kernel.org/show_bug.cgi?id=4588 Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/osl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e3cd0b16031a..8653dac01a76 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -836,7 +836,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) static const int quantum_ms = 1000 / HZ; ret = down_trylock(sem); - for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { + for (i = timeout; (i > 0 && ret != 0); i -= quantum_ms) { schedule_timeout_interruptible(1); ret = down_trylock(sem); } -- cgit v1.2.3 From a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2cc Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 3 Jan 2006 22:38:44 +0000 Subject: [MMC] Improve MMC card block size selection Select a block size for IO based on the read and write block size combinations, and whether the card supports partial block reads and/or partial block writes. If we are able to satisfy block reads but not block writes, mark the device read only. Signed-off-by: Russell King --- drivers/mmc/mmc.c | 10 +++ drivers/mmc/mmc_block.c | 175 ++++++++++++++++++++++++++++++----------------- include/linux/mmc/card.h | 5 ++ 3 files changed, 128 insertions(+), 62 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index eb41391e06e9..6696f71363b9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -550,6 +550,11 @@ static void mmc_decode_csd(struct mmc_card *card) csd->capacity = (1 + m) << (e + 2); csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } else { /* * We only understand CSD structure v1.1 and v1.2. @@ -579,6 +584,11 @@ static void mmc_decode_csd(struct mmc_card *card) csd->capacity = (1 + m) << (e + 2); csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } } diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index abcf19116d70..b9837cc5b9ac 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -54,6 +54,7 @@ struct mmc_blk_data { unsigned int usage; unsigned int block_bits; + unsigned int read_only; }; static DECLARE_MUTEX(open_lock); @@ -85,12 +86,6 @@ static void mmc_blk_put(struct mmc_blk_data *md) up(&open_lock); } -static inline int mmc_blk_readonly(struct mmc_card *card) -{ - return mmc_card_readonly(card) || - !(card->csd.cmdclass & CCC_BLOCK_WRITE); -} - static int mmc_blk_open(struct inode *inode, struct file *filp) { struct mmc_blk_data *md; @@ -102,8 +97,7 @@ static int mmc_blk_open(struct inode *inode, struct file *filp) check_disk_change(inode->i_bdev); ret = 0; - if ((filp->f_mode & FMODE_WRITE) && - mmc_blk_readonly(md->queue.card)) + if ((filp->f_mode & FMODE_WRITE) && md->read_only) ret = -EROFS; } @@ -299,6 +293,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; +static inline int mmc_blk_readonly(struct mmc_card *card) +{ + return mmc_card_readonly(card) || + !(card->csd.cmdclass & CCC_BLOCK_WRITE); +} + static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) { struct mmc_blk_data *md; @@ -310,64 +310,121 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) __set_bit(devidx, dev_use); md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); - if (md) { - memset(md, 0, sizeof(struct mmc_blk_data)); + if (!md) { + ret = -ENOMEM; + goto out; + } - md->disk = alloc_disk(1 << MMC_SHIFT); - if (md->disk == NULL) { - kfree(md); - md = ERR_PTR(-ENOMEM); - goto out; - } + memset(md, 0, sizeof(struct mmc_blk_data)); - spin_lock_init(&md->lock); - md->usage = 1; + /* + * Set the read-only status based on the supported commands + * and the write protect switch. + */ + md->read_only = mmc_blk_readonly(card); - ret = mmc_init_queue(&md->queue, card, &md->lock); - if (ret) { - put_disk(md->disk); - kfree(md); - md = ERR_PTR(ret); - goto out; + /* + * Figure out a workable block size. MMC cards have: + * - two block sizes, one for read and one for write. + * - may support partial reads and/or writes + * (allows block sizes smaller than specified) + */ + md->block_bits = card->csd.read_blkbits; + if (card->csd.write_blkbits != card->csd.read_blkbits) { + if (card->csd.write_blkbits < card->csd.read_blkbits && + card->csd.read_partial) { + /* + * write block size is smaller than read block + * size, but we support partial reads, so choose + * the smaller write block size. + */ + md->block_bits = card->csd.write_blkbits; + } else if (card->csd.write_blkbits > card->csd.read_blkbits && + card->csd.write_partial) { + /* + * read block size is smaller than write block + * size, but we support partial writes. Use read + * block size. + */ + } else { + /* + * We don't support this configuration for writes. + */ + printk(KERN_ERR "%s: unable to select block size for " + "writing (rb%u wb%u rp%u wp%u)\n", + md->disk->disk_name, + 1 << card->csd.read_blkbits, + 1 << card->csd.write_blkbits, + card->csd.read_partial, + card->csd.write_partial); + md->read_only = 1; } - md->queue.prep_fn = mmc_blk_prep_rq; - md->queue.issue_fn = mmc_blk_issue_rq; - md->queue.data = md; + } - md->disk->major = major; - md->disk->first_minor = devidx << MMC_SHIFT; - md->disk->fops = &mmc_bdops; - md->disk->private_data = md; - md->disk->queue = md->queue.queue; - md->disk->driverfs_dev = &card->dev; + /* + * Refuse to allow block sizes smaller than 512 bytes. + */ + if (md->block_bits < 9) { + printk(KERN_ERR "%s: unable to support block size %u\n", + mmc_card_id(card), 1 << md->block_bits); + ret = -EINVAL; + goto err_kfree; + } - /* - * As discussed on lkml, GENHD_FL_REMOVABLE should: - * - * - be set for removable media with permanent block devices - * - be unset for removable block devices with permanent media - * - * Since MMC block devices clearly fall under the second - * case, we do not set GENHD_FL_REMOVABLE. Userspace - * should use the block device creation/destruction hotplug - * messages to tell when the card is present. - */ + md->disk = alloc_disk(1 << MMC_SHIFT); + if (md->disk == NULL) { + ret = -ENOMEM; + goto err_kfree; + } - sprintf(md->disk->disk_name, "mmcblk%d", devidx); - sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); + spin_lock_init(&md->lock); + md->usage = 1; - md->block_bits = card->csd.read_blkbits; + ret = mmc_init_queue(&md->queue, card, &md->lock); + if (ret) + goto err_putdisk; - blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); + md->queue.prep_fn = mmc_blk_prep_rq; + md->queue.issue_fn = mmc_blk_issue_rq; + md->queue.data = md; - /* - * The CSD capacity field is in units of read_blkbits. - * set_capacity takes units of 512 bytes. - */ - set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); - } - out: + md->disk->major = major; + md->disk->first_minor = devidx << MMC_SHIFT; + md->disk->fops = &mmc_bdops; + md->disk->private_data = md; + md->disk->queue = md->queue.queue; + md->disk->driverfs_dev = &card->dev; + + /* + * As discussed on lkml, GENHD_FL_REMOVABLE should: + * + * - be set for removable media with permanent block devices + * - be unset for removable block devices with permanent media + * + * Since MMC block devices clearly fall under the second + * case, we do not set GENHD_FL_REMOVABLE. Userspace + * should use the block device creation/destruction hotplug + * messages to tell when the card is present. + */ + + sprintf(md->disk->disk_name, "mmcblk%d", devidx); + sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); + + blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); + + /* + * The CSD capacity field is in units of read_blkbits. + * set_capacity takes units of 512 bytes. + */ + set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); return md; + + err_putdisk: + put_disk(md->disk); + err_kfree: + kfree(md); + out: + return ERR_PTR(ret); } static int @@ -403,12 +460,6 @@ static int mmc_blk_probe(struct mmc_card *card) if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; - if (card->csd.read_blkbits < 9) { - printk(KERN_WARNING "%s: read blocksize too small (%u)\n", - mmc_card_id(card), 1 << card->csd.read_blkbits); - return -ENODEV; - } - md = mmc_blk_alloc(card); if (IS_ERR(md)) return PTR_ERR(md); @@ -419,7 +470,7 @@ static int mmc_blk_probe(struct mmc_card *card) printk(KERN_INFO "%s: %s %s %luKiB %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), - get_capacity(md->disk) >> 1, mmc_blk_readonly(card)?"(ro)":""); + get_capacity(md->disk) >> 1, md->read_only ? "(ro)" : ""); mmc_set_drvdata(card, md); add_disk(md->disk); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 18fc77f682de..7f7d40684288 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -30,7 +30,12 @@ struct mmc_csd { unsigned int tacc_ns; unsigned int max_dtr; unsigned int read_blkbits; + unsigned int write_blkbits; unsigned int capacity; + unsigned int read_partial:1, + read_misalign:1, + write_partial:1 + write_misalign:1; }; struct sd_scr { -- cgit v1.2.3 From 63648fb5c0173614064e329503cc75c907dcb1a1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 3 Jan 2006 22:56:56 +0000 Subject: [MMC] wbsd: make use of ARRAY_SIZE() macro Signed-off-by: Dmitry Torokhov Acked-by: Pierre Ossman --- drivers/mmc/wbsd.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index c7eb7c269081..9df0ddeb3ff9 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1456,13 +1456,11 @@ static int __devinit wbsd_scan(struct wbsd_host* host) * Iterate through all ports, all codes to * find hardware that is in our known list. */ - for (i = 0;i < sizeof(config_ports)/sizeof(int);i++) - { + for (i = 0; i < ARRAY_SIZE(config_ports); i++) { if (!request_region(config_ports[i], 2, DRIVER_NAME)) continue; - for (j = 0;j < sizeof(unlock_codes)/sizeof(int);j++) - { + for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) { id = 0xFFFF; host->config = config_ports[i]; @@ -1478,8 +1476,7 @@ static int __devinit wbsd_scan(struct wbsd_host* host) wbsd_lock_config(host); - for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++) - { + for (k = 0; k < ARRAY_SIZE(valid_ids); k++) { if (id == valid_ids[k]) { host->chip_id = id; -- cgit v1.2.3 From 21500bb32acd4c34b50e5d985712e29792c1b9ad Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 3 Jan 2006 22:57:35 +0000 Subject: [MMC] wbsd: convert to the new platfrom device interface platform_device_register_simple() is going away, switch to using platfrom_device_alloc() + platform_device_add(). Also make sure that wbsd_driver gets unregistered when wbsd_init fails. Signed-off-by: Dmitry Torokhov Acked-by: Pierre Ossman --- drivers/mmc/wbsd.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 9df0ddeb3ff9..4f13bd2ccf9a 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -2087,10 +2087,20 @@ static int __init wbsd_drv_init(void) if (result < 0) return result; - wbsd_device = platform_device_register_simple(DRIVER_NAME, -1, - NULL, 0); - if (IS_ERR(wbsd_device)) - return PTR_ERR(wbsd_device); + wbsd_device = platform_device_alloc(DRIVER_NAME, -1); + if (!wbsd_device) + { + platform_driver_unregister(&wbsd_driver); + return -ENOMEM; + } + + result = platform_device_add(wbsd_device); + if (result) + { + platform_device_put(wbsd_device); + platform_driver_unregister(&wbsd_driver); + return result; + } } return 0; -- cgit v1.2.3 From bb84db937a875045de9e6d08d177ad3223ae0ae3 Mon Sep 17 00:00:00 2001 From: Karol Kozimor Date: Tue, 3 Jan 2006 23:03:00 -0500 Subject: [ACPI_ASUS] M6R display reading This patch corrects the node to read display settings on M6R laptops. Signed-off-by: Karol Kozimor Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 582995ef9f34..d4e1e95934fb 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -302,7 +302,7 @@ static struct model_data model_conf[END_MODEL] = { .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", - .display_get = "\\SSTE"}, + .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"}, { .name = "M6R", .mt_mled = "MLED", -- cgit v1.2.3 From aea19aa0780d4b006372fedab8434226e1cc7686 Mon Sep 17 00:00:00 2001 From: Karol Kozimor Date: Tue, 3 Jan 2006 23:05:00 -0500 Subject: [ACPI_ASUS] fix asus module param description Signed-off-by: Karol Kozimor Signed-off-by: Len Brown --- drivers/acpi/asus_acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index d4e1e95934fb..f4c87750dbf2 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -78,9 +78,9 @@ MODULE_LICENSE("GPL"); static uid_t asus_uid; static gid_t asus_gid; module_param(asus_uid, uint, 0); -MODULE_PARM_DESC(uid, "UID for entries in /proc/acpi/asus.\n"); +MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus.\n"); module_param(asus_gid, uint, 0); -MODULE_PARM_DESC(gid, "GID for entries in /proc/acpi/asus.\n"); +MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus.\n"); /* For each model, all features implemented, * those marked with R are relative to HOTK, A for absolute */ @@ -851,6 +851,8 @@ static int __init asus_hotk_add_fs(struct acpi_device *device) mode = S_IFREG | S_IRUGO | S_IWUGO; } else { mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP; + printk(KERN_WARNING " asus_uid and asus_gid parameters are " + "deprecated, use chown and chmod instead!\n"); } acpi_device_dir(device) = asus_proc_dir; -- cgit v1.2.3 From ce11a161c11868f268964274edc7a26a3e063e08 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 12:40:39 +0000 Subject: [MMC] Fix missing ',' Signed-off-by: Russell King --- include/linux/mmc/card.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 7f7d40684288..30dd978c1ec8 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -34,7 +34,7 @@ struct mmc_csd { unsigned int capacity; unsigned int read_partial:1, read_misalign:1, - write_partial:1 + write_partial:1, write_misalign:1; }; -- cgit v1.2.3 From 109a9378807cb9093a88fbf9707420de97601e14 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 14:06:31 +0000 Subject: [ARM] Remove unused dma.c files CLPS711x, EPXA10DB and Integrator contained a dma.c file which has never been built. Remove these redundant files. Signed-off-by: Russell King --- arch/arm/mach-clps711x/dma.c | 27 --------------------------- arch/arm/mach-epxa10db/dma.c | 28 ---------------------------- arch/arm/mach-integrator/dma.c | 35 ----------------------------------- 3 files changed, 90 deletions(-) delete mode 100644 arch/arm/mach-clps711x/dma.c delete mode 100644 arch/arm/mach-epxa10db/dma.c delete mode 100644 arch/arm/mach-integrator/dma.c diff --git a/arch/arm/mach-clps711x/dma.c b/arch/arm/mach-clps711x/dma.c deleted file mode 100644 index af5a4de38eac..000000000000 --- a/arch/arm/mach-clps711x/dma.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * linux/arch/arm/mach-clps711x/dma.c - * - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include - -#include -#include - -void __init arch_dma_init(dma_t *dma) -{ -} diff --git a/arch/arm/mach-epxa10db/dma.c b/arch/arm/mach-epxa10db/dma.c deleted file mode 100644 index 0151e9f1c066..000000000000 --- a/arch/arm/mach-epxa10db/dma.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * linux/arch/arm/mach-epxa10db/dma.c - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include - -#include -#include - -void __init arch_dma_init(dma_t *dma) -{ -} diff --git a/arch/arm/mach-integrator/dma.c b/arch/arm/mach-integrator/dma.c deleted file mode 100644 index aae6f23cd72b..000000000000 --- a/arch/arm/mach-integrator/dma.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/dma.c - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -void __init arch_dma_init(dma_t *dma) -{ -} -- cgit v1.2.3 From 333c9624b728a9e83b741ea75836aa114ec35272 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 14:41:29 +0000 Subject: [ARM] Move ISA DMA bus_to_virt() out of set_dma_addr() Allow the compiler to optimise the bus_to_virt(virt_to_bus()) transformation in the ARM ISA DMA interface. Signed-off-by: Russell King --- arch/arm/kernel/dma.c | 8 ++++---- include/asm-arm/dma.h | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 8d6381cd8915..3aedada71046 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -131,7 +131,7 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) * * Copy address to the structure, and set the invalid bit */ -void set_dma_addr (dmach_t channel, unsigned long physaddr) +void __set_dma_addr (dmach_t channel, void *addr) { dma_t *dma = dma_chan + channel; @@ -141,7 +141,7 @@ void set_dma_addr (dmach_t channel, unsigned long physaddr) dma->sg = &dma->buf; dma->sgcount = 1; - dma->buf.__address = bus_to_virt(physaddr); + dma->buf.__address = addr; dma->using_sg = 0; dma->invalid = 1; } @@ -278,7 +278,7 @@ GLOBAL_ALIAS(get_dma_list, get_dma_residue); GLOBAL_ALIAS(set_dma_mode, get_dma_residue); GLOBAL_ALIAS(set_dma_page, get_dma_residue); GLOBAL_ALIAS(set_dma_count, get_dma_residue); -GLOBAL_ALIAS(set_dma_addr, get_dma_residue); +GLOBAL_ALIAS(__set_dma_addr, get_dma_residue); GLOBAL_ALIAS(set_dma_sg, get_dma_residue); GLOBAL_ALIAS(set_dma_speed, get_dma_residue); GLOBAL_ALIAS(init_dma, get_dma_residue); @@ -289,7 +289,7 @@ EXPORT_SYMBOL(request_dma); EXPORT_SYMBOL(free_dma); EXPORT_SYMBOL(enable_dma); EXPORT_SYMBOL(disable_dma); -EXPORT_SYMBOL(set_dma_addr); +EXPORT_SYMBOL(__set_dma_addr); EXPORT_SYMBOL(set_dma_count); EXPORT_SYMBOL(set_dma_mode); EXPORT_SYMBOL(set_dma_page); diff --git a/include/asm-arm/dma.h b/include/asm-arm/dma.h index ef41df43a584..1c7087f9364c 100644 --- a/include/asm-arm/dma.h +++ b/include/asm-arm/dma.h @@ -91,7 +91,9 @@ extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); * especially since some DMA architectures don't update the * DMA address immediately, but defer it to the enable_dma(). */ -extern void set_dma_addr(dmach_t channel, unsigned long physaddr); +extern void __set_dma_addr(dmach_t channel, void *addr); +#define set_dma_addr(channel, addr) \ + __set_dma_addr(channel, bus_to_virt(addr)) /* Set the DMA byte count for this channel * -- cgit v1.2.3 From 7cdad482974792419cfe4b0affca689170116f49 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:08:30 +0000 Subject: [ARM] Remove '__address' from scatterlist and convert to DMA API The old __address element in struct scatterlist remained from older kernels because the ARM DMA emulation code made use of it. Move this field into struct dma_struct, and convert DMA emulation code to setup a SG entry as required. Also, convert DMA emulation code to use the new DMA API rather than the PCI DMA API. Signed-off-by: Russell King --- arch/arm/kernel/dma-isa.c | 22 +++++++++++++--------- arch/arm/kernel/dma.c | 13 ++++--------- arch/arm/mach-rpc/dma.c | 19 +++++++++++-------- include/asm-arm/mach/dma.h | 4 +++- include/asm-arm/scatterlist.h | 1 - 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/arch/arm/kernel/dma-isa.c b/arch/arm/kernel/dma-isa.c index e9a36304ec3e..03532769a97f 100644 --- a/arch/arm/kernel/dma-isa.c +++ b/arch/arm/kernel/dma-isa.c @@ -18,7 +18,7 @@ */ #include #include -#include +#include #include #include @@ -65,37 +65,41 @@ static void isa_enable_dma(dmach_t channel, dma_t *dma) { if (dma->invalid) { unsigned long address, length; - unsigned int mode, direction; + unsigned int mode; + enum dma_data_direction direction; mode = channel & 3; switch (dma->dma_mode & DMA_MODE_MASK) { case DMA_MODE_READ: mode |= ISA_DMA_MODE_READ; - direction = PCI_DMA_FROMDEVICE; + direction = DMA_FROM_DEVICE; break; case DMA_MODE_WRITE: mode |= ISA_DMA_MODE_WRITE; - direction = PCI_DMA_TODEVICE; + direction = DMA_TO_DEVICE; break; case DMA_MODE_CASCADE: mode |= ISA_DMA_MODE_CASCADE; - direction = PCI_DMA_BIDIRECTIONAL; + direction = DMA_BIDIRECTIONAL; break; default: - direction = PCI_DMA_NONE; + direction = DMA_NONE; break; } - if (!dma->using_sg) { + if (!dma->sg) { /* * Cope with ISA-style drivers which expect cache * coherence. */ - dma->buf.dma_address = pci_map_single(NULL, - dma->buf.__address, dma->buf.length, + dma->sg = &dma->buf; + dma->sgcount = 1; + dma->buf.length = dma->count; + dma->buf.dma_address = dma_map_single(NULL, + dma->addr, dma->count, direction); } diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 3aedada71046..913fd947528c 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -123,7 +123,6 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) dma->sg = sg; dma->sgcount = nr_sg; - dma->using_sg = 1; dma->invalid = 1; } @@ -139,10 +138,8 @@ void __set_dma_addr (dmach_t channel, void *addr) printk(KERN_ERR "dma%d: altering DMA address while " "DMA active\n", channel); - dma->sg = &dma->buf; - dma->sgcount = 1; - dma->buf.__address = addr; - dma->using_sg = 0; + dma->sg = NULL; + dma->addr = addr; dma->invalid = 1; } @@ -158,10 +155,8 @@ void set_dma_count (dmach_t channel, unsigned long count) printk(KERN_ERR "dma%d: altering DMA count while " "DMA active\n", channel); - dma->sg = &dma->buf; - dma->sgcount = 1; - dma->buf.length = count; - dma->using_sg = 0; + dma->sg = NULL; + dma->count = count; dma->invalid = 1; } diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c index bc0747439fb3..bd86ffba8810 100644 --- a/arch/arm/mach-rpc/dma.c +++ b/arch/arm/mach-rpc/dma.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -148,11 +148,14 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma) * Cope with ISA-style drivers which expect cache * coherence. */ - if (!dma->using_sg) { - dma->buf.dma_address = pci_map_single(NULL, - dma->buf.__address, dma->buf.length, + if (!dma->sg) { + dma->sg = &dma->buf; + dma->sgcount = 1; + dma->buf.length = dma->count; + dma->buf.dma_address = dma_map_single(NULL, + dma->addr, dma->count, dma->dma_mode == DMA_MODE_READ ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + DMA_FROM_DEVICE : DMA_TO_DEVICE); } iomd_writeb(DMA_CR_C, dma_base + CR); @@ -239,7 +242,7 @@ static void floppy_enable_dma(dmach_t channel, dma_t *dma) unsigned int fiqhandler_length; struct pt_regs regs; - if (dma->using_sg) + if (dma->sg) BUG(); if (dma->dma_mode == DMA_MODE_READ) { @@ -252,8 +255,8 @@ static void floppy_enable_dma(dmach_t channel, dma_t *dma) fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; } - regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = (unsigned long)dma->buf.__address; + regs.ARM_r9 = dma->count; + regs.ARM_r10 = (unsigned long)dma->addr; regs.ARM_fp = (unsigned long)FLOPPYDMA_BASE; if (claim_fiq(&fh)) { diff --git a/include/asm-arm/mach/dma.h b/include/asm-arm/mach/dma.h index 31bf716106ee..e7c4a20aad53 100644 --- a/include/asm-arm/mach/dma.h +++ b/include/asm-arm/mach/dma.h @@ -25,13 +25,15 @@ struct dma_ops { }; struct dma_struct { + void *addr; /* single DMA address */ + unsigned long count; /* single DMA size */ struct scatterlist buf; /* single DMA */ int sgcount; /* number of DMA SG */ struct scatterlist *sg; /* DMA Scatter-Gather List */ unsigned int active:1; /* Transfer active */ unsigned int invalid:1; /* Address/Count changed */ - unsigned int using_sg:1; /* using scatter list? */ + dmamode_t dma_mode; /* DMA mode */ int speed; /* DMA speed */ diff --git a/include/asm-arm/scatterlist.h b/include/asm-arm/scatterlist.h index 83b876fb04cc..de2f65eb42ed 100644 --- a/include/asm-arm/scatterlist.h +++ b/include/asm-arm/scatterlist.h @@ -9,7 +9,6 @@ struct scatterlist { unsigned int offset; /* buffer offset */ dma_addr_t dma_address; /* dma address */ unsigned int length; /* length */ - char *__address; /* for set_dma_addr */ }; /* -- cgit v1.2.3 From 6842b9299272a9471a7e94e046b953f6ffe3db9d Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:17:08 +0000 Subject: [ARM] Use core_initcall() to initialise ARM DMA There's no need to have DMA initialised at the same time as interrupts. Move it to a core_initcall(). Signed-off-by: Russell King --- arch/arm/kernel/dma.c | 6 ++++-- arch/arm/kernel/irq.c | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 913fd947528c..3b325ef55a28 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -248,11 +248,14 @@ int get_dma_residue(dmach_t channel) return ret; } -void __init init_dma(void) +static int __init init_dma(void) { arch_dma_init(dma_chan); + return 0; } +core_initcall(init_dma); + #else int request_dma(dmach_t channel, const char *device_id) @@ -276,7 +279,6 @@ GLOBAL_ALIAS(set_dma_count, get_dma_residue); GLOBAL_ALIAS(__set_dma_addr, get_dma_residue); GLOBAL_ALIAS(set_dma_sg, get_dma_residue); GLOBAL_ALIAS(set_dma_speed, get_dma_residue); -GLOBAL_ALIAS(init_dma, get_dma_residue); #endif diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index d7099dbbb879..869c466e6258 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -1027,7 +1027,6 @@ void __init init_irq_proc(void) void __init init_IRQ(void) { struct irqdesc *desc; - extern void init_dma(void); int irq; #ifdef CONFIG_SMP @@ -1041,7 +1040,6 @@ void __init init_IRQ(void) } init_arch_irq(); - init_dma(); } static int __init noirqdebug_setup(char *str) -- cgit v1.2.3 From d4c6fc9976dd70a27abc988ddbd6a746c1dba0a7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:30:48 +0000 Subject: [ARM] Move common definition of MAX_DMA_ADDRESS to asm/dma.h Signed-off-by: Russell King --- include/asm-arm/arch-aaec2000/dma.h | 1 - include/asm-arm/arch-clps711x/dma.h | 2 -- include/asm-arm/arch-ebsa110/dma.h | 1 - include/asm-arm/arch-ebsa285/dma.h | 5 ----- include/asm-arm/arch-epxa10db/dma.h | 2 -- include/asm-arm/arch-imx/dma.h | 2 -- include/asm-arm/arch-integrator/dma.h | 2 -- include/asm-arm/arch-iop3xx/dma.h | 2 -- include/asm-arm/arch-ixp2000/dma.h | 2 -- include/asm-arm/arch-lh7a40x/dma.h | 1 - include/asm-arm/arch-omap/dma.h | 1 - include/asm-arm/arch-pxa/dma.h | 2 -- include/asm-arm/arch-realview/dma.h | 1 - include/asm-arm/arch-sa1100/dma.h | 6 ------ include/asm-arm/arch-versatile/dma.h | 1 - include/asm-arm/dma.h | 7 +++++++ 16 files changed, 7 insertions(+), 31 deletions(-) diff --git a/include/asm-arm/arch-aaec2000/dma.h b/include/asm-arm/arch-aaec2000/dma.h index 28c890b4a1d3..c42212c9ea79 100644 --- a/include/asm-arm/arch-aaec2000/dma.h +++ b/include/asm-arm/arch-aaec2000/dma.h @@ -11,7 +11,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_CHANNELS 0 #endif diff --git a/include/asm-arm/arch-clps711x/dma.h b/include/asm-arm/arch-clps711x/dma.h index 3c4c5c843252..c35f87d0bf7a 100644 --- a/include/asm-arm/arch-clps711x/dma.h +++ b/include/asm-arm/arch-clps711x/dma.h @@ -20,8 +20,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff - #define MAX_DMA_CHANNELS 0 #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-ebsa110/dma.h b/include/asm-arm/arch-ebsa110/dma.h index d491776ac1cc..f1add1343edc 100644 --- a/include/asm-arm/arch-ebsa110/dma.h +++ b/include/asm-arm/arch-ebsa110/dma.h @@ -12,7 +12,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_CHANNELS 0 #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-ebsa285/dma.h b/include/asm-arm/arch-ebsa285/dma.h index c43046eb8bc7..0259ad45d33c 100644 --- a/include/asm-arm/arch-ebsa285/dma.h +++ b/include/asm-arm/arch-ebsa285/dma.h @@ -9,11 +9,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -/* - * This is the maximum DMA address that can be DMAd to. - */ -#define MAX_DMA_ADDRESS 0xffffffff - /* * The 21285 has two internal DMA channels; we call these 8 and 9. * On CATS hardware we have an additional eight ISA dma channels diff --git a/include/asm-arm/arch-epxa10db/dma.h b/include/asm-arm/arch-epxa10db/dma.h index 5d97734d1077..6e13e6bb8b1d 100644 --- a/include/asm-arm/arch-epxa10db/dma.h +++ b/include/asm-arm/arch-epxa10db/dma.h @@ -20,8 +20,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff - #define MAX_DMA_CHANNELS 0 #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-imx/dma.h b/include/asm-arm/arch-imx/dma.h index dbdc01780413..0b8f39adc9a7 100644 --- a/include/asm-arm/arch-imx/dma.h +++ b/include/asm-arm/arch-imx/dma.h @@ -20,8 +20,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff - #define MAX_DMA_CHANNELS 0 /* diff --git a/include/asm-arm/arch-integrator/dma.h b/include/asm-arm/arch-integrator/dma.h index 7171792290bd..6f934f6d838a 100644 --- a/include/asm-arm/arch-integrator/dma.h +++ b/include/asm-arm/arch-integrator/dma.h @@ -20,8 +20,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff - #define MAX_DMA_CHANNELS 0 #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-iop3xx/dma.h b/include/asm-arm/arch-iop3xx/dma.h index 797f9e6fc745..58ec24db415d 100644 --- a/include/asm-arm/arch-iop3xx/dma.h +++ b/include/asm-arm/arch-iop3xx/dma.h @@ -11,6 +11,4 @@ #ifndef _IOP3XX_DMA_H_P #define _IOP3XX_DMA_H_P -#define MAX_DMA_ADDRESS 0xffffffff - #endif /* _ASM_ARCH_DMA_H_P */ diff --git a/include/asm-arm/arch-ixp2000/dma.h b/include/asm-arm/arch-ixp2000/dma.h index 0fb3568a98dd..3af382551cda 100644 --- a/include/asm-arm/arch-ixp2000/dma.h +++ b/include/asm-arm/arch-ixp2000/dma.h @@ -10,8 +10,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff - /* No DMA */ #define MAX_DMA_CHANNELS 0 diff --git a/include/asm-arm/arch-lh7a40x/dma.h b/include/asm-arm/arch-lh7a40x/dma.h index 5797f01e1844..18f13689a405 100644 --- a/include/asm-arm/arch-lh7a40x/dma.h +++ b/include/asm-arm/arch-lh7a40x/dma.h @@ -11,7 +11,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_CHANNELS 0 /* All DMA is internal to CPU */ #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h index ccbcb580a5c1..40c045404613 100644 --- a/include/asm-arm/arch-omap/dma.h +++ b/include/asm-arm/arch-omap/dma.h @@ -21,7 +21,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_CHANNELS 0 /* Hardware registers for omap1 */ diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h index 56db3d49bfc8..7402bdafc163 100644 --- a/include/asm-arm/arch-pxa/dma.h +++ b/include/asm-arm/arch-pxa/dma.h @@ -12,8 +12,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff - /* No DMA as the rest of the world see it */ #define MAX_DMA_CHANNELS 0 diff --git a/include/asm-arm/arch-realview/dma.h b/include/asm-arm/arch-realview/dma.h index 744491a74bd9..d595cc90b069 100644 --- a/include/asm-arm/arch-realview/dma.h +++ b/include/asm-arm/arch-realview/dma.h @@ -21,7 +21,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_CHANNELS 0 #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-sa1100/dma.h b/include/asm-arm/arch-sa1100/dma.h index 3d60ed9f8c34..a79c2d37c669 100644 --- a/include/asm-arm/arch-sa1100/dma.h +++ b/include/asm-arm/arch-sa1100/dma.h @@ -14,12 +14,6 @@ #include "hardware.h" -/* - * This is the maximum DMA address that can be DMAd to. - */ -#define MAX_DMA_ADDRESS 0xffffffff - - /* * The regular generic DMA interface is inappropriate for the * SA1100 DMA model. None of the SA1100 specific drivers using diff --git a/include/asm-arm/arch-versatile/dma.h b/include/asm-arm/arch-versatile/dma.h index dcc8ac26eac0..94b3fc5a6321 100644 --- a/include/asm-arm/arch-versatile/dma.h +++ b/include/asm-arm/arch-versatile/dma.h @@ -21,7 +21,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_ADDRESS 0xffffffff #define MAX_DMA_CHANNELS 0 #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/dma.h b/include/asm-arm/dma.h index 1c7087f9364c..49c01e2bf7c8 100644 --- a/include/asm-arm/dma.h +++ b/include/asm-arm/dma.h @@ -9,6 +9,13 @@ typedef unsigned int dmach_t; #include #include +/* + * This is the maximum virtual address which can be DMA'd from. + */ +#ifndef MAX_DMA_ADDRESS +#define MAX_DMA_ADDRESS 0xffffffff +#endif + /* * DMA modes */ -- cgit v1.2.3 From 065909b91581cf2438d901a7811a82af3476bdab Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:44:16 +0000 Subject: [ARM] Refine selection of ISA_DMA_API and generic dma.c code ISA_DMA_API tells the rest of the kernel if the ISA DMA API is available. Select this symbol only on machine types which make use of the ISA DMA API. Make building of arch/arm/kernel/dma.c depend on this symbol - if a machine does not support the ISA DMA API, it's pointless building this file. Signed-off-by: Russell King --- arch/arm/Kconfig | 6 +++++- arch/arm/kernel/Makefile | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4b15f5f1e254..cb413109da0c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -154,6 +154,7 @@ config ARCH_RPC select FIQ select TIMER_ACORN select ARCH_MAY_HAVE_PC_FDC + select ISA_DMA_API help On the Acorn Risc-PC, Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. @@ -206,6 +207,7 @@ config ARCH_IMX config ARCH_H720X bool "Hynix-HMS720x-based" + select ISA_DMA_API help This enables support for systems based on the Hynix HMS720x @@ -290,12 +292,14 @@ config ISA (MCA) or VESA. ISA is an older system, now being displaced by PCI; newer boards don't support it. If you have ISA, say Y, otherwise N. +# Select ISA DMA controller support config ISA_DMA bool + select ISA_DMA_API +# Select ISA DMA interface config ISA_DMA_API bool - default y config PCI bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 25b14c3fdc4a..de94b0f3ee2a 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -6,11 +6,12 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Object file lists. -obj-y := compat.o dma.o entry-armv.o entry-common.o irq.o \ +obj-y := compat.o entry-armv.o entry-common.o irq.o \ process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ time.o traps.o obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o obj-$(CONFIG_FOOTBRIDGE) += isa.o obj-$(CONFIG_FIQ) += fiq.o -- cgit v1.2.3 From 95ba9fb06be4a8714c98df6097eab1808c72fa98 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:51:51 +0000 Subject: [ARM] Remove definition of MAX_DMA_CHANNELS to zero Since we now only build arch/arm/kernel/dma.c on machine types which set ISA_DMA_API, we don't need to define MAX_DMA_CHANNELS to 0 to indicate this - this definition becomes superfluous. Remove it. Signed-off-by: Russell King --- arch/arm/kernel/dma.c | 28 ---------------------------- include/asm-arm/arch-aaec2000/dma.h | 7 ------- include/asm-arm/arch-cl7500/dma.h | 1 - include/asm-arm/arch-clps711x/dma.h | 7 ------- include/asm-arm/arch-ebsa110/dma.h | 7 ------- include/asm-arm/arch-epxa10db/dma.h | 7 ------- include/asm-arm/arch-imx/dma.h | 2 -- include/asm-arm/arch-integrator/dma.h | 7 ------- include/asm-arm/arch-iop3xx/dma.h | 5 ----- include/asm-arm/arch-ixp2000/dma.h | 7 ------- include/asm-arm/arch-ixp4xx/dma.h | 3 --- include/asm-arm/arch-l7200/dma.h | 1 - include/asm-arm/arch-lh7a40x/dma.h | 7 ------- include/asm-arm/arch-omap/dma.h | 2 -- include/asm-arm/arch-pxa/dma.h | 3 --- include/asm-arm/arch-realview/dma.h | 6 ------ include/asm-arm/arch-s3c2410/dma.h | 8 -------- include/asm-arm/arch-sa1100/dma.h | 8 -------- include/asm-arm/arch-versatile/dma.h | 6 ------ 19 files changed, 122 deletions(-) diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 3b325ef55a28..62c8966a8b77 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -22,8 +22,6 @@ DEFINE_SPINLOCK(dma_spin_lock); -#if MAX_DMA_CHANNELS > 0 - static dma_t dma_chan[MAX_DMA_CHANNELS]; /* @@ -256,32 +254,6 @@ static int __init init_dma(void) core_initcall(init_dma); -#else - -int request_dma(dmach_t channel, const char *device_id) -{ - return -EINVAL; -} - -int get_dma_residue(dmach_t channel) -{ - return 0; -} - -#define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a) -GLOBAL_ALIAS(disable_dma, get_dma_residue); -GLOBAL_ALIAS(enable_dma, get_dma_residue); -GLOBAL_ALIAS(free_dma, get_dma_residue); -GLOBAL_ALIAS(get_dma_list, get_dma_residue); -GLOBAL_ALIAS(set_dma_mode, get_dma_residue); -GLOBAL_ALIAS(set_dma_page, get_dma_residue); -GLOBAL_ALIAS(set_dma_count, get_dma_residue); -GLOBAL_ALIAS(__set_dma_addr, get_dma_residue); -GLOBAL_ALIAS(set_dma_sg, get_dma_residue); -GLOBAL_ALIAS(set_dma_speed, get_dma_residue); - -#endif - EXPORT_SYMBOL(request_dma); EXPORT_SYMBOL(free_dma); EXPORT_SYMBOL(enable_dma); diff --git a/include/asm-arm/arch-aaec2000/dma.h b/include/asm-arm/arch-aaec2000/dma.h index c42212c9ea79..e100b1e526fe 100644 --- a/include/asm-arm/arch-aaec2000/dma.h +++ b/include/asm-arm/arch-aaec2000/dma.h @@ -7,10 +7,3 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif diff --git a/include/asm-arm/arch-cl7500/dma.h b/include/asm-arm/arch-cl7500/dma.h index 1d6a8829d327..591ed2551892 100644 --- a/include/asm-arm/arch-cl7500/dma.h +++ b/include/asm-arm/arch-cl7500/dma.h @@ -15,7 +15,6 @@ * bytes of RAM. */ #define MAX_DMA_ADDRESS 0xd0000000 -#define MAX_DMA_CHANNELS 0 #define DMA_S0 0 diff --git a/include/asm-arm/arch-clps711x/dma.h b/include/asm-arm/arch-clps711x/dma.h index c35f87d0bf7a..610997938423 100644 --- a/include/asm-arm/arch-clps711x/dma.h +++ b/include/asm-arm/arch-clps711x/dma.h @@ -17,10 +17,3 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ - diff --git a/include/asm-arm/arch-ebsa110/dma.h b/include/asm-arm/arch-ebsa110/dma.h index f1add1343edc..c52f9e2ab0bb 100644 --- a/include/asm-arm/arch-ebsa110/dma.h +++ b/include/asm-arm/arch-ebsa110/dma.h @@ -9,10 +9,3 @@ * * EBSA110 DMA definitions */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ - diff --git a/include/asm-arm/arch-epxa10db/dma.h b/include/asm-arm/arch-epxa10db/dma.h index 6e13e6bb8b1d..de20ec8e74b1 100644 --- a/include/asm-arm/arch-epxa10db/dma.h +++ b/include/asm-arm/arch-epxa10db/dma.h @@ -17,10 +17,3 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ - diff --git a/include/asm-arm/arch-imx/dma.h b/include/asm-arm/arch-imx/dma.h index 0b8f39adc9a7..b45fa367d71e 100644 --- a/include/asm-arm/arch-imx/dma.h +++ b/include/asm-arm/arch-imx/dma.h @@ -20,8 +20,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_CHANNELS 0 - /* * DMA registration */ diff --git a/include/asm-arm/arch-integrator/dma.h b/include/asm-arm/arch-integrator/dma.h index 6f934f6d838a..83fd6bbaf9d3 100644 --- a/include/asm-arm/arch-integrator/dma.h +++ b/include/asm-arm/arch-integrator/dma.h @@ -17,10 +17,3 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ - diff --git a/include/asm-arm/arch-iop3xx/dma.h b/include/asm-arm/arch-iop3xx/dma.h index 58ec24db415d..1e808db8af2a 100644 --- a/include/asm-arm/arch-iop3xx/dma.h +++ b/include/asm-arm/arch-iop3xx/dma.h @@ -7,8 +7,3 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - -#ifndef _IOP3XX_DMA_H_P -#define _IOP3XX_DMA_H_P - -#endif /* _ASM_ARCH_DMA_H_P */ diff --git a/include/asm-arm/arch-ixp2000/dma.h b/include/asm-arm/arch-ixp2000/dma.h index 3af382551cda..548d8dc507eb 100644 --- a/include/asm-arm/arch-ixp2000/dma.h +++ b/include/asm-arm/arch-ixp2000/dma.h @@ -7,10 +7,3 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -/* No DMA */ -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-ixp4xx/dma.h b/include/asm-arm/arch-ixp4xx/dma.h index 312065dc0e7a..b1a071ecebc8 100644 --- a/include/asm-arm/arch-ixp4xx/dma.h +++ b/include/asm-arm/arch-ixp4xx/dma.h @@ -20,7 +20,4 @@ #define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_64M) -/* No DMA */ -#define MAX_DMA_CHANNELS 0 - #endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-l7200/dma.h b/include/asm-arm/arch-l7200/dma.h index 6595b386cfc9..4c7eca63f035 100644 --- a/include/asm-arm/arch-l7200/dma.h +++ b/include/asm-arm/arch-l7200/dma.h @@ -17,7 +17,6 @@ * bytes of RAM. */ #define MAX_DMA_ADDRESS 0xd0000000 -#define MAX_DMA_CHANNELS 0 #define DMA_S0 0 diff --git a/include/asm-arm/arch-lh7a40x/dma.h b/include/asm-arm/arch-lh7a40x/dma.h index 18f13689a405..15492e3253f6 100644 --- a/include/asm-arm/arch-lh7a40x/dma.h +++ b/include/asm-arm/arch-lh7a40x/dma.h @@ -7,10 +7,3 @@ * version 2 as published by the Free Software Foundation. * */ - -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 /* All DMA is internal to CPU */ - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h index 40c045404613..d4e73efcb816 100644 --- a/include/asm-arm/arch-omap/dma.h +++ b/include/asm-arm/arch-omap/dma.h @@ -21,8 +21,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -#define MAX_DMA_CHANNELS 0 - /* Hardware registers for omap1 */ #define OMAP_DMA_BASE (0xfffed800) #define OMAP_DMA_GCR (OMAP_DMA_BASE + 0x400) diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h index 7402bdafc163..3e88a2a02a0f 100644 --- a/include/asm-arm/arch-pxa/dma.h +++ b/include/asm-arm/arch-pxa/dma.h @@ -12,9 +12,6 @@ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H -/* No DMA as the rest of the world see it */ -#define MAX_DMA_CHANNELS 0 - /* * Descriptor structure for PXA's DMA engine * Note: this structure must always be aligned to a 16-byte boundary. diff --git a/include/asm-arm/arch-realview/dma.h b/include/asm-arm/arch-realview/dma.h index d595cc90b069..8342e3f9d6ec 100644 --- a/include/asm-arm/arch-realview/dma.h +++ b/include/asm-arm/arch-realview/dma.h @@ -18,9 +18,3 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h index e830a40e573a..b011e14f3bc6 100644 --- a/include/asm-arm/arch-s3c2410/dma.h +++ b/include/asm-arm/arch-s3c2410/dma.h @@ -31,14 +31,6 @@ #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ -/* according to the samsung port, we cannot use the regular - * dma channels... we must therefore provide our own interface - * for DMA, and allow our drivers to use that. - */ - -#define MAX_DMA_CHANNELS 0 - - /* we have 4 dma channels */ #define S3C2410_DMA_CHANNELS (4) diff --git a/include/asm-arm/arch-sa1100/dma.h b/include/asm-arm/arch-sa1100/dma.h index a79c2d37c669..02575d72ac6b 100644 --- a/include/asm-arm/arch-sa1100/dma.h +++ b/include/asm-arm/arch-sa1100/dma.h @@ -14,14 +14,6 @@ #include "hardware.h" -/* - * The regular generic DMA interface is inappropriate for the - * SA1100 DMA model. None of the SA1100 specific drivers using - * DMA are portable anyway so it's pointless to try to twist the - * regular DMA API to accommodate them. - */ -#define MAX_DMA_CHANNELS 0 - /* * The SA1100 has six internal DMA channels. */ diff --git a/include/asm-arm/arch-versatile/dma.h b/include/asm-arm/arch-versatile/dma.h index 94b3fc5a6321..642577348623 100644 --- a/include/asm-arm/arch-versatile/dma.h +++ b/include/asm-arm/arch-versatile/dma.h @@ -18,9 +18,3 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ -- cgit v1.2.3 From d7b4a75677f8f2a559b0c55a550b364e79a8d302 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:52:45 +0000 Subject: [ARM] Move DMA exports to be next to each function Signed-off-by: Russell King --- arch/arm/kernel/dma.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 62c8966a8b77..5a0f4bc5da95 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -21,6 +21,7 @@ #include DEFINE_SPINLOCK(dma_spin_lock); +EXPORT_SYMBOL(dma_spin_lock); static dma_t dma_chan[MAX_DMA_CHANNELS]; @@ -77,6 +78,7 @@ bad_dma: busy: return -EBUSY; } +EXPORT_SYMBOL(request_dma); /* * Free DMA channel @@ -108,6 +110,7 @@ void free_dma(dmach_t channel) bad_dma: printk(KERN_ERR "dma: trying to free DMA%d\n", channel); } +EXPORT_SYMBOL(free_dma); /* Set DMA Scatter-Gather list */ @@ -123,6 +126,7 @@ void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) dma->sgcount = nr_sg; dma->invalid = 1; } +EXPORT_SYMBOL(set_dma_sg); /* Set DMA address * @@ -140,6 +144,7 @@ void __set_dma_addr (dmach_t channel, void *addr) dma->addr = addr; dma->invalid = 1; } +EXPORT_SYMBOL(__set_dma_addr); /* Set DMA byte count * @@ -157,6 +162,7 @@ void set_dma_count (dmach_t channel, unsigned long count) dma->count = count; dma->invalid = 1; } +EXPORT_SYMBOL(set_dma_count); /* Set DMA direction mode */ @@ -171,6 +177,7 @@ void set_dma_mode (dmach_t channel, dmamode_t mode) dma->dma_mode = mode; dma->invalid = 1; } +EXPORT_SYMBOL(set_dma_mode); /* Enable DMA channel */ @@ -191,6 +198,7 @@ free_dma: printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel); BUG(); } +EXPORT_SYMBOL(enable_dma); /* Disable DMA channel */ @@ -211,6 +219,7 @@ free_dma: printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel); BUG(); } +EXPORT_SYMBOL(disable_dma); /* * Is the specified DMA channel active? @@ -224,6 +233,7 @@ void set_dma_page(dmach_t channel, char pagenr) { printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel); } +EXPORT_SYMBOL(set_dma_page); void set_dma_speed(dmach_t channel, int cycle_ns) { @@ -234,6 +244,7 @@ void set_dma_speed(dmach_t channel, int cycle_ns) ret = dma->d_ops->setspeed(channel, dma, cycle_ns); dma->speed = ret; } +EXPORT_SYMBOL(set_dma_speed); int get_dma_residue(dmach_t channel) { @@ -245,6 +256,7 @@ int get_dma_residue(dmach_t channel) return ret; } +EXPORT_SYMBOL(get_dma_residue); static int __init init_dma(void) { @@ -253,17 +265,3 @@ static int __init init_dma(void) } core_initcall(init_dma); - -EXPORT_SYMBOL(request_dma); -EXPORT_SYMBOL(free_dma); -EXPORT_SYMBOL(enable_dma); -EXPORT_SYMBOL(disable_dma); -EXPORT_SYMBOL(__set_dma_addr); -EXPORT_SYMBOL(set_dma_count); -EXPORT_SYMBOL(set_dma_mode); -EXPORT_SYMBOL(set_dma_page); -EXPORT_SYMBOL(get_dma_residue); -EXPORT_SYMBOL(set_dma_sg); -EXPORT_SYMBOL(set_dma_speed); - -EXPORT_SYMBOL(dma_spin_lock); -- cgit v1.2.3 From b3a962455b106a1677f91c754e5315753c3d44c3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 15:55:41 +0000 Subject: [ARM] Remove SA1100 PM prepare/finish ops These are empty, unnecessary functions, so remove them. Signed-off-by: Russell King --- arch/arm/mach-sa1100/pm.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 59c7964cfe11..786c8534231f 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -134,30 +134,12 @@ unsigned long sleep_phys_sp(void *sp) return virt_to_phys(sp); } -/* - * Called after processes are frozen, but before we shut down devices. - */ -static int sa11x0_pm_prepare(suspend_state_t state) -{ - return 0; -} - -/* - * Called after devices are re-setup, but before processes are thawed. - */ -static int sa11x0_pm_finish(suspend_state_t state) -{ - return 0; -} - /* * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. */ static struct pm_ops sa11x0_pm_ops = { .pm_disk_mode = PM_DISK_FIRMWARE, - .prepare = sa11x0_pm_prepare, .enter = sa11x0_pm_enter, - .finish = sa11x0_pm_finish, }; static int __init sa11x0_pm_init(void) -- cgit v1.2.3 From e9c091b47409255cefa1672041479d850b7b991a Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 16:24:05 +0000 Subject: [MMC] mmci: add data cache coherency Since MMCI currently uses PIO to read data, we have to take steps to ensure data cache coherency on aliasing CPU caches. Add the necessary flush_dcache_page() calls. Signed-off-by: Russell King --- drivers/mmc/mmci.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 166c9b0ad04e..6d161c70014a 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -157,6 +158,13 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) data->error = MMC_ERR_FIFO; status |= MCI_DATAEND; + + /* + * We hit an error condition. Ensure that any data + * partially written to a page is properly coherent. + */ + if (host->sg_len && data->flags & MMC_DATA_READ) + flush_dcache_page(host->sg_ptr->page); } if (status & MCI_DATAEND) { mmci_stop_data(host); @@ -301,6 +309,13 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) if (remain) break; + /* + * If we were reading, and we have completed this + * page, ensure that the data cache is coherent. + */ + if (status & MCI_RXACTIVE) + flush_dcache_page(host->sg_ptr->page); + if (!mmci_next_sg(host)) break; -- cgit v1.2.3 From 2af7cd68f1ed20e2e72c91988c3d4f457fa29ebc Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 16:55:09 +0000 Subject: [Serial] Don't miss modem status changes Reading the MSR register on 8250-compatible UARTs results in any modem status interrupts being cleared. To avoid missing any status changes, arrange for get_mctrl() to read the current status via check_modem_status(), which will process any pending state changes for us. Signed-off-by: Russell King --- drivers/serial/8250.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index d2bcd1f87cd6..076bf848e4d1 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1255,25 +1255,24 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up) __stop_tx(up); } -static _INLINE_ void check_modem_status(struct uart_8250_port *up) +static unsigned int check_modem_status(struct uart_8250_port *up) { - int status; + unsigned int status = serial_in(up, UART_MSR); - status = serial_in(up, UART_MSR); + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI) { + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - up->port.icount.rng++; - if (status & UART_MSR_DDSR) - up->port.icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + wake_up_interruptible(&up->port.info->delta_msr_wait); + } - wake_up_interruptible(&up->port.info->delta_msr_wait); + return status; } /* @@ -1454,10 +1453,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port) static unsigned int serial8250_get_mctrl(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; - unsigned char status; + unsigned int status; unsigned int ret; - status = serial_in(up, UART_MSR); + status = check_modem_status(up); ret = 0; if (status & UART_MSR_DCD) -- cgit v1.2.3 From 26e92861be9c0da3be30718de693976b3f6a8026 Mon Sep 17 00:00:00 2001 From: Gareth Howlett Date: Wed, 4 Jan 2006 17:00:42 +0000 Subject: [SERIAL] Add support for more Connect Tech PCI serial boards I've also fixed the sort-ordering comments on this naming convention. Signed-off-by: Stuart MacDonald Signed-off-by: Russell King --- drivers/serial/8250_pci.c | 120 +++++++++++++++++++++++++++++++++++++++++++--- include/linux/pci_ids.h | 17 +++++++ 2 files changed, 131 insertions(+), 6 deletions(-) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 8adca0ce267f..4a589a9456f5 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -853,14 +853,15 @@ get_pci_irq(struct pci_dev *dev, struct pciserial_board *board) * driver_data member. * * The makeup of these names are: - * pbn_bn{_bt}_n_baud + * pbn_bn{_bt}_n_baud{_offsetinhex} * - * bn = PCI BAR number - * bt = Index using PCI BARs - * n = number of serial ports - * baud = baud rate + * bn = PCI BAR number + * bt = Index using PCI BARs + * n = number of serial ports + * baud = baud rate + * offsetinhex = offset for each sequential port (in hex) * - * This table is sorted by (in order): baud, bt, bn, n. + * This table is sorted by (in order): bn, bt, baud, offsetindex, n. * * Please note: in theory if n = 1, _bt infix should make no difference. * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200 @@ -881,6 +882,13 @@ enum pci_board_num_t { pbn_b0_4_1152000, + pbn_b0_2_1843200, + pbn_b0_4_1843200, + + pbn_b0_2_1843200_200, + pbn_b0_4_1843200_200, + pbn_b0_8_1843200_200, + pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, pbn_b0_bt_8_115200, @@ -904,6 +912,8 @@ enum pci_board_num_t { pbn_b1_4_921600, pbn_b1_8_921600, + pbn_b1_2_1250000, + pbn_b1_bt_2_921600, pbn_b1_1_1382400, @@ -1029,6 +1039,38 @@ static struct pciserial_board pci_boards[] __devinitdata = { .uart_offset = 8, }, + [pbn_b0_2_1843200] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 1843200, + .uart_offset = 8, + }, + [pbn_b0_4_1843200] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1843200, + .uart_offset = 8, + }, + + [pbn_b0_2_1843200_200] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 1843200, + .uart_offset = 0x200, + }, + [pbn_b0_4_1843200_200] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 1843200, + .uart_offset = 0x200, + }, + [pbn_b0_8_1843200_200] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 1843200, + .uart_offset = 0x200, + }, + [pbn_b0_bt_1_115200] = { .flags = FL_BASE0|FL_BASE_BARS, .num_ports = 1, @@ -1141,6 +1183,12 @@ static struct pciserial_board pci_boards[] __devinitdata = { .base_baud = 921600, .uart_offset = 8, }, + [pbn_b1_2_1250000] = { + .flags = FL_BASE1, + .num_ports = 2, + .base_baud = 1250000, + .uart_offset = 8, + }, [pbn_b1_bt_2_921600] = { .flags = FL_BASE1|FL_BASE_BARS, @@ -1801,6 +1849,66 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, pbn_b1_4_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0, + pbn_b1_2_1250000 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0, + pbn_b0_2_1843200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0, + pbn_b0_4_1843200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8, 0, 0, + pbn_b0_8_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0, + pbn_b0_2_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485, 0, 0, + pbn_b0_4_1843200_200 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485, 0, 0, + pbn_b0_8_1843200_200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4db67b3b05cc..efb5d22f8c09 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1567,6 +1567,23 @@ #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009 #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A #define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ 0x000C +#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM 0x000D +#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI 0x0100 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2 0x0201 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4 0x0202 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232 0x0300 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232 0x0301 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232 0x0302 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1 0x0310 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2 0x0311 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4 0x0312 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2 0x0320 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4 0x0321 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8 0x0322 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485 0x0330 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331 +#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332 #define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 -- cgit v1.2.3 From f7e8bbb8207c17afbd716e7e5fc785b78fa08571 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Wed, 4 Jan 2006 17:17:10 +0000 Subject: [ARM] 3192/1: Remove gpio_isr_line_clear() API from IXP4xx Patch from Deepak Saxena Other than interrupt masking purposes, this API is only used when configuring interrupt lines and this patch moves that functionality directly into the ixp4xx_set_irq_type() implementation as board level PCI code should not need to worry about those details. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/common.c | 4 +++- arch/arm/mach-ixp4xx/coyote-pci.c | 3 --- arch/arm/mach-ixp4xx/ixdp425-pci.c | 5 ----- arch/arm/mach-ixp4xx/ixdpg425-pci.c | 3 --- arch/arm/mach-ixp4xx/nslu2-pci.c | 8 -------- arch/arm/mach-ixp4xx/nslu2-power.c | 3 --- include/asm-arm/arch-ixp4xx/platform.h | 5 ----- 7 files changed, 3 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index f3c687cf0071..9f33cb21e7f3 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -142,6 +142,8 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type) *int_reg &= ~(IXP4XX_GPIO_STYLE_CLEAR << (line * IXP4XX_GPIO_STYLE_SIZE)); + *IXP4XX_GPIO_GPISR = (1 << line); + /* Set the new style */ *int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE)); @@ -169,7 +171,7 @@ static void ixp4xx_irq_ack(unsigned int irq) int line = (irq < 32) ? irq2gpio[irq] : -1; if (line >= 0) - gpio_line_isr_clear(line); + *IXP4XX_GPIO_GPISR = (1 << line); } /* diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c index 60de8a94cff5..e6b7fcd923fa 100644 --- a/arch/arm/mach-ixp4xx/coyote-pci.c +++ b/arch/arm/mach-ixp4xx/coyote-pci.c @@ -33,9 +33,6 @@ void __init coyote_pci_preinit(void) set_irq_type(IRQ_COYOTE_PCI_SLOT0, IRQT_LOW); set_irq_type(IRQ_COYOTE_PCI_SLOT1, IRQT_LOW); - gpio_line_isr_clear(COYOTE_PCI_SLOT0_PIN); - gpio_line_isr_clear(COYOTE_PCI_SLOT1_PIN); - ixp4xx_pci_preinit(); } diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c index f9a1d3e7d692..da415d5d7f37 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-pci.c +++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c @@ -32,11 +32,6 @@ void __init ixdp425_pci_preinit(void) set_irq_type(IRQ_IXDP425_PCI_INTC, IRQT_LOW); set_irq_type(IRQ_IXDP425_PCI_INTD, IRQT_LOW); - gpio_line_isr_clear(IXDP425_PCI_INTA_PIN); - gpio_line_isr_clear(IXDP425_PCI_INTB_PIN); - gpio_line_isr_clear(IXDP425_PCI_INTC_PIN); - gpio_line_isr_clear(IXDP425_PCI_INTD_PIN); - ixp4xx_pci_preinit(); } diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c index fe5e7660de1d..526fb6175bc3 100644 --- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c +++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c @@ -32,9 +32,6 @@ void __init ixdpg425_pci_preinit(void) set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW); set_irq_type(IRQ_IXP4XX_GPIO7, IRQT_LOW); - gpio_line_isr_clear(6); - gpio_line_isr_clear(7); - ixp4xx_pci_preinit(); } diff --git a/arch/arm/mach-ixp4xx/nslu2-pci.c b/arch/arm/mach-ixp4xx/nslu2-pci.c index a575f2e0b2c8..ece860444d5b 100644 --- a/arch/arm/mach-ixp4xx/nslu2-pci.c +++ b/arch/arm/mach-ixp4xx/nslu2-pci.c @@ -28,14 +28,6 @@ void __init nslu2_pci_preinit(void) set_irq_type(IRQ_NSLU2_PCI_INTB, IRQT_LOW); set_irq_type(IRQ_NSLU2_PCI_INTC, IRQT_LOW); - gpio_line_isr_clear(NSLU2_PCI_INTA_PIN); - gpio_line_isr_clear(NSLU2_PCI_INTB_PIN); - gpio_line_isr_clear(NSLU2_PCI_INTC_PIN); - - /* INTD is not configured as GPIO is used - * for the power input button. - */ - ixp4xx_pci_preinit(); } diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c index 18fbc8c0fb30..b0ad9e901f6e 100644 --- a/arch/arm/mach-ixp4xx/nslu2-power.c +++ b/arch/arm/mach-ixp4xx/nslu2-power.c @@ -54,9 +54,6 @@ static int __init nslu2_power_init(void) set_irq_type(NSLU2_RB_IRQ, IRQT_LOW); set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH); - gpio_line_isr_clear(NSLU2_RB_GPIO); - gpio_line_isr_clear(NSLU2_PB_GPIO); - if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler, SA_INTERRUPT, "NSLU2 reset button", NULL) < 0) { diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index f14ed63590c3..6b77ed26be79 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -112,10 +112,5 @@ static inline void gpio_line_set(u8 line, int value) *IXP4XX_GPIO_GPOUTR &= ~(1 << line); } -static inline void gpio_line_isr_clear(u8 line) -{ - *IXP4XX_GPIO_GPISR = (1 << line); -} - #endif // __ASSEMBLY__ -- cgit v1.2.3 From 3145d8a6cc83ee15adf18f598873e53a54cd1841 Mon Sep 17 00:00:00 2001 From: Rod Whitby Date: Wed, 4 Jan 2006 17:17:11 +0000 Subject: [ARM] 3215/1: Iomega NAS 100d (MACH_NAS100D) machine support Patch from Rod Whitby This patch adds support for a new arm/ixp4xx machine - the Iomega NAS 100d network attached storage product. The NAS100D is a consumer device containing a 266MHz Intel IXP420 processor, 16MB of flash, 64MB of RAM, a 160Gb internal IDE hard disk, and 802.11b/g wireless on an Atheros mini-PCI card. Work on porting the latest 2.6.x kernel to this device is being done by the NSLU2-Linux project (the same team who maintains the port to the Linksys NSLU2 device). In particular, the majority of this patch was authored by Alessandro Zummo, based on the work done for MACH_NSLU2 support by the NSLU2-Linux core team of developers. MACH_NAS100D (as implemented by this patch) can be enabled in jumbo ixp4xx kernels without any affect on the other machines supported by that kernel. This patch applies cleanly against 2.6.15-rc7 and should be trivial to apply to later kernel versions. It does not depend upon any other patches. Modified files (and number of lines inserted): arch/arm/mach-ixp4xx/Kconfig | 8 arch/arm/mach-ixp4xx/Makefile | 1 include/asm-arm/arch-ixp4xx/hardware.h | 1 include/asm-arm/arch-ixp4xx/irqs.h | 9 include/asm-arm/arch-ixp4xx/nas100d.h | 75 arch/arm/mach-ixp4xx/nas100d-pci.c | 77 arch/arm/mach-ixp4xx/nas100d-power.c | 69 arch/arm/mach-ixp4xx/nas100d-setup.c | 133 -- Rod Whitby (NSLU2-Linux project lead) Signed-off-by: Rod Whitby Signed-off-by: Alessandro Zummo Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/Kconfig | 8 ++ arch/arm/mach-ixp4xx/Makefile | 1 + arch/arm/mach-ixp4xx/nas100d-pci.c | 77 +++++++++++++++++++ arch/arm/mach-ixp4xx/nas100d-power.c | 69 +++++++++++++++++ arch/arm/mach-ixp4xx/nas100d-setup.c | 133 +++++++++++++++++++++++++++++++++ include/asm-arm/arch-ixp4xx/hardware.h | 1 + include/asm-arm/arch-ixp4xx/irqs.h | 9 +++ include/asm-arm/arch-ixp4xx/nas100d.h | 75 +++++++++++++++++++ 8 files changed, 373 insertions(+) create mode 100644 arch/arm/mach-ixp4xx/nas100d-pci.c create mode 100644 arch/arm/mach-ixp4xx/nas100d-power.c create mode 100644 arch/arm/mach-ixp4xx/nas100d-setup.c create mode 100644 include/asm-arm/arch-ixp4xx/nas100d.h diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 385285851cb5..daadc78e271b 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -71,6 +71,14 @@ config ARCH_PRPMC1100 PrPCM1100 Processor Mezanine Module. For more information on this platform, see . +config MACH_NAS100D + bool + prompt "NAS100D" + help + Say 'Y' here if you want your kernel to support Iomega's + NAS 100d device. For more information on this platform, + see http://www.nslu2-linux.org/wiki/NAS100d/HomePage + # # Avila and IXDP share the same source for now. Will change in future # diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 7a15629c18d0..0471044fa179 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_MACH_IXDPG425) += ixdpg425-pci.o coyote-setup.o obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o obj-$(CONFIG_MACH_NSLU2) += nslu2-pci.o nslu2-setup.o nslu2-power.o +obj-$(CONFIG_MACH_NAS100D) += nas100d-pci.o nas100d-setup.o nas100d-power.o diff --git a/arch/arm/mach-ixp4xx/nas100d-pci.c b/arch/arm/mach-ixp4xx/nas100d-pci.c new file mode 100644 index 000000000000..9bd029462359 --- /dev/null +++ b/arch/arm/mach-ixp4xx/nas100d-pci.c @@ -0,0 +1,77 @@ +/* + * arch/arm/mach-ixp4xx/nas100d-pci.c + * + * NAS 100d board-level PCI initialization + * + * based on ixdp425-pci.c: + * Copyright (C) 2002 Intel Corporation. + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Maintainer: http://www.nslu2-linux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include +#include + +void __init nas100d_pci_preinit(void) +{ + set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW); + set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW); + set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW); + set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW); + set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW); + + gpio_line_isr_clear(NAS100D_PCI_INTA_PIN); + gpio_line_isr_clear(NAS100D_PCI_INTB_PIN); + gpio_line_isr_clear(NAS100D_PCI_INTC_PIN); + gpio_line_isr_clear(NAS100D_PCI_INTD_PIN); + gpio_line_isr_clear(NAS100D_PCI_INTE_PIN); + + ixp4xx_pci_preinit(); +} + +static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + static int pci_irq_table[NAS100D_PCI_MAX_DEV][NAS100D_PCI_IRQ_LINES] = + { + { IRQ_NAS100D_PCI_INTA, -1, -1 }, + { IRQ_NAS100D_PCI_INTB, -1, -1 }, + { IRQ_NAS100D_PCI_INTC, IRQ_NAS100D_PCI_INTD, IRQ_NAS100D_PCI_INTE }, + }; + + int irq = -1; + + if (slot >= 1 && slot <= NAS100D_PCI_MAX_DEV && + pin >= 1 && pin <= NAS100D_PCI_IRQ_LINES) + irq = pci_irq_table[slot-1][pin-1]; + + return irq; +} + +struct hw_pci __initdata nas100d_pci = { + .nr_controllers = 1, + .preinit = nas100d_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = nas100d_map_irq, +}; + +int __init nas100d_pci_init(void) +{ + if (machine_is_nas100d()) + pci_common_init(&nas100d_pci); + + return 0; +} + +subsys_initcall(nas100d_pci_init); diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c new file mode 100644 index 000000000000..c74a19004390 --- /dev/null +++ b/arch/arm/mach-ixp4xx/nas100d-power.c @@ -0,0 +1,69 @@ +/* + * arch/arm/mach-ixp4xx/nas100d-power.c + * + * NAS 100d Power/Reset driver + * + * Copyright (C) 2005 Tower Technologies + * + * based on nas100d-io.c + * Copyright (C) 2004 Karen Spearel + * + * Author: Alessandro Zummo + * Maintainers: http://www.nslu2-linux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include + +extern void ctrl_alt_del(void); + +static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + /* Signal init to do the ctrlaltdel action, this will bypass init if + * it hasn't started and do a kernel_restart. + */ + ctrl_alt_del(); + + return IRQ_HANDLED; +} + +static int __init nas100d_power_init(void) +{ + if (!(machine_is_nas100d())) + return 0; + + set_irq_type(NAS100D_RB_IRQ, IRQT_LOW); + + gpio_line_isr_clear(NAS100D_RB_GPIO); + + if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler, + SA_INTERRUPT, "NAS100D reset button", NULL) < 0) { + + printk(KERN_DEBUG "Reset Button IRQ %d not available\n", + NAS100D_RB_IRQ); + + return -EIO; + } + + return 0; +} + +static void __exit nas100d_power_exit(void) +{ + free_irq(NAS100D_RB_IRQ, NULL); +} + +module_init(nas100d_power_init); +module_exit(nas100d_power_exit); + +MODULE_AUTHOR("Alessandro Zummo "); +MODULE_DESCRIPTION("NAS100D Power/Reset driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c new file mode 100644 index 000000000000..bde9648e7afc --- /dev/null +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -0,0 +1,133 @@ +/* + * arch/arm/mach-ixp4xx/nas100d-setup.c + * + * NAS 100d board-setup + * + * based ixdp425-setup.c: + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * Author: Alessandro Zummo + * Author: Rod Whitby + * Maintainers: http://www.nslu2-linux.org/ + * + */ + +#include +#include +#include + +#include +#include +#include + +static struct flash_platform_data nas100d_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource nas100d_flash_resource = { + .start = NAS100D_FLASH_BASE, + .end = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nas100d_flash = { + .name = "IXP4XX-Flash", + .id = 0, + .dev.platform_data = &nas100d_flash_data, + .num_resources = 1, + .resource = &nas100d_flash_resource, +}; + +static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = { + .sda_pin = NAS100D_SDA_PIN, + .scl_pin = NAS100D_SCL_PIN, +}; + +static struct platform_device nas100d_i2c_controller = { + .name = "IXP4XX-I2C", + .id = 0, + .dev.platform_data = &nas100d_i2c_gpio_pins, + .num_resources = 0, +}; + +static struct resource nas100d_uart_resources[] = { + { + .start = IXP4XX_UART1_BASE_PHYS, + .end = IXP4XX_UART1_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM, + }, + { + .start = IXP4XX_UART2_BASE_PHYS, + .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM, + } +}; + +static struct plat_serial8250_port nas100d_uart_data[] = { + { + .mapbase = IXP4XX_UART1_BASE_PHYS, + .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART1, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { + .mapbase = IXP4XX_UART2_BASE_PHYS, + .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { } +}; + +static struct platform_device nas100d_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev.platform_data = nas100d_uart_data, + .num_resources = 2, + .resource = nas100d_uart_resources, +}; + +static struct platform_device *nas100d_devices[] __initdata = { + &nas100d_i2c_controller, + &nas100d_flash, + &nas100d_uart, +}; + +static void nas100d_power_off(void) +{ + /* This causes the box to drop the power and go dead. */ + + /* enable the pwr cntl gpio */ + gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT); + + /* do the deed */ + gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH); +} + +static void __init nas100d_init(void) +{ + ixp4xx_sys_init(); + + pm_power_off = nas100d_power_off; + + platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices)); +} + +MACHINE_START(NAS100D, "Iomega NAS 100d") + /* Maintainer: www.nslu2-linux.org */ + .phys_ram = PHYS_OFFSET, + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC, + .boot_params = 0x00000100, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .init_machine = nas100d_init, +MACHINE_END diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h index cfb413c845f7..6acb69c95ef9 100644 --- a/include/asm-arm/arch-ixp4xx/hardware.h +++ b/include/asm-arm/arch-ixp4xx/hardware.h @@ -45,5 +45,6 @@ extern unsigned int processor_id; #include "coyote.h" #include "prpmc1100.h" #include "nslu2.h" +#include "nas100d.h" #endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h index 2cf4930372bc..f24b763ca18e 100644 --- a/include/asm-arm/arch-ixp4xx/irqs.h +++ b/include/asm-arm/arch-ixp4xx/irqs.h @@ -100,4 +100,13 @@ #define IRQ_NSLU2_PCI_INTB IRQ_IXP4XX_GPIO10 #define IRQ_NSLU2_PCI_INTC IRQ_IXP4XX_GPIO9 +/* + * NAS100D board IRQs + */ +#define IRQ_NAS100D_PCI_INTA IRQ_IXP4XX_GPIO11 +#define IRQ_NAS100D_PCI_INTB IRQ_IXP4XX_GPIO10 +#define IRQ_NAS100D_PCI_INTC IRQ_IXP4XX_GPIO9 +#define IRQ_NAS100D_PCI_INTD IRQ_IXP4XX_GPIO8 +#define IRQ_NAS100D_PCI_INTE IRQ_IXP4XX_GPIO7 + #endif diff --git a/include/asm-arm/arch-ixp4xx/nas100d.h b/include/asm-arm/arch-ixp4xx/nas100d.h new file mode 100644 index 000000000000..ce7a86a98fc2 --- /dev/null +++ b/include/asm-arm/arch-ixp4xx/nas100d.h @@ -0,0 +1,75 @@ +/* + * include/asm-arm/arch-ixp4xx/nas100d.h + * + * NAS100D platform specific definitions + * + * Copyright (c) 2005 Tower Technologies + * + * Author: Alessandro Zummo + * + * based on ixdp425.h: + * Copyright 2004 (c) MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __ASM_ARCH_HARDWARE_H__ +#error "Do not include this directly, instead #include " +#endif + +#define NAS100D_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS +#define NAS100D_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE + +#define NAS100D_SDA_PIN 6 +#define NAS100D_SCL_PIN 5 + +/* + * NAS100D PCI IRQs + */ +#define NAS100D_PCI_MAX_DEV 3 +#define NAS100D_PCI_IRQ_LINES 3 + + +/* PCI controller GPIO to IRQ pin mappings */ +#define NAS100D_PCI_INTA_PIN 11 +#define NAS100D_PCI_INTB_PIN 10 +#define NAS100D_PCI_INTC_PIN 9 +#define NAS100D_PCI_INTD_PIN 8 +#define NAS100D_PCI_INTE_PIN 7 + +/* GPIO */ + +#define NAS100D_GPIO0 0 +#define NAS100D_GPIO1 1 +#define NAS100D_GPIO2 2 +#define NAS100D_GPIO3 3 +#define NAS100D_GPIO4 4 +#define NAS100D_GPIO5 5 +#define NAS100D_GPIO6 6 +#define NAS100D_GPIO7 7 +#define NAS100D_GPIO8 8 +#define NAS100D_GPIO9 9 +#define NAS100D_GPIO10 10 +#define NAS100D_GPIO11 11 +#define NAS100D_GPIO12 12 +#define NAS100D_GPIO13 13 +#define NAS100D_GPIO14 14 +#define NAS100D_GPIO15 15 + + +/* Buttons */ + +#define NAS100D_PB_GPIO NAS100D_GPIO14 +#define NAS100D_RB_GPIO NAS100D_GPIO4 +#define NAS100D_PO_GPIO NAS100D_GPIO12 /* power off */ + +#define NAS100D_PB_IRQ IRQ_IXP4XX_GPIO14 +#define NAS100D_RB_IRQ IRQ_IXP4XX_GPIO4 + +/* +#define NAS100D_PB_BM (1L << NAS100D_PB_GPIO) +#define NAS100D_PO_BM (1L << NAS100D_PO_GPIO) +#define NAS100D_RB_BM (1L << NAS100D_RB_GPIO) +*/ -- cgit v1.2.3 From 8d27e6992bc6a7ca7eaa1d29fb1a8d6cb6022c45 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Wed, 4 Jan 2006 17:17:12 +0000 Subject: [ARM] 3220/1: Remove gpio_isr_line_clear() from NAS 100d Patch from Deepak Saxena This patch removes referneces to gpio_isr_line_clear() from the NAS 100d platform implementation. Depends on 3192/1 and 3215/1 Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/nas100d-pci.c | 6 ------ arch/arm/mach-ixp4xx/nas100d-power.c | 2 -- 2 files changed, 8 deletions(-) diff --git a/arch/arm/mach-ixp4xx/nas100d-pci.c b/arch/arm/mach-ixp4xx/nas100d-pci.c index 9bd029462359..26b7c001ff64 100644 --- a/arch/arm/mach-ixp4xx/nas100d-pci.c +++ b/arch/arm/mach-ixp4xx/nas100d-pci.c @@ -30,12 +30,6 @@ void __init nas100d_pci_preinit(void) set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW); set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW); - gpio_line_isr_clear(NAS100D_PCI_INTA_PIN); - gpio_line_isr_clear(NAS100D_PCI_INTB_PIN); - gpio_line_isr_clear(NAS100D_PCI_INTC_PIN); - gpio_line_isr_clear(NAS100D_PCI_INTD_PIN); - gpio_line_isr_clear(NAS100D_PCI_INTE_PIN); - ixp4xx_pci_preinit(); } diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c index c74a19004390..2bec69bfa715 100644 --- a/arch/arm/mach-ixp4xx/nas100d-power.c +++ b/arch/arm/mach-ixp4xx/nas100d-power.c @@ -42,8 +42,6 @@ static int __init nas100d_power_init(void) set_irq_type(NAS100D_RB_IRQ, IRQT_LOW); - gpio_line_isr_clear(NAS100D_RB_GPIO); - if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler, SA_INTERRUPT, "NAS100D reset button", NULL) < 0) { -- cgit v1.2.3 From 313cbb5519405966e3e65fca86c0305ab24f2a3b Mon Sep 17 00:00:00 2001 From: Rod Whitby Date: Wed, 4 Jan 2006 17:17:13 +0000 Subject: [ARM] 3218/1: PAGE_SHIFT undeclared in arch-ixp4xx/memory.h (adjust_zones moved out of line) Patch from Rod Whitby PAGE_SHIFT is undeclared in include/asm-arm/arch-ixp4xx/memory.h, identified by the following kernel compilation error: CC [M] sound/core/memory.o In file included from include/asm/memory.h:27, from include/asm/io.h:28, from sound/core/memory.c:24: include/asm/arch/memory.h: In function `__arch_adjust_zones': include/asm/arch/memory.h:28: error: `PAGE_SHIFT' undeclared (first use in this function) This patch replaces my previous attempt at fixing this problem (Patch 3214/1) and is based on the following feedback: Russell King wrote: > The error you see came up on SA1100. The best solution was to move > the __arch_adjust_zones() function out of line. I suggest ixp4xx > does the same. I have moved the function out of line into arch/arm/mach-ixp4xx/common-pci.c as suggested. Signed-off-by: Rod Whitby Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/common-pci.c | 23 +++++++++++++++++++++++ include/asm-arm/arch-ixp4xx/memory.h | 25 ++----------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index 9795da270e3a..6e3462ed5306 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -341,6 +341,29 @@ int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M); } +/* + * Only first 64MB of memory can be accessed via PCI. + * We use GFP_DMA to allocate safe buffers to do map/unmap. + * This is really ugly and we need a better way of specifying + * DMA-capable regions of memory. + */ +void __init ixp4xx_adjust_zones(int node, unsigned long *zone_size, + unsigned long *zhole_size) +{ + unsigned int sz = SZ_64M >> PAGE_SHIFT; + + /* + * Only adjust if > 64M on current system + */ + if (node || (zone_size[0] <= sz)) + return; + + zone_size[1] = zone_size[0] - sz; + zone_size[0] = sz; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + void __init ixp4xx_pci_preinit(void) { unsigned long processor_id; diff --git a/include/asm-arm/arch-ixp4xx/memory.h b/include/asm-arm/arch-ixp4xx/memory.h index e024d0a1a669..ee211d28a3ef 100644 --- a/include/asm-arm/arch-ixp4xx/memory.h +++ b/include/asm-arm/arch-ixp4xx/memory.h @@ -16,31 +16,10 @@ #ifndef __ASSEMBLY__ -/* - * Only first 64MB of memory can be accessed via PCI. - * We use GFP_DMA to allocate safe buffers to do map/unmap. - * This is really ugly and we need a better way of specifying - * DMA-capable regions of memory. - */ -static inline void __arch_adjust_zones(int node, unsigned long *zone_size, - unsigned long *zhole_size) -{ - unsigned int sz = SZ_64M >> PAGE_SHIFT; - - /* - * Only adjust if > 64M on current system - */ - if (node || (zone_size[0] <= sz)) - return; - - zone_size[1] = zone_size[0] - sz; - zone_size[0] = sz; - zhole_size[1] = zhole_size[0]; - zhole_size[0] = 0; -} +void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes); #define arch_adjust_zones(node, size, holes) \ - __arch_adjust_zones(node, size, holes) + ixp4xx_adjust_zones(node, size, holes) #define ISA_DMA_THRESHOLD (SZ_64M - 1) -- cgit v1.2.3 From b1ad3a57d39001af413414c34feb5cd41d0f7917 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Wed, 4 Jan 2006 17:17:14 +0000 Subject: [ARM] 3221/1: Update IXP4xx defconfig Patch from Deepak Saxena Add NAS 100d to machine build list and update to new 2.6.15 options. Signed-off-by: Deepak Saxena --- Signed-off-by: Russell King --- arch/arm/configs/ixp4xx_defconfig | 84 ++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index f74c926beb42..613afab62720 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14-rc1-git5 -# Tue Sep 20 17:26:28 2005 +# Linux kernel version: 2.6.15 +# Tue Jan 3 03:20:40 2006 # CONFIG_ARM=y CONFIG_MMU=y @@ -33,6 +33,7 @@ CONFIG_SYSCTL=y CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set @@ -42,7 +43,6 @@ CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 @@ -61,6 +61,23 @@ CONFIG_MODVERSIONS=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y +# +# Block layer +# + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + # # System Type # @@ -83,6 +100,7 @@ CONFIG_ARCH_IXP4XX=y # CONFIG_ARCH_LH7A40X is not set # CONFIG_ARCH_OMAP is not set # CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_REALVIEW is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set # CONFIG_ARCH_AAEC2000 is not set @@ -102,6 +120,7 @@ CONFIG_MACH_IXDPG425=y CONFIG_MACH_IXDP465=y CONFIG_ARCH_IXCDP1100=y CONFIG_ARCH_PRPMC1100=y +CONFIG_MACH_NAS100D=y CONFIG_ARCH_IXDP4XX=y CONFIG_CPU_IXP46X=y # CONFIG_MACH_GTWX5715 is not set @@ -155,6 +174,7 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 CONFIG_ALIGNMENT_TRAP=y # @@ -173,6 +193,7 @@ CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs" # At least one emulation must be selected # CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set # CONFIG_FPE_FASTFPE is not set # @@ -187,6 +208,8 @@ CONFIG_BINFMT_ELF=y # Power management options # CONFIG_PM=y +CONFIG_PM_LEGACY=y +# CONFIG_PM_DEBUG is not set CONFIG_APM=y # @@ -271,6 +294,10 @@ CONFIG_IP_VS_SH=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# # CONFIG_NETFILTER_NETLINK is not set # @@ -286,6 +313,7 @@ CONFIG_IP_NF_IRC=m # CONFIG_IP_NF_NETBIOS_NS is not set # CONFIG_IP_NF_TFTP is not set # CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_PPTP is not set CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_LIMIT=m @@ -319,6 +347,7 @@ CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_LOG=m CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_TARGET_NFQUEUE is not set CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m @@ -380,10 +409,18 @@ CONFIG_ECONET=m CONFIG_ECONET_AUNUDP=y CONFIG_ECONET_NATIVE=y CONFIG_WAN_ROUTER=m + +# +# QoS and/or fair queueing +# CONFIG_NET_SCHED=y CONFIG_NET_SCH_CLK_JIFFIES=y # CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set # CONFIG_NET_SCH_CLK_CPU is not set + +# +# Queueing/Scheduling +# CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m # CONFIG_NET_SCH_HFSC is not set @@ -397,8 +434,10 @@ CONFIG_NET_SCH_GRED=m CONFIG_NET_SCH_DSMARK=m # CONFIG_NET_SCH_NETEM is not set CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_QOS=y -CONFIG_NET_ESTIMATOR=y + +# +# Classification +# CONFIG_NET_CLS=y # CONFIG_NET_CLS_BASIC is not set CONFIG_NET_CLS_TCINDEX=m @@ -407,13 +446,14 @@ CONFIG_NET_CLS_ROUTE=y CONFIG_NET_CLS_FW=m CONFIG_NET_CLS_U32=m # CONFIG_CLS_U32_PERF is not set -# CONFIG_NET_CLS_IND is not set # CONFIG_CLS_U32_MARK is not set CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m # CONFIG_NET_EMATCH is not set # CONFIG_NET_CLS_ACT is not set CONFIG_NET_CLS_POLICE=y +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_ESTIMATOR=y # # Network testing @@ -436,6 +476,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -458,6 +503,7 @@ CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set # # RAM/ROM/Flash chip drivers @@ -492,7 +538,6 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y # CONFIG_MTD_PHYSMAP is not set # CONFIG_MTD_ARM_INTEGRATOR is not set CONFIG_MTD_IXP4XX=y -# CONFIG_MTD_EDB7312 is not set # CONFIG_MTD_PCI is not set # CONFIG_MTD_PLATRAM is not set @@ -522,6 +567,11 @@ CONFIG_MTD_NAND_IDS=m # CONFIG_MTD_NAND_DISKONCHIP is not set # CONFIG_MTD_NAND_NANDSIM is not set +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + # # Parallel port support # @@ -548,14 +598,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y # CONFIG_ATA_OVER_ETH is not set # @@ -668,6 +710,7 @@ CONFIG_NET_ETHERNET=y CONFIG_MII=y # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set # CONFIG_DM9000 is not set @@ -739,6 +782,7 @@ CONFIG_NET_RADIO=y # # Wireless 802.11b ISA/PCI cards support # +# CONFIG_AIRO is not set CONFIG_HERMES=y # CONFIG_PLX_HERMES is not set # CONFIG_TMD_HERMES is not set @@ -782,6 +826,7 @@ CONFIG_WAN_ROUTER_DRIVERS=y # # ATM drivers # +# CONFIG_ATM_DUMMY is not set CONFIG_ATM_TCP=m # CONFIG_ATM_LANAI is not set # CONFIG_ATM_ENI is not set @@ -902,6 +947,7 @@ CONFIG_IXP4XX_WATCHDOG=y # TPM devices # # CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # # I2C support @@ -954,6 +1000,7 @@ CONFIG_SENSORS_EEPROM=y # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set # CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -1035,6 +1082,10 @@ CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y # CONFIG_USB is not set +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + # # USB Gadget Support # @@ -1110,6 +1161,7 @@ CONFIG_RAMFS=y CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -1190,7 +1242,9 @@ CONFIG_DETECT_SOFTLOCKUP=y CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set CONFIG_FRAME_POINTER=y +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_WAITQ is not set CONFIG_DEBUG_ERRORS=y -- cgit v1.2.3 From b721243a6700b2ecc11f7b920d3d5d6718c5d148 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 4 Jan 2006 17:17:15 +0000 Subject: [ARM] 3223/1: remove ixdp2x01 cs89x0 hack Patch from Lennert Buytenhek Remove the ixdp2x01 cs89x0 hack from ixp2000's io implementation. Since the cs89x0 driver has been made properly aware of the odd way the cs89x0 is hooked up on the ixdp2x01, we don't need this hack anymore. Signed-off-by: Lennert Buytenhek Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/io.h | 98 --------------------------------------- 1 file changed, 98 deletions(-) diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h index 7fbcdf9931ee..c0ff2c6c66e7 100644 --- a/include/asm-arm/arch-ixp2000/io.h +++ b/include/asm-arm/arch-ixp2000/io.h @@ -131,102 +131,4 @@ #endif -#ifdef CONFIG_ARCH_IXDP2X01 -/* - * This is an ugly hack but the CS8900 on the 2x01's does not sit in any sort - * of "I/O space" and is just direct mapped into a 32-bit-only addressable - * bus. The address space for this bus is such that we can't really easily - * make it contiguous to the PCI I/O address range, and it also does not - * need swapping like PCI addresses do (IXDP2x01 is a BE platform). - * B/C of this we can't use the standard in/out functions and need to - * runtime check if the incoming address is a PCI address or for - * the CS89x0. - */ -#undef inw -#undef outw -#undef insw -#undef outsw - -#include - -static inline void insw(u32 ptr, void *buf, int length) -{ - register volatile u32 *port = (volatile u32 *)ptr; - - /* - * Is this cycle meant for the CS8900? - */ - if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && - (((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) && - ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) { - u8 *buf8 = (u8*)buf; - register u32 tmp32; - - do { - tmp32 = *port; - *buf8++ = (u8)tmp32; - *buf8++ = (u8)(tmp32 >> 8); - } while(--length); - - return; - } - - __raw_readsw(alignw(___io(ptr)),buf,length); -} - -static inline void outsw(u32 ptr, void *buf, int length) -{ - register volatile u32 *port = (volatile u32 *)ptr; - - /* - * Is this cycle meant for the CS8900? - */ - if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && - (((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) && - ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) { - register u32 tmp32; - u8 *buf8 = (u8*)buf; - do { - tmp32 = *buf8++; - tmp32 |= (*buf8++) << 8; - *port = tmp32; - } while(--length); - return; - } - - __raw_writesw(alignw(___io(ptr)),buf,length); -} - - -static inline u16 inw(u32 ptr) -{ - register volatile u32 *port = (volatile u32 *)ptr; - - /* - * Is this cycle meant for the CS8900? - */ - if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && - (((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) && - ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) { - return (u16)(*port); - } - - return __raw_readw(alignw(___io(ptr))); -} - -static inline void outw(u16 value, u32 ptr) -{ - register volatile u32 *port = (volatile u32 *)ptr; - - if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && - (((u32)port >= (u32)IXDP2X01_CS8900_VIRT_BASE) && - ((u32)port <= (u32)IXDP2X01_CS8900_VIRT_END))) { - *port = value; - return; - } - - __raw_writew((value),alignw(___io(ptr))); -} -#endif /* IXDP2x01 */ - #endif -- cgit v1.2.3 From 7a94283a7e8cd8a4ea29bf2cfedba511c706b0b4 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 4 Jan 2006 17:17:16 +0000 Subject: [ARM] 3224/1: add masked thread interrupt status registers for ixp2000 Patch from Lennert Buytenhek In its interrupt handler, the (NAPI) ixp2000 netdev driver needs to use the masked thread interrupt status register (instead of the raw one) to prevent scheduling polling when polling is already running when a TXdone interrupt comes in. The definitions for the masked status registers were not in yet, so this patch adds them. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/ixp2000-regs.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index fc5ac6aec4f2..8cf70ff160af 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -156,6 +156,14 @@ #define IXP2000_IRQ_THD_RAW_STATUS_B_1 IXP2000_INTCTL_REG(0x84) #define IXP2000_IRQ_THD_RAW_STATUS_B_2 IXP2000_INTCTL_REG(0x88) #define IXP2000_IRQ_THD_RAW_STATUS_B_3 IXP2000_INTCTL_REG(0x8c) +#define IXP2000_IRQ_THD_STATUS_A_0 IXP2000_INTCTL_REG(0xe0) +#define IXP2000_IRQ_THD_STATUS_A_1 IXP2000_INTCTL_REG(0xe4) +#define IXP2000_IRQ_THD_STATUS_A_2 IXP2000_INTCTL_REG(0xe8) +#define IXP2000_IRQ_THD_STATUS_A_3 IXP2000_INTCTL_REG(0xec) +#define IXP2000_IRQ_THD_STATUS_B_0 IXP2000_INTCTL_REG(0x100) +#define IXP2000_IRQ_THD_STATUS_B_1 IXP2000_INTCTL_REG(0x104) +#define IXP2000_IRQ_THD_STATUS_B_2 IXP2000_INTCTL_REG(0x108) +#define IXP2000_IRQ_THD_STATUS_B_3 IXP2000_INTCTL_REG(0x10c) #define IXP2000_IRQ_THD_ENABLE_SET_A_0 IXP2000_INTCTL_REG(0x160) #define IXP2000_IRQ_THD_ENABLE_SET_A_1 IXP2000_INTCTL_REG(0x164) #define IXP2000_IRQ_THD_ENABLE_SET_A_2 IXP2000_INTCTL_REG(0x168) -- cgit v1.2.3 From 4c70b926c91ba9c1ce3dc92d418f8e4670c8f16d Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 4 Jan 2006 17:17:17 +0000 Subject: [ARM] 3225/1: add symbolic names for enp2611 gpio interrupts Patch from Lennert Buytenhek Add symbolic names for the five ixp2400 GPIO lines on the enp2611 that are used as interrupts. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- include/asm-arm/arch-ixp2000/enp2611.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/asm-arm/arch-ixp2000/enp2611.h b/include/asm-arm/arch-ixp2000/enp2611.h index 95128d9f5026..42f3c28dc5c4 100644 --- a/include/asm-arm/arch-ixp2000/enp2611.h +++ b/include/asm-arm/arch-ixp2000/enp2611.h @@ -36,5 +36,11 @@ #define ENP2611_GPIO_SCL 7 #define ENP2611_GPIO_SDA 6 +#define IRQ_ENP2611_THERMAL IRQ_IXP2000_GPIO4 +#define IRQ_ENP2611_OPTION_BOARD IRQ_IXP2000_GPIO3 +#define IRQ_ENP2611_CALEB IRQ_IXP2000_GPIO2 +#define IRQ_ENP2611_PM3386_1 IRQ_IXP2000_GPIO1 +#define IRQ_ENP2611_PM3386_0 IRQ_IXP2000_GPIO0 + #endif -- cgit v1.2.3 From 1624f003349b49050f42c7d9f5407dfc05efb912 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 4 Jan 2006 18:09:44 +0000 Subject: [SERIAL] Fix matching of MMIO ports The function uart_match_port() incorrectly compares the ioremap'd virtual addresses of ports instead of the physical address to find duplicate ports for MMIO based UARTs. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Russell King --- drivers/serial/serial_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index c17d680e3f04..34c576dfad8d 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2307,7 +2307,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) return (port1->iobase == port2->iobase) && (port1->hub6 == port2->hub6); case UPIO_MEM: - return (port1->membase == port2->membase); + return (port1->mapbase == port2->mapbase); } return 0; } -- cgit v1.2.3 From 50aec3b561de4e435204ad315e5c5ab58ef9feda Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 18:13:03 +0000 Subject: [SERIAL] Use uart_match_port() to find a matching port in find_port() Signed-off-by: Russell King --- drivers/serial/8250.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 076bf848e4d1..ad20d2dd85d7 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2299,9 +2299,7 @@ static int __init find_port(struct uart_port *p) for (line = 0; line < UART_NR; line++) { port = &serial8250_ports[line].port; - if (p->iotype == port->iotype && - p->iobase == port->iobase && - p->membase == port->membase) + if (uart_match_port(p, port)) return line; } return -ENODEV; -- cgit v1.2.3 From 45e24601921fc1c4ca7932f7f7a475d3ad64ecad Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 19:19:06 +0000 Subject: [SERIAL] Move interrupt-time spinlocking inside serial8250_handle_port() All call sites for serial8250_handle_port() acquired the port spinlock and released it afterwards. This is a needless duplication of code. Move the spinlocking inside serial8250_handle_port(). Signed-off-by: Russell King --- drivers/serial/8250.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index ad20d2dd85d7..56dcfd93bdc4 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1281,7 +1281,11 @@ static unsigned int check_modem_status(struct uart_8250_port *up) static inline void serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) { - unsigned int status = serial_inp(up, UART_LSR); + unsigned int status; + + spin_lock(&up->port.lock); + + status = serial_inp(up, UART_LSR); DEBUG_INTR("status = %x...", status); @@ -1290,6 +1294,8 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); + + spin_unlock(&up->port.lock); } /* @@ -1325,9 +1331,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) { - spin_lock(&up->port.lock); serial8250_handle_port(up, regs); - spin_unlock(&up->port.lock); handled = 1; @@ -1426,11 +1430,8 @@ static void serial8250_timeout(unsigned long data) unsigned int iir; iir = serial_in(up, UART_IIR); - if (!(iir & UART_IIR_NO_INT)) { - spin_lock(&up->port.lock); + if (!(iir & UART_IIR_NO_INT)) serial8250_handle_port(up, NULL); - spin_unlock(&up->port.lock); - } timeout = up->port.timeout; timeout = timeout > 6 ? (timeout / 2 - 2) : 1; -- cgit v1.2.3 From ea8874dc3881c2a496a4bd6bc981f707cc6a0db1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 4 Jan 2006 19:43:24 +0000 Subject: [SERIAL] Remove _INLINE_ Signed-off-by: Russell King --- drivers/serial/8250.c | 8 ++++---- drivers/serial/8250.h | 6 ------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 56dcfd93bdc4..1891cf5bdeef 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -296,7 +296,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) #endif -static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) +static unsigned int serial_in(struct uart_8250_port *up, int offset) { offset = map_8250_in_reg(up, offset) << up->port.regshift; @@ -321,7 +321,7 @@ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) } } -static _INLINE_ void +static void serial_out(struct uart_8250_port *up, int offset, int value) { offset = map_8250_out_reg(up, offset) << up->port.regshift; @@ -1131,7 +1131,7 @@ static void serial8250_enable_ms(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -static _INLINE_ void +static void receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) { struct tty_struct *tty = up->port.info->tty; @@ -1217,7 +1217,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) *status = lsr; } -static _INLINE_ void transmit_chars(struct uart_8250_port *up) +static void transmit_chars(struct uart_8250_port *up) { struct circ_buf *xmit = &up->port.info->xmit; int count; diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h index a607b98016db..490606b87095 100644 --- a/drivers/serial/8250.h +++ b/drivers/serial/8250.h @@ -51,12 +51,6 @@ struct serial8250_config { #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ #define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ -#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) -#define _INLINE_ inline -#else -#define _INLINE_ -#endif - #define PROBE_RSA (1 << 0) #define PROBE_ANY (~0) -- cgit v1.2.3 From 1d7d2f6f476cf7aa65f9f740a6c932fb75608110 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 4 Jan 2006 14:42:39 -0800 Subject: IB/mthca: fix WQE size calculation in create-srq Thinko: 64 bytes is the minimum SRQ WQE size (not the maximum). Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_srq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index f7d234295efe..e7e153d9c4c6 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -201,7 +201,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, if (mthca_is_memfree(dev)) srq->max = roundup_pow_of_two(srq->max + 1); - ds = min(64UL, + ds = max(64UL, roundup_pow_of_two(sizeof (struct mthca_next_seg) + srq->max_gs * sizeof (struct mthca_data_seg))); srq->wqe_shift = long_log2(ds); -- cgit v1.2.3 From f3e2628bed0d5a88ced8239b35f1534557f9631c Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Thu, 5 Jan 2006 10:31:23 +0000 Subject: [MMC] mmci: kunmap_atomic() unmaps virtual address, not page Signed-off-by: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Russell King --- drivers/mmc/mmci.c | 2 +- drivers/mmc/mmci.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 6d161c70014a..2b10a2d4ae09 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -300,7 +300,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) /* * Unmap the buffer. */ - mmci_kunmap_atomic(host, &flags); + mmci_kunmap_atomic(host, buffer, &flags); host->sg_off += len; host->size -= len; diff --git a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h index 4589bbd68192..6d7eadc9a678 100644 --- a/drivers/mmc/mmci.h +++ b/drivers/mmc/mmci.h @@ -172,8 +172,8 @@ static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flag return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; } -static inline void mmci_kunmap_atomic(struct mmci_host *host, unsigned long *flags) +static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags) { - kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); + kunmap_atomic(buffer, KM_BIO_SRC_IRQ); local_irq_restore(*flags); } -- cgit v1.2.3 From dd68e88c72ac9ad25052065c4a443326eda6a052 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 5 Jan 2006 10:55:26 +0000 Subject: [SERIAL] 8520_pci: build fix _INLINE_ went away. Signed-off-by: Andrew Morton Signed-off-by: Russell King --- drivers/serial/8250_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 4a589a9456f5..589fb076654a 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -837,8 +837,8 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) return quirk; } -static _INLINE_ int -get_pci_irq(struct pci_dev *dev, struct pciserial_board *board) +static inline int get_pci_irq(struct pci_dev *dev, + struct pciserial_board *board) { if (board->flags & FL_NOIRQ) return 0; -- cgit v1.2.3 From 3125c68d70e3433c21234431a9df9e7336efa29f Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 5 Jan 2006 20:44:52 +0000 Subject: [ARM] 3227/1: Spitz: Add pxa27x OHCI platform specific code Patch from Richard Purdie Add platform code to enable the ohci device on the pxa27x based Sharp Zaurus Cxx00 devices. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/spitz.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 2df1b56615b1..5d34abc64af7 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -334,6 +335,35 @@ static struct pxamci_platform_data spitz_mci_platform_data = { }; +/* + * USB Host (OHCI) + */ +static int spitz_ohci_init(struct device *dev) +{ + /* Only Port 2 is connected */ + pxa_gpio_mode(SPITZ_GPIO_USB_CONNECT | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_USB_HOST | GPIO_OUT); + pxa_gpio_mode(SPITZ_GPIO_USB_DEVICE | GPIO_IN); + + /* Setup USB Port 2 Output Control Register */ + UP2OCR = UP2OCR_HXS | UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE; + + GPSR(SPITZ_GPIO_USB_HOST) = GPIO_bit(SPITZ_GPIO_USB_HOST); + + UHCHR = (UHCHR) & + ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); + + UHCRHDA |= UHCRHDA_NOCP; + + return 0; +} + +static struct pxaohci_platform_data spitz_ohci_platform_data = { + .port_mode = PMM_NPS_MODE, + .init = spitz_ohci_init, +}; + + /* * Irda */ @@ -411,6 +441,7 @@ static void __init common_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_mci_info(&spitz_mci_platform_data); + pxa_set_ohci_info(&spitz_ohci_platform_data); pxa_set_ficp_info(&spitz_ficp_platform_data); set_pxa_fb_parent(&spitzssp_device.dev); set_pxa_fb_info(&spitz_pxafb_info); -- cgit v1.2.3 From b7557de41a04346cb545d4dda7088760cb96e713 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 5 Jan 2006 20:44:55 +0000 Subject: [ARM] 3228/1: SharpSL: Move PM code to arch/arm/common Patch from Richard Purdie This patch moves a large chunk of the sharpsl_pm driver to arch/arm/common so that it can be reused on other devices such as the SL-5500 (collie). It also abstracts some functions from the core into the machine and platform specific parts of the driver to aid reuse. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/common/Kconfig | 3 + arch/arm/common/Makefile | 1 + arch/arm/common/sharpsl_pm.c | 839 ++++++++++++++++++++++++++++++++++ arch/arm/mach-pxa/Kconfig | 2 + arch/arm/mach-pxa/corgi_pm.c | 45 +- arch/arm/mach-pxa/sharpsl.h | 100 +--- arch/arm/mach-pxa/sharpsl_pm.c | 825 +-------------------------------- arch/arm/mach-pxa/spitz_pm.c | 47 +- drivers/video/backlight/corgi_bl.c | 1 + include/asm-arm/hardware/sharpsl_pm.h | 94 ++++ 10 files changed, 1016 insertions(+), 941 deletions(-) create mode 100644 arch/arm/common/sharpsl_pm.c create mode 100644 include/asm-arm/hardware/sharpsl_pm.h diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 666ba393575b..d7509c7a3c5e 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -23,5 +23,8 @@ config SHARP_LOCOMO config SHARP_PARAM bool +config SHARPSL_PM + bool + config SHARP_SCOOP bool diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index a87886564b19..2685051b3013 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -13,4 +13,5 @@ obj-$(CONFIG_DMABOUNCE) += dmabounce.o obj-$(CONFIG_TIMER_ACORN) += time-acorn.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o +obj-$(CONFIG_SHARPSL_PM) += sharpsl_pm.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c new file mode 100644 index 000000000000..978d32e82d39 --- /dev/null +++ b/arch/arm/common/sharpsl_pm.c @@ -0,0 +1,839 @@ +/* + * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00 + * series of PDAs + * + * Copyright (c) 2004-2005 Richard Purdie + * + * Based on code written by Sharp for 2.4 kernels + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants + */ +#define SHARPSL_CHARGE_ON_TIME_INTERVAL (msecs_to_jiffies(1*60*1000)) /* 1 min */ +#define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */ +#define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */ +#define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */ +#define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */ +#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */ +#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */ +#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */ +#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */ +#define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */ +#define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */ +#define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */ + +#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ +#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ +#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */ +#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */ +#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ +#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ + +/* + * Prototypes + */ +static int sharpsl_off_charge_battery(void); +static int sharpsl_check_battery_temp(void); +static int sharpsl_check_battery_voltage(void); +static int sharpsl_ac_check(void); +static int sharpsl_fatal_check(void); +static int sharpsl_average_value(int ad); +static void sharpsl_average_clear(void); +static void sharpsl_charge_toggle(void *private_); +static void sharpsl_battery_thread(void *private_); + + +/* + * Variables + */ +struct sharpsl_pm_status sharpsl_pm; +DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); +DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); + + +static int get_percentage(int voltage) +{ + int i = sharpsl_pm.machinfo->bat_levels - 1; + struct battery_thresh *thresh; + + if (sharpsl_pm.charge_mode == CHRG_ON) + thresh=sharpsl_pm.machinfo->bat_levels_acin; + else + thresh=sharpsl_pm.machinfo->bat_levels_noac; + + while (i > 0 && (voltage > thresh[i].voltage)) + i--; + + return thresh[i].percentage; +} + +static int get_apm_status(int voltage) +{ + int low_thresh, high_thresh; + + if (sharpsl_pm.charge_mode == CHRG_ON) { + high_thresh = sharpsl_pm.machinfo->status_high_acin; + low_thresh = sharpsl_pm.machinfo->status_low_acin; + } else { + high_thresh = sharpsl_pm.machinfo->status_high_noac; + low_thresh = sharpsl_pm.machinfo->status_low_noac; + } + + if (voltage >= high_thresh) + return APM_BATTERY_STATUS_HIGH; + if (voltage >= low_thresh) + return APM_BATTERY_STATUS_LOW; + return APM_BATTERY_STATUS_CRITICAL; +} + +void sharpsl_battery_kick(void) +{ + schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125)); +} +EXPORT_SYMBOL(sharpsl_battery_kick); + + +static void sharpsl_battery_thread(void *private_) +{ + int voltage, percent, apm_status, i = 0; + + if (!sharpsl_pm.machinfo) + return; + + sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE); + + /* Corgi cannot confirm when battery fully charged so periodically kick! */ + if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON) + && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) + schedule_work(&toggle_charger); + + while(1) { + voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); + + if (voltage > 0) break; + if (i++ > 5) { + voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage; + dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n"); + break; + } + } + + voltage = sharpsl_average_value(voltage); + apm_status = get_apm_status(voltage); + percent = get_percentage(voltage); + + /* At low battery voltages, the voltage has a tendency to start + creeping back up so we try to avoid this here */ + if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) || percent <= sharpsl_pm.battstat.mainbat_percent) { + sharpsl_pm.battstat.mainbat_voltage = voltage; + sharpsl_pm.battstat.mainbat_status = apm_status; + sharpsl_pm.battstat.mainbat_percent = percent; + } + + dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %d\n", voltage, + sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies); + + /* If battery is low. limit backlight intensity to save power. */ + if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) + && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) || + (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) { + if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) { + corgibl_limit_intensity(1); + sharpsl_pm.flags |= SHARPSL_BL_LIMIT; + } + } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) { + corgibl_limit_intensity(0); + sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT; + } + + /* Suspend if critical battery level */ + if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) + && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL) + && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) { + sharpsl_pm.flags |= SHARPSL_APM_QUEUED; + dev_err(sharpsl_pm.dev, "Fatal Off\n"); + apm_queue_event(APM_CRITICAL_SUSPEND); + } + + schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME); +} + +void sharpsl_pm_led(int val) +{ + if (val == SHARPSL_LED_ERROR) { + dev_err(sharpsl_pm.dev, "Charging Error!\n"); + } else if (val == SHARPSL_LED_ON) { + dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); + + } else { + dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); + + } +} + +static void sharpsl_charge_on(void) +{ + dev_dbg(sharpsl_pm.dev, "Turning Charger On\n"); + + sharpsl_pm.full_count = 0; + sharpsl_pm.charge_mode = CHRG_ON; + schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250)); + schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500)); +} + +static void sharpsl_charge_off(void) +{ + dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n"); + + sharpsl_pm.machinfo->charge(0); + sharpsl_pm_led(SHARPSL_LED_OFF); + sharpsl_pm.charge_mode = CHRG_OFF; + + schedule_work(&sharpsl_bat); +} + +static void sharpsl_charge_error(void) +{ + sharpsl_pm_led(SHARPSL_LED_ERROR); + sharpsl_pm.machinfo->charge(0); + sharpsl_pm.charge_mode = CHRG_ERROR; +} + +static void sharpsl_charge_toggle(void *private_) +{ + dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); + + if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { + sharpsl_charge_off(); + return; + } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) { + sharpsl_charge_error(); + return; + } + + sharpsl_pm_led(SHARPSL_LED_ON); + sharpsl_pm.machinfo->charge(0); + mdelay(SHARPSL_CHARGE_WAIT_TIME); + sharpsl_pm.machinfo->charge(1); + + sharpsl_pm.charge_start_time = jiffies; +} + +static void sharpsl_ac_timer(unsigned long data) +{ + int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); + + dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin); + + sharpsl_average_clear(); + if (acin && (sharpsl_pm.charge_mode != CHRG_ON)) + sharpsl_charge_on(); + else if (sharpsl_pm.charge_mode == CHRG_ON) + sharpsl_charge_off(); + + schedule_work(&sharpsl_bat); +} + + +irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp) +{ + /* Delay the event slightly to debounce */ + /* Must be a smaller delay than the chrg_full_isr below */ + mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +static void sharpsl_chrg_full_timer(unsigned long data) +{ + dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies); + + sharpsl_pm.full_count++; + + if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { + dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n"); + if (sharpsl_pm.charge_mode == CHRG_ON) + sharpsl_charge_off(); + } else if (sharpsl_pm.full_count < 2) { + dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); + schedule_work(&toggle_charger); + } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { + dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); + schedule_work(&toggle_charger); + } else { + sharpsl_charge_off(); + sharpsl_pm.charge_mode = CHRG_DONE; + dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n"); + } +} + +/* Charging Finished Interrupt (Not present on Corgi) */ +/* Can trigger at the same time as an AC staus change so + delay until after that has been processed */ +irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp) +{ + if (sharpsl_pm.flags & SHARPSL_SUSPENDED) + return IRQ_HANDLED; + + /* delay until after any ac interrupt */ + mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500)); + + return IRQ_HANDLED; +} + +irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp) +{ + int is_fatal = 0; + + if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) { + dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n"); + is_fatal = 1; + } + + if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) { + dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n"); + is_fatal = 1; + } + + if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) { + sharpsl_pm.flags |= SHARPSL_APM_QUEUED; + apm_queue_event(APM_CRITICAL_SUSPEND); + } + + return IRQ_HANDLED; +} + +/* + * Maintain an average of the last 10 readings + */ +#define SHARPSL_CNV_VALUE_NUM 10 +static int sharpsl_ad_index; + +static void sharpsl_average_clear(void) +{ + sharpsl_ad_index = 0; +} + +static int sharpsl_average_value(int ad) +{ + int i, ad_val = 0; + static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1]; + + if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) { + sharpsl_ad_index = 0; + return ad; + } + + sharpsl_ad[sharpsl_ad_index] = ad; + sharpsl_ad_index++; + if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) { + for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++) + sharpsl_ad[i] = sharpsl_ad[i+1]; + sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1; + } + for (i=0; i < sharpsl_ad_index; i++) + ad_val += sharpsl_ad[i]; + + return (ad_val / sharpsl_ad_index); +} + +/* + * Take an array of 5 integers, remove the maximum and minimum values + * and return the average. + */ +static int get_select_val(int *val) +{ + int i, j, k, temp, sum = 0; + + /* Find MAX val */ + temp = val[0]; + j=0; + for (i=1; i<5; i++) { + if (temp < val[i]) { + temp = val[i]; + j = i; + } + } + + /* Find MIN val */ + temp = val[4]; + k=4; + for (i=3; i>=0; i--) { + if (temp > val[i]) { + temp = val[i]; + k = i; + } + } + + for (i=0; i<5; i++) + if (i != j && i != k ) + sum += val[i]; + + dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]); + + return (sum/3); +} + +static int sharpsl_check_battery_temp(void) +{ + int val, i, buff[5]; + + /* Check battery temperature */ + for (i=0; i<5; i++) { + mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); + sharpsl_pm.machinfo->measure_temp(1); + mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); + buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP); + sharpsl_pm.machinfo->measure_temp(0); + } + + val = get_select_val(buff); + + dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); + if (val > SHARPSL_CHARGE_ON_TEMP) + return -1; + + return 0; +} + +static int sharpsl_check_battery_voltage(void) +{ + int val, i, buff[5]; + + /* disable charge, enable discharge */ + sharpsl_pm.machinfo->charge(0); + sharpsl_pm.machinfo->discharge(1); + mdelay(SHARPSL_WAIT_DISCHARGE_ON); + + if (sharpsl_pm.machinfo->discharge1) + sharpsl_pm.machinfo->discharge1(1); + + /* Check battery voltage */ + for (i=0; i<5; i++) { + buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); + mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); + } + + if (sharpsl_pm.machinfo->discharge1) + sharpsl_pm.machinfo->discharge1(0); + + sharpsl_pm.machinfo->discharge(0); + + val = get_select_val(buff); + dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val); + + if (val < SHARPSL_CHARGE_ON_VOLT) + return -1; + + return 0; +} + +static int sharpsl_ac_check(void) +{ + int temp, i, buff[5]; + + for (i=0; i<5; i++) { + buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT); + mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN); + } + + temp = get_select_val(buff); + dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp); + + if ((temp > SHARPSL_CHARGE_ON_ACIN_HIGH) || (temp < SHARPSL_CHARGE_ON_ACIN_LOW)) { + dev_err(sharpsl_pm.dev, "Error: AC check failed.\n"); + return -1; + } + + return 0; +} + +#ifdef CONFIG_PM +static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state) +{ + sharpsl_pm.flags |= SHARPSL_SUSPENDED; + flush_scheduled_work(); + + if (sharpsl_pm.charge_mode == CHRG_ON) + sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; + else + sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; + + return 0; +} + +static int sharpsl_pm_resume(struct platform_device *pdev) +{ + /* Clear the reset source indicators as they break the bootloader upon reboot */ + RCSR = 0x0f; + sharpsl_average_clear(); + sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED; + sharpsl_pm.flags &= ~SHARPSL_SUSPENDED; + + return 0; +} + +static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) +{ + dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR); + + dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG); + /* not charging and AC-IN! */ + + if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) { + dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n"); + sharpsl_pm.charge_mode = CHRG_OFF; + sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; + sharpsl_off_charge_battery(); + } + + sharpsl_pm.machinfo->presuspend(); + + PEDR = 0xffffffff; /* clear it */ + + sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE; + if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) { + RTSR &= RTSR_ALE; + RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND; + dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR); + sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE; + } else if (alarm_enable) { + RTSR &= RTSR_ALE; + RTAR = alarm_time; + dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR); + } else { + dev_dbg(sharpsl_pm.dev, "No alarms set.\n"); + } + + pxa_pm_enter(state); + + sharpsl_pm.machinfo->postsuspend(); + + dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR); +} + +static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) +{ + if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) ) + { + if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) { + dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n"); + corgi_goto_sleep(alarm_time, alarm_enable, state); + return 1; + } + if(sharpsl_off_charge_battery()) { + dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n"); + corgi_goto_sleep(alarm_time, alarm_enable, state); + return 1; + } + dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n"); + } + + if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) ) + { + dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n"); + corgi_goto_sleep(alarm_time, alarm_enable, state); + return 1; + } + + return 0; +} + +static int corgi_pxa_pm_enter(suspend_state_t state) +{ + unsigned long alarm_time = RTAR; + unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0); + + dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n"); + + corgi_goto_sleep(alarm_time, alarm_status, state); + + while (corgi_enter_suspend(alarm_time,alarm_status,state)) + {} + + dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n"); + + return 0; +} +#endif + + +/* + * Check for fatal battery errors + * Fatal returns -1 + */ +static int sharpsl_fatal_check(void) +{ + int buff[5], temp, i, acin; + + dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n"); + + /* Check AC-Adapter */ + acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); + + if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { + sharpsl_pm.machinfo->charge(0); + udelay(100); + sharpsl_pm.machinfo->discharge(1); /* enable discharge */ + mdelay(SHARPSL_WAIT_DISCHARGE_ON); + } + + if (sharpsl_pm.machinfo->discharge1) + sharpsl_pm.machinfo->discharge1(1); + + /* Check battery : check inserting battery ? */ + for (i=0; i<5; i++) { + buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); + mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); + } + + if (sharpsl_pm.machinfo->discharge1) + sharpsl_pm.machinfo->discharge1(0); + + if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { + udelay(100); + sharpsl_pm.machinfo->charge(1); + sharpsl_pm.machinfo->discharge(0); + } + + temp = get_select_val(buff); + dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT)); + + if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) || + (!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT))) + return -1; + return 0; +} + +static int sharpsl_off_charge_error(void) +{ + dev_err(sharpsl_pm.dev, "Offline Charger: Error occured.\n"); + sharpsl_pm.machinfo->charge(0); + sharpsl_pm_led(SHARPSL_LED_ERROR); + sharpsl_pm.charge_mode = CHRG_ERROR; + return 1; +} + +/* + * Charging Control while suspended + * Return 1 - go straight to sleep + * Return 0 - sleep or wakeup depending on other factors + */ +static int sharpsl_off_charge_battery(void) +{ + int time; + + dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode); + + if (sharpsl_pm.charge_mode == CHRG_OFF) { + dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n"); + + /* AC Check */ + if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0)) + return sharpsl_off_charge_error(); + + /* Start Charging */ + sharpsl_pm_led(SHARPSL_LED_ON); + sharpsl_pm.machinfo->charge(0); + mdelay(SHARPSL_CHARGE_WAIT_TIME); + sharpsl_pm.machinfo->charge(1); + + sharpsl_pm.charge_mode = CHRG_ON; + sharpsl_pm.full_count = 0; + + return 1; + } else if (sharpsl_pm.charge_mode != CHRG_ON) { + return 1; + } + + if (sharpsl_pm.full_count == 0) { + int time; + + dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n"); + + if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0)) + return sharpsl_off_charge_error(); + + sharpsl_pm.machinfo->charge(0); + mdelay(SHARPSL_CHARGE_WAIT_TIME); + sharpsl_pm.machinfo->charge(1); + sharpsl_pm.charge_mode = CHRG_ON; + + mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); + + time = RCNR; + while(1) { + /* Check if any wakeup event had occured */ + if (sharpsl_pm.machinfo->charger_wakeup() != 0) + return 0; + /* Check for timeout */ + if ((RCNR - time) > SHARPSL_WAIT_CO_TIME) + return 1; + if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) { + dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n"); + sharpsl_pm.full_count++; + sharpsl_pm.machinfo->charge(0); + mdelay(SHARPSL_CHARGE_WAIT_TIME); + sharpsl_pm.machinfo->charge(1); + return 1; + } + } + } + + dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n"); + + mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); + + time = RCNR; + while(1) { + /* Check if any wakeup event had occured */ + if (sharpsl_pm.machinfo->charger_wakeup() != 0) + return 0; + /* Check for timeout */ + if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) { + if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) { + dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n"); + sharpsl_pm.full_count = 0; + } + sharpsl_pm.full_count++; + return 1; + } + if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) { + dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n"); + sharpsl_pm_led(SHARPSL_LED_OFF); + sharpsl_pm.machinfo->charge(0); + sharpsl_pm.charge_mode = CHRG_DONE; + return 1; + } + } +} + + +static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent); +} + +static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage); +} + +static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL); +static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL); + +extern void (*apm_get_power_status)(struct apm_power_info *); + +static void sharpsl_apm_get_power_status(struct apm_power_info *info) +{ + info->ac_line_status = sharpsl_pm.battstat.ac_status; + + if (sharpsl_pm.charge_mode == CHRG_ON) + info->battery_status = APM_BATTERY_STATUS_CHARGING; + else + info->battery_status = sharpsl_pm.battstat.mainbat_status; + + info->battery_flag = (1 << info->battery_status); + info->battery_life = sharpsl_pm.battstat.mainbat_percent; +} + +static struct pm_ops sharpsl_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, + .prepare = pxa_pm_prepare, + .enter = corgi_pxa_pm_enter, + .finish = pxa_pm_finish, +}; + +static int __init sharpsl_pm_probe(struct platform_device *pdev) +{ + if (!pdev->dev.platform_data) + return -EINVAL; + + sharpsl_pm.dev = &pdev->dev; + sharpsl_pm.machinfo = pdev->dev.platform_data; + sharpsl_pm.charge_mode = CHRG_OFF; + sharpsl_pm.flags = 0; + + init_timer(&sharpsl_pm.ac_timer); + sharpsl_pm.ac_timer.function = sharpsl_ac_timer; + + init_timer(&sharpsl_pm.chrg_full_timer); + sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; + + sharpsl_pm.machinfo->init(); + + device_create_file(&pdev->dev, &dev_attr_battery_percentage); + device_create_file(&pdev->dev, &dev_attr_battery_voltage); + + apm_get_power_status = sharpsl_apm_get_power_status; + + pm_set_ops(&sharpsl_pm_ops); + + mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); + + return 0; +} + +static int sharpsl_pm_remove(struct platform_device *pdev) +{ + pm_set_ops(NULL); + + device_remove_file(&pdev->dev, &dev_attr_battery_percentage); + device_remove_file(&pdev->dev, &dev_attr_battery_voltage); + + sharpsl_pm.machinfo->exit(); + + del_timer_sync(&sharpsl_pm.chrg_full_timer); + del_timer_sync(&sharpsl_pm.ac_timer); + + return 0; +} + +static struct platform_driver sharpsl_pm_driver = { + .probe = sharpsl_pm_probe, + .remove = sharpsl_pm_remove, + .suspend = sharpsl_pm_suspend, + .resume = sharpsl_pm_resume, + .driver = { + .name = "sharpsl-pm", + }, +}; + +static int __devinit sharpsl_pm_init(void) +{ + return platform_driver_register(&sharpsl_pm_driver); +} + +static void sharpsl_pm_exit(void) +{ + platform_driver_unregister(&sharpsl_pm_driver); +} + +late_initcall(sharpsl_pm_init); +module_exit(sharpsl_pm_exit); diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 2a58499c0968..c1d77f5b3823 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -112,12 +112,14 @@ config IWMMXT config PXA_SHARP_C7xx bool select PXA_SSP + select SHARPSL_PM help Enable support for all Sharp C7xx models config PXA_SHARP_Cxx00 bool select PXA_SSP + select SHARPSL_PM help Enable common support for Sharp Cxx00 models diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c index 599be14754f9..de8b2403c929 100644 --- a/arch/arm/mach-pxa/corgi_pm.c +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -33,19 +34,7 @@ static void corgi_charger_init(void) pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT); pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT); pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN); -} - -static void corgi_charge_led(int val) -{ - if (val == SHARPSL_LED_ERROR) { - dev_dbg(sharpsl_pm.dev, "Charge LED Error\n"); - } else if (val == SHARPSL_LED_ON) { - dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); - GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); - } else { - dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); - GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); - } + sharpsl_pm_pxa_init(); } static void corgi_measure_temp(int on) @@ -138,15 +127,15 @@ static int corgi_should_wakeup(unsigned int resume_on_alarm) dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR); if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) { - if (STATUS_AC_IN()) { + if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { /* charge on */ dev_dbg(sharpsl_pm.dev, "ac insert\n"); sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; } else { /* charge off */ dev_dbg(sharpsl_pm.dev, "ac remove\n"); - CHARGE_LED_OFF(); - CHARGE_OFF(); + sharpsl_pm_led(SHARPSL_LED_OFF); + sharpsl_pm.machinfo->charge(0); sharpsl_pm.charge_mode = CHRG_OFF; } } @@ -172,23 +161,39 @@ static unsigned long corgi_charger_wakeup(void) return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) ); } -static int corgi_acin_status(void) +unsigned long corgipm_read_devdata(int type) { - return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0); + switch(type) { + case SHARPSL_STATUS_ACIN: + return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0); + case SHARPSL_STATUS_LOCK: + return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock); + case SHARPSL_STATUS_CHRGFULL: + return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull); + case SHARPSL_STATUS_FATAL: + return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal); + case SHARPSL_ACIN_VOLT: + return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT); + case SHARPSL_BATT_TEMP: + return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_TEMP); + case SHARPSL_BATT_VOLT: + default: + return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_VOLT); + } } static struct sharpsl_charger_machinfo corgi_pm_machinfo = { .init = corgi_charger_init, + .exit = sharpsl_pm_pxa_remove, .gpio_batlock = CORGI_GPIO_BAT_COVER, .gpio_acin = CORGI_GPIO_AC_IN, .gpio_batfull = CORGI_GPIO_CHRG_FULL, - .status_acin = corgi_acin_status, .discharge = corgi_discharge, .charge = corgi_charge, - .chargeled = corgi_charge_led, .measure_temp = corgi_measure_temp, .presuspend = corgi_presuspend, .postsuspend = corgi_postsuspend, + .read_devdata = corgipm_read_devdata, .charger_wakeup = corgi_charger_wakeup, .should_wakeup = corgi_should_wakeup, .bat_levels = 40, diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h index b0c40a1d6671..92b793050509 100644 --- a/arch/arm/mach-pxa/sharpsl.h +++ b/arch/arm/mach-pxa/sharpsl.h @@ -1,7 +1,16 @@ /* - * SharpSL SSP Driver + * Copyright (c) 2004-2005 Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * */ + +/* + * SharpSL SSP Driver + */ struct corgissp_machinfo { int port; int cs_lcdcon; @@ -14,18 +23,18 @@ struct corgissp_machinfo { void corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo); + /* * SharpSL Backlight */ - void corgi_bl_set_intensity(int intensity); void spitz_bl_set_intensity(int intensity); void akita_bl_set_intensity(int intensity); + /* * SharpSL Touchscreen Driver */ - unsigned long corgi_get_hsync_len(void); unsigned long spitz_get_hsync_len(void); void corgi_put_hsync(void); @@ -33,89 +42,22 @@ void spitz_put_hsync(void); void corgi_wait_hsync(void); void spitz_wait_hsync(void); + /* * SharpSL Battery/PM Driver */ -struct sharpsl_charger_machinfo { - void (*init)(void); - int gpio_acin; - int gpio_batfull; - int gpio_batlock; - int gpio_fatal; - int (*status_acin)(void); - void (*discharge)(int); - void (*discharge1)(int); - void (*charge)(int); - void (*chargeled)(int); - void (*measure_temp)(int); - void (*presuspend)(void); - void (*postsuspend)(void); - unsigned long (*charger_wakeup)(void); - int (*should_wakeup)(unsigned int resume_on_alarm); - int bat_levels; - struct battery_thresh *bat_levels_noac; - struct battery_thresh *bat_levels_acin; - int status_high_acin; - int status_low_acin; - int status_high_noac; - int status_low_noac; -}; - -struct battery_thresh { - int voltage; - int percentage; -}; - -struct battery_stat { - int ac_status; /* APM AC Present/Not Present */ - int mainbat_status; /* APM Main Battery Status */ - int mainbat_percent; /* Main Battery Percentage Charge */ - int mainbat_voltage; /* Main Battery Voltage */ -}; - -struct sharpsl_pm_status { - struct device *dev; - struct timer_list ac_timer; - struct timer_list chrg_full_timer; - - int charge_mode; -#define CHRG_ERROR (-1) -#define CHRG_OFF (0) -#define CHRG_ON (1) -#define CHRG_DONE (2) - - unsigned int flags; -#define SHARPSL_SUSPENDED (1 << 0) /* Device is Suspended */ -#define SHARPSL_ALARM_ACTIVE (1 << 1) /* Alarm is for charging event (not user) */ -#define SHARPSL_BL_LIMIT (1 << 2) /* Backlight Intensity Limited */ -#define SHARPSL_APM_QUEUED (1 << 3) /* APM Event Queued */ -#define SHARPSL_DO_OFFLINE_CHRG (1 << 4) /* Trigger the offline charger */ +#define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x)) - int full_count; - unsigned long charge_start_time; - struct sharpsl_charger_machinfo *machinfo; - struct battery_stat battstat; -}; +/* MAX1111 Channel Definitions */ +#define MAX1111_BATT_VOLT 4u +#define MAX1111_BATT_TEMP 2u +#define MAX1111_ACIN_VOLT 6u -extern struct sharpsl_pm_status sharpsl_pm; extern struct battery_thresh spitz_battery_levels_acin[]; extern struct battery_thresh spitz_battery_levels_noac[]; +void sharpsl_pm_pxa_init(void); +void sharpsl_pm_pxa_remove(void); +int sharpsl_pm_pxa_read_max1111(int channel); -#define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x)) - -#define SHARPSL_LED_ERROR 2 -#define SHARPSL_LED_ON 1 -#define SHARPSL_LED_OFF 0 -#define CHARGE_ON() sharpsl_pm.machinfo->charge(1) -#define CHARGE_OFF() sharpsl_pm.machinfo->charge(0) -#define CHARGE_LED_ON() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ON) -#define CHARGE_LED_OFF() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_OFF) -#define CHARGE_LED_ERR() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ERROR) -#define DISCHARGE_ON() sharpsl_pm.machinfo->discharge(1) -#define DISCHARGE_OFF() sharpsl_pm.machinfo->discharge(0) -#define STATUS_AC_IN() sharpsl_pm.machinfo->status_acin() -#define STATUS_BATT_LOCKED() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock) -#define STATUS_CHRG_FULL() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull) -#define STATUS_FATAL() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal) diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index c10be00fb526..f6fefb181411 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -15,48 +15,21 @@ #undef DEBUG #include -#include #include #include -#include -#include #include #include #include -#include #include #include #include - #include #include #include +#include #include "sharpsl.h" -/* - * Constants - */ -#define SHARPSL_CHARGE_ON_TIME_INTERVAL (msecs_to_jiffies(1*60*1000)) /* 1 min */ -#define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */ -#define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */ -#define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */ -#define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */ -#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */ -#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */ -#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */ -#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */ -#define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */ -#define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */ -#define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */ - -#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ -#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ -#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */ -#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */ -#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ -#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ - struct battery_thresh spitz_battery_levels_acin[] = { { 213, 100}, { 212, 98}, @@ -151,763 +124,17 @@ struct battery_thresh spitz_battery_levels_noac[] = { #define MAXCTRL_SEL_SH 4 #define MAXCTRL_STR 1u << 7 -/* MAX1111 Channel Definitions */ -#define BATT_AD 4u -#define BATT_THM 2u -#define JK_VAD 6u - - -/* - * Prototypes - */ -static int sharpsl_read_main_battery(void); -static int sharpsl_off_charge_battery(void); -static int sharpsl_check_battery_temp(void); -static int sharpsl_check_battery_voltage(void); -static int sharpsl_ac_check(void); -static int sharpsl_fatal_check(void); -static int sharpsl_average_value(int ad); -static void sharpsl_average_clear(void); -static void sharpsl_charge_toggle(void *private_); -static void sharpsl_battery_thread(void *private_); - - -/* - * Variables - */ -struct sharpsl_pm_status sharpsl_pm; -DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); -DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); - - -static int get_percentage(int voltage) -{ - int i = sharpsl_pm.machinfo->bat_levels - 1; - struct battery_thresh *thresh; - - if (sharpsl_pm.charge_mode == CHRG_ON) - thresh=sharpsl_pm.machinfo->bat_levels_acin; - else - thresh=sharpsl_pm.machinfo->bat_levels_noac; - - while (i > 0 && (voltage > thresh[i].voltage)) - i--; - - return thresh[i].percentage; -} - -static int get_apm_status(int voltage) -{ - int low_thresh, high_thresh; - - if (sharpsl_pm.charge_mode == CHRG_ON) { - high_thresh = sharpsl_pm.machinfo->status_high_acin; - low_thresh = sharpsl_pm.machinfo->status_low_acin; - } else { - high_thresh = sharpsl_pm.machinfo->status_high_noac; - low_thresh = sharpsl_pm.machinfo->status_low_noac; - } - - if (voltage >= high_thresh) - return APM_BATTERY_STATUS_HIGH; - if (voltage >= low_thresh) - return APM_BATTERY_STATUS_LOW; - return APM_BATTERY_STATUS_CRITICAL; -} - -void sharpsl_battery_kick(void) -{ - schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125)); -} -EXPORT_SYMBOL(sharpsl_battery_kick); - - -static void sharpsl_battery_thread(void *private_) -{ - int voltage, percent, apm_status, i = 0; - - if (!sharpsl_pm.machinfo) - return; - - sharpsl_pm.battstat.ac_status = (STATUS_AC_IN() ? APM_AC_ONLINE : APM_AC_OFFLINE); - - /* Corgi cannot confirm when battery fully charged so periodically kick! */ - if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON) - && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) - schedule_work(&toggle_charger); - - while(1) { - voltage = sharpsl_read_main_battery(); - if (voltage > 0) break; - if (i++ > 5) { - voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage; - dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n"); - break; - } - } - - voltage = sharpsl_average_value(voltage); - apm_status = get_apm_status(voltage); - percent = get_percentage(voltage); - - /* At low battery voltages, the voltage has a tendency to start - creeping back up so we try to avoid this here */ - if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) || percent <= sharpsl_pm.battstat.mainbat_percent) { - sharpsl_pm.battstat.mainbat_voltage = voltage; - sharpsl_pm.battstat.mainbat_status = apm_status; - sharpsl_pm.battstat.mainbat_percent = percent; - } - - dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %d\n", voltage, - sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies); - - /* If battery is low. limit backlight intensity to save power. */ - if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) - && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) || - (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) { - if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) { - corgibl_limit_intensity(1); - sharpsl_pm.flags |= SHARPSL_BL_LIMIT; - } - } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) { - corgibl_limit_intensity(0); - sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT; - } - - /* Suspend if critical battery level */ - if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) - && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL) - && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) { - sharpsl_pm.flags |= SHARPSL_APM_QUEUED; - dev_err(sharpsl_pm.dev, "Fatal Off\n"); - apm_queue_event(APM_CRITICAL_SUSPEND); - } - - schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME); -} - -static void sharpsl_charge_on(void) -{ - dev_dbg(sharpsl_pm.dev, "Turning Charger On\n"); - - sharpsl_pm.full_count = 0; - sharpsl_pm.charge_mode = CHRG_ON; - schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250)); - schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500)); -} - -static void sharpsl_charge_off(void) -{ - dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n"); - - CHARGE_OFF(); - CHARGE_LED_OFF(); - sharpsl_pm.charge_mode = CHRG_OFF; - - schedule_work(&sharpsl_bat); -} - -static void sharpsl_charge_error(void) -{ - CHARGE_LED_ERR(); - CHARGE_OFF(); - sharpsl_pm.charge_mode = CHRG_ERROR; -} - -static void sharpsl_charge_toggle(void *private_) -{ - dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); - - if (STATUS_AC_IN() == 0) { - sharpsl_charge_off(); - return; - } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) { - sharpsl_charge_error(); - return; - } - - CHARGE_LED_ON(); - CHARGE_OFF(); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - CHARGE_ON(); - - sharpsl_pm.charge_start_time = jiffies; -} - -static void sharpsl_ac_timer(unsigned long data) -{ - int acin = STATUS_AC_IN(); - - dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin); - - sharpsl_average_clear(); - if (acin && (sharpsl_pm.charge_mode != CHRG_ON)) - sharpsl_charge_on(); - else if (sharpsl_pm.charge_mode == CHRG_ON) - sharpsl_charge_off(); - - schedule_work(&sharpsl_bat); -} - - -static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp) -{ - /* Delay the event slightly to debounce */ - /* Must be a smaller delay than the chrg_full_isr below */ - mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); - - return IRQ_HANDLED; -} - -static void sharpsl_chrg_full_timer(unsigned long data) -{ - dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies); - - sharpsl_pm.full_count++; - - if (STATUS_AC_IN() == 0) { - dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n"); - if (sharpsl_pm.charge_mode == CHRG_ON) - sharpsl_charge_off(); - } else if (sharpsl_pm.full_count < 2) { - dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); - schedule_work(&toggle_charger); - } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { - dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); - schedule_work(&toggle_charger); - } else { - sharpsl_charge_off(); - sharpsl_pm.charge_mode = CHRG_DONE; - dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n"); - } -} - -/* Charging Finished Interrupt (Not present on Corgi) */ -/* Can trigger at the same time as an AC staus change so - delay until after that has been processed */ -static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp) -{ - if (sharpsl_pm.flags & SHARPSL_SUSPENDED) - return IRQ_HANDLED; - - /* delay until after any ac interrupt */ - mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500)); - - return IRQ_HANDLED; -} - -static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp) -{ - int is_fatal = 0; - - if (STATUS_BATT_LOCKED() == 0) { - dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n"); - is_fatal = 1; - } - - if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL() == 0)) { - dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n"); - is_fatal = 1; - } - - if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) { - sharpsl_pm.flags |= SHARPSL_APM_QUEUED; - apm_queue_event(APM_CRITICAL_SUSPEND); - } - - return IRQ_HANDLED; -} - -/* - * Maintain an average of the last 10 readings - */ -#define SHARPSL_CNV_VALUE_NUM 10 -static int sharpsl_ad_index; - -static void sharpsl_average_clear(void) -{ - sharpsl_ad_index = 0; -} - -static int sharpsl_average_value(int ad) -{ - int i, ad_val = 0; - static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1]; - - if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) { - sharpsl_ad_index = 0; - return ad; - } - - sharpsl_ad[sharpsl_ad_index] = ad; - sharpsl_ad_index++; - if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) { - for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++) - sharpsl_ad[i] = sharpsl_ad[i+1]; - sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1; - } - for (i=0; i < sharpsl_ad_index; i++) - ad_val += sharpsl_ad[i]; - - return (ad_val / sharpsl_ad_index); -} - - /* * Read MAX1111 ADC */ -static int read_max1111(int channel) +int sharpsl_pm_pxa_read_max1111(int channel) { return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1 | MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR); } -static int sharpsl_read_main_battery(void) -{ - return read_max1111(BATT_AD); -} - -static int sharpsl_read_temp(void) +void sharpsl_pm_pxa_init(void) { - int temp; - - sharpsl_pm.machinfo->measure_temp(1); - - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); - temp = read_max1111(BATT_THM); - - sharpsl_pm.machinfo->measure_temp(0); - - return temp; -} - -static int sharpsl_read_acin(void) -{ - return read_max1111(JK_VAD); -} - -/* - * Take an array of 5 integers, remove the maximum and minimum values - * and return the average. - */ -static int get_select_val(int *val) -{ - int i, j, k, temp, sum = 0; - - /* Find MAX val */ - temp = val[0]; - j=0; - for (i=1; i<5; i++) { - if (temp < val[i]) { - temp = val[i]; - j = i; - } - } - - /* Find MIN val */ - temp = val[4]; - k=4; - for (i=3; i>=0; i--) { - if (temp > val[i]) { - temp = val[i]; - k = i; - } - } - - for (i=0; i<5; i++) - if (i != j && i != k ) - sum += val[i]; - - dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]); - - return (sum/3); -} - -static int sharpsl_check_battery_temp(void) -{ - int val, i, buff[5]; - - /* Check battery temperature */ - for (i=0; i<5; i++) { - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); - buff[i] = sharpsl_read_temp(); - } - - val = get_select_val(buff); - - dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); - if (val > SHARPSL_CHARGE_ON_TEMP) - return -1; - - return 0; -} - -static int sharpsl_check_battery_voltage(void) -{ - int val, i, buff[5]; - - /* disable charge, enable discharge */ - CHARGE_OFF(); - DISCHARGE_ON(); - mdelay(SHARPSL_WAIT_DISCHARGE_ON); - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(1); - - /* Check battery voltage */ - for (i=0; i<5; i++) { - buff[i] = sharpsl_read_main_battery(); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(0); - - DISCHARGE_OFF(); - - val = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val); - - if (val < SHARPSL_CHARGE_ON_VOLT) - return -1; - - return 0; -} - -static int sharpsl_ac_check(void) -{ - int temp, i, buff[5]; - - for (i=0; i<5; i++) { - buff[i] = sharpsl_read_acin(); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN); - } - - temp = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp); - - if ((temp > SHARPSL_CHARGE_ON_ACIN_HIGH) || (temp < SHARPSL_CHARGE_ON_ACIN_LOW)) { - dev_err(sharpsl_pm.dev, "Error: AC check failed.\n"); - return -1; - } - - return 0; -} - -#ifdef CONFIG_PM -static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state) -{ - sharpsl_pm.flags |= SHARPSL_SUSPENDED; - flush_scheduled_work(); - - if (sharpsl_pm.charge_mode == CHRG_ON) - sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; - else - sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; - - return 0; -} - -static int sharpsl_pm_resume(struct platform_device *pdev) -{ - /* Clear the reset source indicators as they break the bootloader upon reboot */ - RCSR = 0x0f; - sharpsl_average_clear(); - sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED; - sharpsl_pm.flags &= ~SHARPSL_SUSPENDED; - - return 0; -} - -static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) -{ - dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR); - - dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG); - /* not charging and AC-IN! */ - - if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN() != 0)) { - dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n"); - sharpsl_pm.charge_mode = CHRG_OFF; - sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; - sharpsl_off_charge_battery(); - } - - sharpsl_pm.machinfo->presuspend(); - - PEDR = 0xffffffff; /* clear it */ - - sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE; - if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) { - RTSR &= RTSR_ALE; - RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND; - dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR); - sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE; - } else if (alarm_enable) { - RTSR &= RTSR_ALE; - RTAR = alarm_time; - dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR); - } else { - dev_dbg(sharpsl_pm.dev, "No alarms set.\n"); - } - - pxa_pm_enter(state); - - sharpsl_pm.machinfo->postsuspend(); - - dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR); -} - -static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) -{ - if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) ) - { - if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) { - dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n"); - corgi_goto_sleep(alarm_time, alarm_enable, state); - return 1; - } - if(sharpsl_off_charge_battery()) { - dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n"); - corgi_goto_sleep(alarm_time, alarm_enable, state); - return 1; - } - dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n"); - } - - if ((STATUS_BATT_LOCKED() == 0) || (sharpsl_fatal_check() < 0) ) - { - dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n"); - corgi_goto_sleep(alarm_time, alarm_enable, state); - return 1; - } - - return 0; -} - -static int corgi_pxa_pm_enter(suspend_state_t state) -{ - unsigned long alarm_time = RTAR; - unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0); - - dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n"); - - corgi_goto_sleep(alarm_time, alarm_status, state); - - while (corgi_enter_suspend(alarm_time,alarm_status,state)) - {} - - dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n"); - - return 0; -} -#endif - - -/* - * Check for fatal battery errors - * Fatal returns -1 - */ -static int sharpsl_fatal_check(void) -{ - int buff[5], temp, i, acin; - - dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n"); - - /* Check AC-Adapter */ - acin = STATUS_AC_IN(); - - if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { - CHARGE_OFF(); - udelay(100); - DISCHARGE_ON(); /* enable discharge */ - mdelay(SHARPSL_WAIT_DISCHARGE_ON); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(1); - - /* Check battery : check inserting battery ? */ - for (i=0; i<5; i++) { - buff[i] = sharpsl_read_main_battery(); - mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); - } - - if (sharpsl_pm.machinfo->discharge1) - sharpsl_pm.machinfo->discharge1(0); - - if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { - udelay(100); - CHARGE_ON(); - DISCHARGE_OFF(); - } - - temp = get_select_val(buff); - dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_main_battery()); - - if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) || - (!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT))) - return -1; - return 0; -} - -static int sharpsl_off_charge_error(void) -{ - dev_err(sharpsl_pm.dev, "Offline Charger: Error occured.\n"); - CHARGE_OFF(); - CHARGE_LED_ERR(); - sharpsl_pm.charge_mode = CHRG_ERROR; - return 1; -} - -/* - * Charging Control while suspended - * Return 1 - go straight to sleep - * Return 0 - sleep or wakeup depending on other factors - */ -static int sharpsl_off_charge_battery(void) -{ - int time; - - dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode); - - if (sharpsl_pm.charge_mode == CHRG_OFF) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n"); - - /* AC Check */ - if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0)) - return sharpsl_off_charge_error(); - - /* Start Charging */ - CHARGE_LED_ON(); - CHARGE_OFF(); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - CHARGE_ON(); - - sharpsl_pm.charge_mode = CHRG_ON; - sharpsl_pm.full_count = 0; - - return 1; - } else if (sharpsl_pm.charge_mode != CHRG_ON) { - return 1; - } - - if (sharpsl_pm.full_count == 0) { - int time; - - dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n"); - - if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0)) - return sharpsl_off_charge_error(); - - CHARGE_OFF(); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - CHARGE_ON(); - sharpsl_pm.charge_mode = CHRG_ON; - - mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); - - time = RCNR; - while(1) { - /* Check if any wakeup event had occured */ - if (sharpsl_pm.machinfo->charger_wakeup() != 0) - return 0; - /* Check for timeout */ - if ((RCNR - time) > SHARPSL_WAIT_CO_TIME) - return 1; - if (STATUS_CHRG_FULL()) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n"); - sharpsl_pm.full_count++; - CHARGE_OFF(); - mdelay(SHARPSL_CHARGE_WAIT_TIME); - CHARGE_ON(); - return 1; - } - } - } - - dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n"); - - mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); - - time = RCNR; - while(1) { - /* Check if any wakeup event had occured */ - if (sharpsl_pm.machinfo->charger_wakeup() != 0) - return 0; - /* Check for timeout */ - if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) { - if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n"); - sharpsl_pm.full_count = 0; - } - sharpsl_pm.full_count++; - return 1; - } - if (STATUS_CHRG_FULL()) { - dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n"); - CHARGE_LED_OFF(); - CHARGE_OFF(); - sharpsl_pm.charge_mode = CHRG_DONE; - return 1; - } - } -} - - -static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent); -} - -static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage); -} - -static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL); -static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL); - -extern void (*apm_get_power_status)(struct apm_power_info *); - -static void sharpsl_apm_get_power_status(struct apm_power_info *info) -{ - info->ac_line_status = sharpsl_pm.battstat.ac_status; - - if (sharpsl_pm.charge_mode == CHRG_ON) - info->battery_status = APM_BATTERY_STATUS_CHARGING; - else - info->battery_status = sharpsl_pm.battstat.mainbat_status; - - info->battery_flag = (1 << info->battery_status); - info->battery_life = sharpsl_pm.battstat.mainbat_percent; -} - -static struct pm_ops sharpsl_pm_ops = { - .pm_disk_mode = PM_DISK_FIRMWARE, - .prepare = pxa_pm_prepare, - .enter = corgi_pxa_pm_enter, - .finish = pxa_pm_finish, -}; - -static int __init sharpsl_pm_probe(struct platform_device *pdev) -{ - if (!pdev->dev.platform_data) - return -EINVAL; - - sharpsl_pm.dev = &pdev->dev; - sharpsl_pm.machinfo = pdev->dev.platform_data; - sharpsl_pm.charge_mode = CHRG_OFF; - sharpsl_pm.flags = 0; - - sharpsl_pm.machinfo->init(); - - init_timer(&sharpsl_pm.ac_timer); - sharpsl_pm.ac_timer.function = sharpsl_ac_timer; - - init_timer(&sharpsl_pm.chrg_full_timer); - sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; - pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN); pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN); pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN); @@ -938,26 +165,10 @@ static int __init sharpsl_pm_probe(struct platform_device *pdev) } else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING); } - - device_create_file(&pdev->dev, &dev_attr_battery_percentage); - device_create_file(&pdev->dev, &dev_attr_battery_voltage); - - apm_get_power_status = sharpsl_apm_get_power_status; - - pm_set_ops(&sharpsl_pm_ops); - - mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); - - return 0; } -static int sharpsl_pm_remove(struct platform_device *pdev) +void sharpsl_pm_pxa_remove(void) { - pm_set_ops(NULL); - - device_remove_file(&pdev->dev, &dev_attr_battery_percentage); - device_remove_file(&pdev->dev, &dev_attr_battery_voltage); - free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr); free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr); @@ -966,32 +177,4 @@ static int sharpsl_pm_remove(struct platform_device *pdev) if (!machine_is_corgi()) free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr); - - del_timer_sync(&sharpsl_pm.chrg_full_timer); - del_timer_sync(&sharpsl_pm.ac_timer); - - return 0; } - -static struct platform_driver sharpsl_pm_driver = { - .probe = sharpsl_pm_probe, - .remove = sharpsl_pm_remove, - .suspend = sharpsl_pm_suspend, - .resume = sharpsl_pm_resume, - .driver = { - .name = "sharpsl-pm", - }, -}; - -static int __devinit sharpsl_pm_init(void) -{ - return platform_driver_register(&sharpsl_pm_driver); -} - -static void sharpsl_pm_exit(void) -{ - platform_driver_unregister(&sharpsl_pm_driver); -} - -late_initcall(sharpsl_pm_init); -module_exit(sharpsl_pm_exit); diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c index 3ce7486daa51..76a5c26dea0b 100644 --- a/arch/arm/mach-pxa/spitz_pm.c +++ b/arch/arm/mach-pxa/spitz_pm.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -33,19 +34,7 @@ static void spitz_charger_init(void) { pxa_gpio_mode(SPITZ_GPIO_KEY_INT | GPIO_IN); pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN); -} - -static void spitz_charge_led(int val) -{ - if (val == SHARPSL_LED_ERROR) { - dev_dbg(sharpsl_pm.dev, "Charge LED Error\n"); - } else if (val == SHARPSL_LED_ON) { - dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); - set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); - } else { - dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); - reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); - } + sharpsl_pm_pxa_init(); } static void spitz_measure_temp(int on) @@ -92,7 +81,7 @@ static void spitz_discharge1(int on) static void spitz_presuspend(void) { - spitz_last_ac_status = STATUS_AC_IN(); + spitz_last_ac_status = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); /* GPIO Sleep Register */ PGSR0 = 0x00144018; @@ -138,7 +127,7 @@ static void spitz_postsuspend(void) static int spitz_should_wakeup(unsigned int resume_on_alarm) { int is_resume = 0; - int acin = STATUS_AC_IN(); + int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); if (spitz_last_ac_status != acin) { if (acin) { @@ -148,8 +137,8 @@ static int spitz_should_wakeup(unsigned int resume_on_alarm) } else { /* charge off */ dev_dbg(sharpsl_pm.dev, "AC Removed\n"); - CHARGE_LED_OFF(); - CHARGE_OFF(); + sharpsl_pm_led(SHARPSL_LED_OFF); + sharpsl_pm.machinfo->charge(0); sharpsl_pm.charge_mode = CHRG_OFF; } spitz_last_ac_status = acin; @@ -175,25 +164,41 @@ static unsigned long spitz_charger_wakeup(void) return (~GPLR0 & GPIO_bit(SPITZ_GPIO_KEY_INT)) | (GPLR0 & GPIO_bit(SPITZ_GPIO_SYNC)); } -static int spitz_acin_status(void) +unsigned long spitzpm_read_devdata(int type) { - return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0); + switch(type) { + case SHARPSL_STATUS_ACIN: + return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0); + case SHARPSL_STATUS_LOCK: + return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock); + case SHARPSL_STATUS_CHRGFULL: + return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull); + case SHARPSL_STATUS_FATAL: + return READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal); + case SHARPSL_ACIN_VOLT: + return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT); + case SHARPSL_BATT_TEMP: + return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_TEMP); + case SHARPSL_BATT_VOLT: + default: + return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_VOLT); + } } struct sharpsl_charger_machinfo spitz_pm_machinfo = { .init = spitz_charger_init, + .exit = sharpsl_pm_pxa_remove, .gpio_batlock = SPITZ_GPIO_BAT_COVER, .gpio_acin = SPITZ_GPIO_AC_IN, .gpio_batfull = SPITZ_GPIO_CHRG_FULL, .gpio_fatal = SPITZ_GPIO_FATAL_BAT, - .status_acin = spitz_acin_status, .discharge = spitz_discharge, .discharge1 = spitz_discharge1, .charge = spitz_charge, - .chargeled = spitz_charge_led, .measure_temp = spitz_measure_temp, .presuspend = spitz_presuspend, .postsuspend = spitz_postsuspend, + .read_devdata = spitzpm_read_devdata, .charger_wakeup = spitz_charger_wakeup, .should_wakeup = spitz_should_wakeup, .bat_levels = 40, diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 6a219b2c77e3..d0aaf450e8c7 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -20,6 +20,7 @@ #include #include +#include #define CORGI_DEFAULT_INTENSITY 0x1f #define CORGI_LIMIT_MASK 0x0b diff --git a/include/asm-arm/hardware/sharpsl_pm.h b/include/asm-arm/hardware/sharpsl_pm.h new file mode 100644 index 000000000000..36983e5f3665 --- /dev/null +++ b/include/asm-arm/hardware/sharpsl_pm.h @@ -0,0 +1,94 @@ +/* + * SharpSL Battery/PM Driver + * + * Copyright (c) 2004-2005 Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include + +struct sharpsl_charger_machinfo { + void (*init)(void); + void (*exit)(void); + int gpio_acin; + int gpio_batfull; + int gpio_batlock; + int gpio_fatal; + void (*discharge)(int); + void (*discharge1)(int); + void (*charge)(int); + void (*measure_temp)(int); + void (*presuspend)(void); + void (*postsuspend)(void); + unsigned long (*read_devdata)(int); +#define SHARPSL_BATT_VOLT 1 +#define SHARPSL_BATT_TEMP 2 +#define SHARPSL_ACIN_VOLT 3 +#define SHARPSL_STATUS_ACIN 4 +#define SHARPSL_STATUS_LOCK 5 +#define SHARPSL_STATUS_CHRGFULL 6 +#define SHARPSL_STATUS_FATAL 7 + unsigned long (*charger_wakeup)(void); + int (*should_wakeup)(unsigned int resume_on_alarm); + int bat_levels; + struct battery_thresh *bat_levels_noac; + struct battery_thresh *bat_levels_acin; + int status_high_acin; + int status_low_acin; + int status_high_noac; + int status_low_noac; +}; + +struct battery_thresh { + int voltage; + int percentage; +}; + +struct battery_stat { + int ac_status; /* APM AC Present/Not Present */ + int mainbat_status; /* APM Main Battery Status */ + int mainbat_percent; /* Main Battery Percentage Charge */ + int mainbat_voltage; /* Main Battery Voltage */ +}; + +struct sharpsl_pm_status { + struct device *dev; + struct timer_list ac_timer; + struct timer_list chrg_full_timer; + + int charge_mode; +#define CHRG_ERROR (-1) +#define CHRG_OFF (0) +#define CHRG_ON (1) +#define CHRG_DONE (2) + + unsigned int flags; +#define SHARPSL_SUSPENDED (1 << 0) /* Device is Suspended */ +#define SHARPSL_ALARM_ACTIVE (1 << 1) /* Alarm is for charging event (not user) */ +#define SHARPSL_BL_LIMIT (1 << 2) /* Backlight Intensity Limited */ +#define SHARPSL_APM_QUEUED (1 << 3) /* APM Event Queued */ +#define SHARPSL_DO_OFFLINE_CHRG (1 << 4) /* Trigger the offline charger */ + + int full_count; + unsigned long charge_start_time; + struct sharpsl_charger_machinfo *machinfo; + struct battery_stat battstat; +}; + +extern struct sharpsl_pm_status sharpsl_pm; + + +#define SHARPSL_LED_ERROR 2 +#define SHARPSL_LED_ON 1 +#define SHARPSL_LED_OFF 0 + +void sharpsl_battery_kick(void); +void sharpsl_pm_led(int val); +irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp); +irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp); +irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp); + -- cgit v1.2.3 From 53b7c2b243bd31f857dddabd9339f2dd6ae3fb67 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 5 Jan 2006 20:44:55 +0000 Subject: [ARM] 3229/1: Remove uneeded ARM apm dependency on PM_LEGACY Patch from Richard Purdie ARM doesn't use ACPI so ARM's apm implementation has no need to depend on PM_LEGACY. This patch removes that dependency. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/Kconfig | 1 - arch/arm/kernel/apm.c | 19 +++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cb413109da0c..16a5d522b2f2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -660,7 +660,6 @@ source "kernel/power/Kconfig" config APM tristate "Advanced Power Management Emulation" - depends on PM_LEGACY ---help--- APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c index a2843be05557..b9df1b782bb1 100644 --- a/arch/arm/kernel/apm.c +++ b/arch/arm/kernel/apm.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -81,6 +80,7 @@ struct apm_user { */ static int suspends_pending; static int apm_disabled; +static int arm_apm_active; static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); @@ -477,9 +477,9 @@ static int kapmd(void *arg) apm_event_t event; wait_event_interruptible(kapmd_wait, - !queue_empty(&kapmd_queue) || !pm_active); + !queue_empty(&kapmd_queue) || !arm_apm_active); - if (!pm_active) + if (!arm_apm_active) break; spin_lock_irq(&kapmd_queue_lock); @@ -522,16 +522,11 @@ static int __init apm_init(void) return -ENODEV; } - if (PM_IS_ACTIVE()) { - printk(KERN_NOTICE "apm: overridden by ACPI.\n"); - return -EINVAL; - } - - pm_active = 1; + arm_apm_active = 1; ret = kernel_thread(kapmd, NULL, CLONE_KERNEL); if (ret < 0) { - pm_active = 0; + arm_apm_active = 0; return ret; } @@ -543,7 +538,7 @@ static int __init apm_init(void) if (ret != 0) { remove_proc_entry("apm", NULL); - pm_active = 0; + arm_apm_active = 0; wake_up(&kapmd_wait); wait_for_completion(&kapmd_exit); } @@ -556,7 +551,7 @@ static void __exit apm_exit(void) misc_deregister(&apm_device); remove_proc_entry("apm", NULL); - pm_active = 0; + arm_apm_active = 0; wake_up(&kapmd_wait); wait_for_completion(&kapmd_exit); } -- cgit v1.2.3 From 945b957972844881002ab4f68534581f4427a30b Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 5 Jan 2006 20:44:57 +0000 Subject: [ARM] 3230/1: Sharp Scoop: Fix Shared Power Control Issues Patch from Richard Purdie The SL-Cxx00 devices have a power control register in SCOOP that is shared by both CF and MMC/SD card slots. The CF reset code was resetting this register leading to various lockups as the MMC power was suddenly lost. This patch handles the CPR register in a more sensitive manner. It also removes some unneeded collie specific calls as the reset code handles this. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/common/scoop.c | 2 +- arch/arm/mach-pxa/spitz.c | 4 +++- drivers/pcmcia/pxa2xx_sharpsl.c | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 0c3cbd9a388b..b6de43e73699 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -33,7 +33,6 @@ void reset_scoop(struct device *dev) SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100; // 00 SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000; // 04 - SCOOP_REG(sdev->base,SCOOP_CPR) = 0x0000; // 0C SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000; // 10 SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000; // 18 SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF; // 14 @@ -154,6 +153,7 @@ int __init scoop_probe(struct platform_device *pdev) SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140; reset_scoop(&pdev->dev); + SCOOP_REG(devptr->base, SCOOP_CPR) = 0x0000; SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff; SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff; diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 5d34abc64af7..f2007db0cda5 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -127,10 +127,12 @@ static void spitz_card_pwr_ctrl(int device, unsigned short new_cpr) cpr &= ~0x0002; if (device == SPITZ_PWR_SD) cpr &= ~0x0004; - write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr); if (!(cpr & 0x0002) && !(cpr & 0x0004)) { + write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, 0x0000); mdelay(1); reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); + } else { + write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr); } } } diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 56c58831e80e..4fbd995360b0 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -36,9 +36,18 @@ struct scoop_pcmcia_config *platform_scoop_config; #define SCOOP_DEV platform_scoop_config->devs -static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev) +static void sharpsl_pcmcia_init_reset(struct soc_pcmcia_socket *skt) { + struct scoop_pcmcia_dev *scoopdev = &SCOOP_DEV[skt->nr]; + reset_scoop(scoopdev->dev); + + /* Shared power controls need to be handled carefully */ + if (platform_scoop_config->power_ctrl) + platform_scoop_config->power_ctrl(scoopdev->dev, 0x0000, skt->nr); + else + write_scoop_reg(scoopdev->dev, SCOOP_CPR, 0x0000); + scoopdev->keep_vs = NO_KEEP_VS; scoopdev->keep_rd = 0; } @@ -208,26 +217,17 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) { - sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]); + sharpsl_pcmcia_init_reset(skt); /* Enable interrupt */ write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0); write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101); SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS; - - if (machine_is_collie()) - /* We need to disable SS_OUTPUT_ENA here. */ - write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { - /* CF_BUS_OFF */ - sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]); - - if (machine_is_collie()) - /* We need to disable SS_OUTPUT_ENA here. */ - write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080); + sharpsl_pcmcia_init_reset(skt); } static struct pcmcia_low_level sharpsl_pcmcia_ops = { -- cgit v1.2.3 From 6a2273d6fc627d28a4de9beadf77ae6636b1e5d0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Jan 2006 20:44:58 +0000 Subject: [ARM] 3231/1: mx1ads board support cleanup Patch from Sascha Hauer - remove unnecessary mappings - rename mx1ads_device to cs89x0_device, because that's what it is - fix io/irq resource for cs89x0 device Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- arch/arm/mach-imx/mx1ads.c | 55 +++++++++------------------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index 708e1b3faa14..c9e0cd8ed016 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -29,27 +29,27 @@ #include "generic.h" #include -static struct resource mx1ads_resources[] = { +static struct resource cs89x0_resources[] = { [0] = { - .start = IMX_CS4_VIRT, - .end = IMX_CS4_VIRT + 16, + .start = IMX_CS4_PHYS + 0x300, + .end = IMX_CS4_PHYS + 0x300 + 16, .flags = IORESOURCE_MEM, }, [1] = { - .start = 13, - .end = 13, + .start = IRQ_GPIOC(17), + .end = IRQ_GPIOC(17), .flags = IORESOURCE_IRQ, }, }; -static struct platform_device mx1ads_device = { - .name = "mx1ads", - .num_resources = ARRAY_SIZE(mx1ads_resources), - .resource = mx1ads_resources, +static struct platform_device cs89x0_device = { + .name = "cirrus-cs89x0", + .num_resources = ARRAY_SIZE(cs89x0_resources), + .resource = cs89x0_resources, }; static struct platform_device *devices[] __initdata = { - &mx1ads_device, + &cs89x0_device, }; static void __init @@ -61,45 +61,10 @@ mx1ads_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); } -static struct map_desc mx1ads_io_desc[] __initdata = { - { - .virtual = IMX_CS0_VIRT, - .pfn = __phys_to_pfn(IMX_CS0_PHYS), - .length = IMX_CS0_SIZE, - .type = MT_DEVICE - }, { - .virtual = IMX_CS1_VIRT, - .pfn = __phys_to_pfn(IMX_CS1_PHYS), - .length = IMX_CS1_SIZE, - .type = MT_DEVICE - }, { - .virtual = IMX_CS2_VIRT, - .pfn = __phys_to_pfn(IMX_CS2_PHYS), - .length = IMX_CS2_SIZE, - .type = MT_DEVICE - }, { - .virtual = IMX_CS3_VIRT, - .pfn = __phys_to_pfn(IMX_CS3_PHYS), - .length = IMX_CS3_SIZE, - .type = MT_DEVICE - }, { - .virtual = IMX_CS4_VIRT, - .pfn = __phys_to_pfn(IMX_CS4_PHYS), - .length = IMX_CS4_SIZE, - .type = MT_DEVICE - }, { - .virtual = IMX_CS5_VIRT, - .pfn = __phys_to_pfn(IMX_CS5_PHYS), - .length = IMX_CS5_SIZE, - .type = MT_DEVICE - } -}; - static void __init mx1ads_map_io(void) { imx_map_io(); - iotable_init(mx1ads_io_desc, ARRAY_SIZE(mx1ads_io_desc)); } MACHINE_START(MX1ADS, "Motorola MX1ADS") -- cgit v1.2.3 From 2b9ac7c15c0c5c9d6057b9e297dabaebd208ffe8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 5 Jan 2006 20:53:02 +0000 Subject: [ARM] 3217/1: iop331 uarts as platform devices Patch from Dan Williams Convert old-style serial devices to platform devices so that printk's are visible during the boot process. Signed-off-by: Dan Williams Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-iop3xx/iop331-setup.c | 94 +++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c index 53f60614498b..e6ea1cba6a17 100644 --- a/arch/arm/mach-iop3xx/iop331-setup.c +++ b/arch/arm/mach-iop3xx/iop331-setup.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -50,32 +50,74 @@ static struct map_desc iop331_std_desc[] __initdata = { } }; -static struct uart_port iop331_serial_ports[] = { - { - .membase = (char*)(IOP331_UART0_VIRT), - .mapbase = (IOP331_UART0_PHYS), - .irq = IRQ_IOP331_UART0, - .flags = UPF_SKIP_TEST, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = IOP331_UART_XTAL, - .line = 0, - .type = PORT_XSCALE, - .fifosize = 32 - } , { - .membase = (char*)(IOP331_UART1_VIRT), - .mapbase = (IOP331_UART1_PHYS), - .irq = IRQ_IOP331_UART1, - .flags = UPF_SKIP_TEST, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = IOP331_UART_XTAL, - .line = 1, - .type = PORT_XSCALE, - .fifosize = 32 +static struct resource iop33x_uart0_resources[] = { + [0] = { + .start = IOP331_UART0_PHYS, + .end = IOP331_UART0_PHYS + 0x3f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IOP331_UART0, + .end = IRQ_IOP331_UART0, + .flags = IORESOURCE_IRQ + } +}; + +static struct resource iop33x_uart1_resources[] = { + [0] = { + .start = IOP331_UART1_PHYS, + .end = IOP331_UART1_PHYS + 0x3f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IOP331_UART1, + .end = IRQ_IOP331_UART1, + .flags = IORESOURCE_IRQ } }; +static struct plat_serial8250_port iop33x_uart0_data[] = { + { + .membase = (char*)(IOP331_UART0_VIRT), + .mapbase = (IOP331_UART0_PHYS), + .irq = IRQ_IOP331_UART0, + .uartclk = IOP331_UART_XTAL, + .regshift = 2, + .iotype = UPIO_MEM, + .flags = UPF_SKIP_TEST, + }, + { }, +}; + +static struct plat_serial8250_port iop33x_uart1_data[] = { + { + .membase = (char*)(IOP331_UART1_VIRT), + .mapbase = (IOP331_UART1_PHYS), + .irq = IRQ_IOP331_UART1, + .uartclk = IOP331_UART_XTAL, + .regshift = 2, + .iotype = UPIO_MEM, + .flags = UPF_SKIP_TEST, + }, + { }, +}; + +static struct platform_device iop33x_uart0 = { + .name = "serial8250", + .id = 0, + .dev.platform_data = iop33x_uart0_data, + .num_resources = 2, + .resource = iop33x_uart0_resources, +}; + +static struct platform_device iop33x_uart1 = { + .name = "serial8250", + .id = 1, + .dev.platform_data = iop33x_uart1_data, + .num_resources = 2, + .resource = iop33x_uart1_resources, +}; + static struct resource iop33x_i2c_0_resources[] = { [0] = { .start = 0xfffff680, @@ -117,6 +159,8 @@ static struct platform_device iop33x_i2c_1_controller = { }; static struct platform_device *iop33x_devices[] __initdata = { + &iop33x_uart0, + &iop33x_uart1, &iop33x_i2c_0_controller, &iop33x_i2c_1_controller }; @@ -133,8 +177,6 @@ void __init iop33x_init(void) void __init iop331_map_io(void) { iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc)); - early_serial_setup(&iop331_serial_ports[0]); - early_serial_setup(&iop331_serial_ports[1]); } #ifdef CONFIG_ARCH_IOP331 -- cgit v1.2.3 From 54e269ead6e672325866037b0617a72edd1396b9 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Thu, 5 Jan 2006 20:59:29 +0000 Subject: [ARM] 3226/1: IXP4xx runtime expansion bus window size configuration Patch from Deepak Saxena The expansion bus on the IXP46x NPU can be configured for either 32MiB or 16MiB windows and changing the configuration causes the base address for each chip select for each region to change. Because of this, we cannot hardcode the physical base as we currently do. This patch checks the expansion bus configuration registers at runtime to determine the appropriate window size. Note that this requires that the bootloader already configured the device sizes appropriately, but I feel that is valid assumption to make as the bootloader must configure and access the flash window, the output display (LCD, LEDs, etc) window, and other expansion bus devices. Signed-off-by: Deepak Saxena Signed-off-by: Russell King --- arch/arm/mach-ixp4xx/common.c | 16 ++++++++++++++++ arch/arm/mach-ixp4xx/coyote-setup.c | 10 ++++++---- arch/arm/mach-ixp4xx/gtwx5715-setup.c | 15 +++++++++++---- arch/arm/mach-ixp4xx/ixdp425-setup.c | 13 ++++--------- arch/arm/mach-ixp4xx/nas100d-setup.c | 6 ++++-- include/asm-arm/arch-ixp4xx/coyote.h | 5 +---- include/asm-arm/arch-ixp4xx/gtwx5715.h | 4 ---- include/asm-arm/arch-ixp4xx/ixdp425.h | 3 --- include/asm-arm/arch-ixp4xx/nas100d.h | 3 --- include/asm-arm/arch-ixp4xx/nslu2.h | 3 --- include/asm-arm/arch-ixp4xx/platform.h | 21 +++++++++++---------- 11 files changed, 53 insertions(+), 46 deletions(-) diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 9f33cb21e7f3..6b393691d0e8 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -332,11 +332,27 @@ static struct platform_device *ixp46x_devices[] __initdata = { &ixp46x_i2c_controller }; +unsigned long ixp4xx_exp_bus_size; + void __init ixp4xx_sys_init(void) { + ixp4xx_exp_bus_size = SZ_16M; + if (cpu_is_ixp46x()) { + int region; + platform_add_devices(ixp46x_devices, ARRAY_SIZE(ixp46x_devices)); + + for (region = 0; region < 7; region++) { + if((*(IXP4XX_EXP_REG(0x4 * region)) & 0x200)) { + ixp4xx_exp_bus_size = SZ_32M; + break; + } + } } + + printk("IXP4xx: Using %uMiB expansion bus window size\n", + ixp4xx_exp_bus_size >> 20); } diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c index 050c92768913..679594a73981 100644 --- a/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/arch/arm/mach-ixp4xx/coyote-setup.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -30,8 +31,6 @@ static struct flash_platform_data coyote_flash_data = { }; static struct resource coyote_flash_resource = { - .start = COYOTE_FLASH_BASE, - .end = COYOTE_FLASH_BASE + COYOTE_FLASH_SIZE - 1, .flags = IORESOURCE_MEM, }; @@ -81,6 +80,11 @@ static struct platform_device *coyote_devices[] __initdata = { static void __init coyote_init(void) { + ixp4xx_sys_init(); + + coyote_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + coyote_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1; + *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0; @@ -91,8 +95,6 @@ static void __init coyote_init(void) coyote_uart_data[0].irq = IRQ_IXP4XX_UART1; } - - ixp4xx_sys_init(); platform_add_devices(coyote_devices, ARRAY_SIZE(coyote_devices)); } diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c index 29a6d02fa851..038670489970 100644 --- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c +++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -106,11 +107,9 @@ static struct flash_platform_data gtwx5715_flash_data = { .width = 2, }; -static struct resource gtwx5715_flash_resource = { - .start = GTWX5715_FLASH_BASE, - .end = GTWX5715_FLASH_BASE + GTWX5715_FLASH_SIZE - 1, +static struct gtw5715_flash_resource = { .flags = IORESOURCE_MEM, -}; +} static struct platform_device gtwx5715_flash = { .name = "IXP4XX-Flash", @@ -129,6 +128,14 @@ static struct platform_device *gtwx5715_devices[] __initdata = { static void __init gtwx5715_init(void) { + ixp4xx_sys_init(); + + if (!flash_resource) + printk(KERN_ERR "Could not allocate flash resource\n"); + + gtwx5715_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + gtwx5715_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_8M - 1; + platform_add_devices(gtwx5715_devices, ARRAY_SIZE(gtwx5715_devices)); } diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 3a22d84e1047..c2e105c89c95 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -30,8 +31,6 @@ static struct flash_platform_data ixdp425_flash_data = { }; static struct resource ixdp425_flash_resource = { - .start = IXDP425_FLASH_BASE, - .end = IXDP425_FLASH_BASE + IXDP425_FLASH_SIZE - 1, .flags = IORESOURCE_MEM, }; @@ -108,17 +107,13 @@ static struct platform_device *ixdp425_devices[] __initdata = { &ixdp425_uart }; - static void __init ixdp425_init(void) { ixp4xx_sys_init(); - /* - * IXP465 has 32MB window - */ - if (machine_is_ixdp465()) { - ixdp425_flash_resource.end += IXDP425_FLASH_SIZE; - } + ixdp425_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + ixdp425_flash_resource.end = + IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); } diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index bde9648e7afc..49998a8bd4e8 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -26,8 +26,6 @@ static struct flash_platform_data nas100d_flash_data = { }; static struct resource nas100d_flash_resource = { - .start = NAS100D_FLASH_BASE, - .end = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE, .flags = IORESOURCE_MEM, }; @@ -115,6 +113,10 @@ static void __init nas100d_init(void) { ixp4xx_sys_init(); + nas100d_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + nas100d_flash_resource.end = + IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; + pm_power_off = nas100d_power_off; platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices)); diff --git a/include/asm-arm/arch-ixp4xx/coyote.h b/include/asm-arm/arch-ixp4xx/coyote.h index dd0c2d2d8503..7ac9ba2c035c 100644 --- a/include/asm-arm/arch-ixp4xx/coyote.h +++ b/include/asm-arm/arch-ixp4xx/coyote.h @@ -16,9 +16,6 @@ #error "Do not include this directly, instead #include " #endif -#define COYOTE_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS -#define COYOTE_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE * 2 - /* PCI controller GPIO to IRQ pin mappings */ #define COYOTE_PCI_SLOT0_PIN 6 #define COYOTE_PCI_SLOT1_PIN 11 @@ -26,7 +23,7 @@ #define COYOTE_PCI_SLOT0_DEVID 14 #define COYOTE_PCI_SLOT1_DEVID 15 -#define COYOTE_IDE_BASE_PHYS IXP4XX_EXP_BUS_CS3_BASE_PHYS +#define COYOTE_IDE_BASE_PHYS IXP4XX_EXP_BUS_BASE(3) #define COYOTE_IDE_BASE_VIRT 0xFFFE1000 #define COYOTE_IDE_REGION_SIZE 0x1000 diff --git a/include/asm-arm/arch-ixp4xx/gtwx5715.h b/include/asm-arm/arch-ixp4xx/gtwx5715.h index fc460af70627..c3069d67c00e 100644 --- a/include/asm-arm/arch-ixp4xx/gtwx5715.h +++ b/include/asm-arm/arch-ixp4xx/gtwx5715.h @@ -57,10 +57,6 @@ #define GTWX5715_GPIO13_IRQ IRQ_IXP4XX_SW_INT1 #define GTWX5715_GPIO14_IRQ IRQ_IXP4XX_SW_INT2 - -#define GTWX5715_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS -#define GTWX5715_FLASH_SIZE (0x00800000) - /* PCI controller GPIO to IRQ pin mappings INTA INTB diff --git a/include/asm-arm/arch-ixp4xx/ixdp425.h b/include/asm-arm/arch-ixp4xx/ixdp425.h index 7d21bf941379..3d3820d7ba09 100644 --- a/include/asm-arm/arch-ixp4xx/ixdp425.h +++ b/include/asm-arm/arch-ixp4xx/ixdp425.h @@ -16,9 +16,6 @@ #error "Do not include this directly, instead #include " #endif -#define IXDP425_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS -#define IXDP425_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE - #define IXDP425_SDA_PIN 7 #define IXDP425_SCL_PIN 6 diff --git a/include/asm-arm/arch-ixp4xx/nas100d.h b/include/asm-arm/arch-ixp4xx/nas100d.h index ce7a86a98fc2..51ac0180427c 100644 --- a/include/asm-arm/arch-ixp4xx/nas100d.h +++ b/include/asm-arm/arch-ixp4xx/nas100d.h @@ -19,9 +19,6 @@ #error "Do not include this directly, instead #include " #endif -#define NAS100D_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS -#define NAS100D_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE - #define NAS100D_SDA_PIN 6 #define NAS100D_SCL_PIN 5 diff --git a/include/asm-arm/arch-ixp4xx/nslu2.h b/include/asm-arm/arch-ixp4xx/nslu2.h index b8b347a559c7..4281838873ef 100644 --- a/include/asm-arm/arch-ixp4xx/nslu2.h +++ b/include/asm-arm/arch-ixp4xx/nslu2.h @@ -18,9 +18,6 @@ #error "Do not include this directly, instead #include " #endif -#define NSLU2_FLASH_BASE IXP4XX_EXP_BUS_CS0_BASE_PHYS -#define NSLU2_FLASH_SIZE IXP4XX_EXP_BUS_CSX_REGION_SIZE - #define NSLU2_SDA_PIN 7 #define NSLU2_SCL_PIN 6 diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h index 6b77ed26be79..daf9790645ca 100644 --- a/include/asm-arm/arch-ixp4xx/platform.h +++ b/include/asm-arm/arch-ixp4xx/platform.h @@ -26,16 +26,17 @@ */ #define IXP4XX_EXP_BUS_BASE_PHYS (0x50000000) -#define IXP4XX_EXP_BUS_CSX_REGION_SIZE (0x01000000) - -#define IXP4XX_EXP_BUS_CS0_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x00000000) -#define IXP4XX_EXP_BUS_CS1_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x01000000) -#define IXP4XX_EXP_BUS_CS2_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x02000000) -#define IXP4XX_EXP_BUS_CS3_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x03000000) -#define IXP4XX_EXP_BUS_CS4_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x04000000) -#define IXP4XX_EXP_BUS_CS5_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x05000000) -#define IXP4XX_EXP_BUS_CS6_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x06000000) -#define IXP4XX_EXP_BUS_CS7_BASE_PHYS (IXP4XX_EXP_BUS_BASE_PHYS + 0x07000000) +/* + * The expansion bus on the IXP4xx can be configured for either 16 or + * 32MB windows and the CS offset for each region changes based on the + * current configuration. This means that we cannot simply hardcode + * each offset. ixp4xx_sys_init() looks at the expansion bus configuration + * as setup by the bootloader to determine our window size. + */ +extern unsigned long ixp4xx_exp_bus_size; + +#define IXP4XX_EXP_BUS_BASE(region)\ + (IXP4XX_EXP_BUS_BASE_PHYS + ((region) * ixp4xx_exp_bus_size)) #define IXP4XX_FLASH_WRITABLE (0x2) #define IXP4XX_FLASH_DEFAULT (0xbcd23c40) -- cgit v1.2.3 From 5b2e98cdf3a6ac6c57de6a2156c673d4b0262684 Mon Sep 17 00:00:00 2001 From: Jared Hulbert Date: Thu, 5 Jan 2006 21:12:26 +0000 Subject: [ARM] 3206/1: Modifications to the bus arbiter controller for the Intel PXA27x Patch from Jared Hulbert The following patch changes the bus arbiter controller settings for the Intel PXA27x Application Processor Family. Up to 5% better video performance. It parks the bus on the core while not in use and sets the arbitration for other bus items. The patch only applies changes to the Intel Mainstone development platform. This patch is not compatible with preproduction Intel PXA27x silicon. This patch is based on the Intel Linux Preview Kit released to the public on 25 Feb. 2005 found at ftp://ftp.arm.linux.org.uk/pub/linux/arm/people/xscale/mainstone/02-25-2005/. Signed-off-by: Justin A Treon Signed-off-by: Jared Hulbert Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mach-pxa/mainstone.c | 6 ++++++ include/asm-arm/arch-pxa/pxa-regs.h | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 07892f4012d8..fe7404318aa8 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -407,6 +407,12 @@ static void __init mainstone_init(void) printk(KERN_NOTICE "Mainstone configured to boot from %s\n", mst_flash_data[0].name); + /* system bus arbiter setting + * - Core_Park + * - LCD_wt:DMA_wt:CORE_Wt = 2:3:4 + */ + ARB_CNTRL = ARB_CORE_PARK | 0x234; + /* * On Mainstone, we route AC97_SYSCLK via GPIO45 to * the audio daughter card diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index a75a2470f4f5..dae138b9cac5 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -2042,6 +2042,18 @@ #ifdef CONFIG_PXA27x +#define ARB_CNTRL __REG(0x48000048) /* Arbiter Control Register */ + +#define ARB_DMA_SLV_PARK (1<<31) /* Be parked with DMA slave when idle */ +#define ARB_CI_PARK (1<<30) /* Be parked with Camera Interface when idle */ +#define ARB_EX_MEM_PARK (1<<29) /* Be parked with external MEMC when idle */ +#define ARB_INT_MEM_PARK (1<<28) /* Be parked with internal MEMC when idle */ +#define ARB_USB_PARK (1<<27) /* Be parked with USB when idle */ +#define ARB_LCD_PARK (1<<26) /* Be parked with LCD when idle */ +#define ARB_DMA_PARK (1<<25) /* Be parked with DMA when idle */ +#define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */ +#define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */ + /* * Keypad */ -- cgit v1.2.3 From aa2f9367790ad81ef51d3f667124227ca3003d3b Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 5 Jan 2006 16:12:01 -0800 Subject: IB/mthca: check return value in mthca_dev_lim call Check error return on call to mthca_dev_lim for Tavor (as is done for memfree). Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 6f94b25f3acd..8b00d9a0f6f4 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -261,6 +261,10 @@ static int __devinit mthca_init_tavor(struct mthca_dev *mdev) } err = mthca_dev_lim(mdev, &dev_lim); + if (err) { + mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); + goto err_disable; + } profile = default_profile; profile.num_uar = dev_lim.uar_size / PAGE_SIZE; -- cgit v1.2.3 From 38d1e793471d95728219f500bbb8bd25658d73b0 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 5 Jan 2006 16:13:46 -0800 Subject: IB/mthca: check port validity in modify_qp Modify_qp should check that the physical port number provided is a legal value. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index d786ef443614..ea45fa400fab 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -621,6 +621,12 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) return -EINVAL; } + if ((attr_mask & IB_QP_PORT) && + (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) { + mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num); + return -EINVAL; + } + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n", -- cgit v1.2.3 From 466200562ccd80f728f7ef602d2b97b4fdedd566 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 5 Jan 2006 16:17:38 -0800 Subject: IB/mthca: create_eq with size not a power of 2 Fix mthca_create_eq for when the EQ size is not a power of 2. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_eq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 34d68e5a72d8..e8a948f087c0 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -484,8 +484,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, u8 intr, struct mthca_eq *eq) { - int npages = (nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) / - PAGE_SIZE; + int npages; u64 *dma_list = NULL; dma_addr_t t; struct mthca_mailbox *mailbox; @@ -496,6 +495,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, eq->dev = dev; eq->nent = roundup_pow_of_two(max(nent, 2)); + npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE; eq->page_list = kmalloc(npages * sizeof *eq->page_list, GFP_KERNEL); -- cgit v1.2.3 From dbc26344350dff2932902a7723a4e89e71752803 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 5 Jan 2006 23:00:13 -0500 Subject: Input: atkbd - don't lose keymap settings when reconnecting keyboard Call serio_reconnect() instead of serio_rescan() when detecting that a new keyboard was plugged in. This should help KVM uses losing custom keymap settings when switching between boxes. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index a0256f8de8ef..ffacf6eca5f5 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -321,7 +321,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, switch (code) { case ATKBD_RET_BAT: atkbd->enabled = 0; - serio_rescan(atkbd->ps2dev.serio); + serio_reconnect(atkbd->ps2dev.serio); goto out; case ATKBD_RET_EMUL0: atkbd->emul = 1; -- cgit v1.2.3 From 1f85145c5825a6f1fdf83e6c48e788dd3117c39a Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Thu, 5 Jan 2006 23:00:26 -0500 Subject: Input: add missing keys from input.h to hid-debug.h Signed-off-by: Michael Hanselmann Signed-off-by: Dmitry Torokhov --- drivers/usb/input/hid-debug.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index 4a42162ee2ea..702c48c2f81b 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h @@ -681,7 +681,21 @@ static char *keys[KEY_MAX + 1] = { [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", [KEY_DOCUMENTS] = "Documents", - [KEY_FN] = "Fn", + [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", + [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", + [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", + [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", + [KEY_FN_S] = "Fn+S", + [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", + [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", + [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", + [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", + [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", + [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", + [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", + [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", + [KEY_KBDILLUMUP] = "KbdIlluminationUp", + [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", }; static char *relatives[REL_MAX + 1] = { -- cgit v1.2.3 From 6020bafc9e30e04f4db65298d00e8e28ffb40652 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Thu, 5 Jan 2006 23:00:38 -0500 Subject: Input: i8042 - add OQO Zepto to noloop dmi table. Signed-off-by: Ben Collins Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 057beca1986a..2d2f9fb3aded 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -84,6 +84,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), }, }, + { + .ident = "OQO Model 01", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "OQO"), + DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "00"), + }, + }, { } }; -- cgit v1.2.3 From 5b3bc7a68171138d52b1b62012c37ac888895460 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 6 Jan 2006 12:57:30 -0800 Subject: IB/mthca: max_inline_data handling tweaks Fix a case where copying max_inline_data from a successful create_qp capabilities output to create_qp input could cause EINVAL error: mthca_set_qp_size must check max_inline_data directly against max_desc_sz; checking qp->sq.max_gs is wrong since max_inline_data depends on the qp type and does not involve max_sg. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 62 ++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index ea45fa400fab..fd60cf3a5ba3 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -890,18 +890,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) return err; } -static void mthca_adjust_qp_caps(struct mthca_dev *dev, - struct mthca_pd *pd, - struct mthca_qp *qp) +static int mthca_max_data_size(struct mthca_dev *dev, struct mthca_qp *qp, int desc_sz) { - int max_data_size; - /* * Calculate the maximum size of WQE s/g segments, excluding * the next segment and other non-data segments. */ - max_data_size = min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift) - - sizeof (struct mthca_next_seg); + int max_data_size = desc_sz - sizeof (struct mthca_next_seg); switch (qp->transport) { case MLX: @@ -920,11 +915,24 @@ static void mthca_adjust_qp_caps(struct mthca_dev *dev, break; } + return max_data_size; +} + +static inline int mthca_max_inline_data(struct mthca_pd *pd, int max_data_size) +{ /* We don't support inline data for kernel QPs (yet). */ - if (!pd->ibpd.uobject) - qp->max_inline_data = 0; - else - qp->max_inline_data = max_data_size - MTHCA_INLINE_HEADER_SIZE; + return pd->ibpd.uobject ? max_data_size - MTHCA_INLINE_HEADER_SIZE : 0; +} + +static void mthca_adjust_qp_caps(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_qp *qp) +{ + int max_data_size = mthca_max_data_size(dev, qp, + min(dev->limits.max_desc_sz, + 1 << qp->sq.wqe_shift)); + + qp->max_inline_data = mthca_max_inline_data(pd, max_data_size); qp->sq.max_gs = min_t(int, dev->limits.max_sg, max_data_size / sizeof (struct mthca_data_seg)); @@ -1191,13 +1199,23 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, } static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, - struct mthca_qp *qp) + struct mthca_pd *pd, struct mthca_qp *qp) { + int max_data_size = mthca_max_data_size(dev, qp, dev->limits.max_desc_sz); + /* Sanity check QP size before proceeding */ - if (cap->max_send_wr > dev->limits.max_wqes || - cap->max_recv_wr > dev->limits.max_wqes || - cap->max_send_sge > dev->limits.max_sg || - cap->max_recv_sge > dev->limits.max_sg) + if (cap->max_send_wr > dev->limits.max_wqes || + cap->max_recv_wr > dev->limits.max_wqes || + cap->max_send_sge > dev->limits.max_sg || + cap->max_recv_sge > dev->limits.max_sg || + cap->max_inline_data > mthca_max_inline_data(pd, max_data_size)) + return -EINVAL; + + /* + * For MLX transport we need 2 extra S/G entries: + * one for the header and one for the checksum at the end + */ + if (qp->transport == MLX && cap->max_recv_sge + 2 > dev->limits.max_sg) return -EINVAL; if (mthca_is_memfree(dev)) { @@ -1216,14 +1234,6 @@ static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, MTHCA_INLINE_CHUNK_SIZE) / sizeof (struct mthca_data_seg)); - /* - * For MLX transport we need 2 extra S/G entries: - * one for the header and one for the checksum at the end - */ - if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) || - qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg) - return -EINVAL; - return 0; } @@ -1238,7 +1248,7 @@ int mthca_alloc_qp(struct mthca_dev *dev, { int err; - err = mthca_set_qp_size(dev, cap, qp); + err = mthca_set_qp_size(dev, cap, pd, qp); if (err) return err; @@ -1281,7 +1291,7 @@ int mthca_alloc_sqp(struct mthca_dev *dev, u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1; int err; - err = mthca_set_qp_size(dev, cap, &sqp->qp); + err = mthca_set_qp_size(dev, cap, pd, &sqp->qp); if (err) return err; -- cgit v1.2.3 From 0364ffc3e8c441d4185e3eb41ecc61dbb09614e4 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 6 Jan 2006 13:01:27 -0800 Subject: IB/mthca: fix for SQEr-to-RTS transition in modify QP Fixes to SQEr->RTS transition in modify_qp: 1. The flag IB_QP_ACCESS_FLAGS is optional for UC qps 2. The SQEr state is not supported for RC qps Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index fd60cf3a5ba3..623f5144eae2 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -476,9 +476,8 @@ static const struct { .opt_param = { [UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), - [UC] = IB_QP_CUR_STATE, - [RC] = (IB_QP_CUR_STATE | - IB_QP_MIN_RNR_TIMER), + [UC] = (IB_QP_CUR_STATE | + IB_QP_ACCESS_FLAGS), [MLX] = (IB_QP_CUR_STATE | IB_QP_QKEY), } -- cgit v1.2.3 From 0d3b525fff40475e58dab9176740d2efc5f37838 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 6 Jan 2006 13:03:43 -0800 Subject: IB/mthca: fix for RTR-to-RTS transition in modify QP PKEY_INDEX is not a legal parameter in the RTR->RTS transition. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 623f5144eae2..ff2def3e9dd1 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -383,12 +383,10 @@ static const struct { [UC] = (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | - IB_QP_PKEY_INDEX | IB_QP_PATH_MIG_STATE), [RC] = (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | - IB_QP_PKEY_INDEX | IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE), [MLX] = (IB_QP_CUR_STATE | -- cgit v1.2.3 From 5ceb74557c71465cf8f6fda050aac00e53f9ad3d Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 6 Jan 2006 13:11:07 -0800 Subject: IB/mthca: multiple fixes for multicast group handling Multicast group management fixes: . Fix leak of mailbox memory in error handling on multicast group operations. . Free AMGM indices at detach and in attach error handling. . Fix amount to shift for aligning next_gid_index in mailbox: it starts at bit 6, not bit 5. . Allocate AMGM index after end of MGM table, in the range num_mgms to multicast table size - 1. Add some BUG_ON checks to catch cases where the index falls in the MGM hash area. . Initialize the list of QPs in a newly-allocated group from AMGM to 0 This is necessary since when a group is moved from AMGM to MGM (in the case where the MGM entry has been emptied of QPs), the AMGM entry is not reset to 0 (and we don't want an extra command to do that). Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_mcg.c | 54 +++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index 2fc449da418d..77bc6c746f43 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -111,7 +111,8 @@ static int find_mgm(struct mthca_dev *dev, goto out; if (status) { mthca_err(dev, "READ_MGM returned status %02x\n", status); - return -EINVAL; + err = -EINVAL; + goto out; } if (!memcmp(mgm->gid, zero_gid, 16)) { @@ -126,7 +127,7 @@ static int find_mgm(struct mthca_dev *dev, goto out; *prev = *index; - *index = be32_to_cpu(mgm->next_gid_index) >> 5; + *index = be32_to_cpu(mgm->next_gid_index) >> 6; } while (*index); *index = -1; @@ -153,8 +154,10 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return PTR_ERR(mailbox); mgm = mailbox->buf; - if (down_interruptible(&dev->mcg_table.sem)) - return -EINTR; + if (down_interruptible(&dev->mcg_table.sem)) { + err = -EINTR; + goto err_sem; + } err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); if (err) @@ -181,9 +184,8 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = -EINVAL; goto out; } - + memset(mgm, 0, sizeof *mgm); memcpy(mgm->gid, gid->raw, 16); - mgm->next_gid_index = 0; } for (i = 0; i < MTHCA_QP_PER_MGM; ++i) @@ -209,6 +211,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (status) { mthca_err(dev, "WRITE_MGM returned status %02x\n", status); err = -EINVAL; + goto out; } if (!link) @@ -223,7 +226,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) goto out; } - mgm->next_gid_index = cpu_to_be32(index << 5); + mgm->next_gid_index = cpu_to_be32(index << 6); err = mthca_WRITE_MGM(dev, prev, mailbox, &status); if (err) @@ -234,7 +237,12 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } out: + if (err && link && index != -1) { + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); + } up(&dev->mcg_table.sem); + err_sem: mthca_free_mailbox(dev, mailbox); return err; } @@ -255,8 +263,10 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return PTR_ERR(mailbox); mgm = mailbox->buf; - if (down_interruptible(&dev->mcg_table.sem)) - return -EINTR; + if (down_interruptible(&dev->mcg_table.sem)) { + err = -EINTR; + goto err_sem; + } err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); if (err) @@ -305,13 +315,11 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (i != 1) goto out; - goto out; - if (prev == -1) { /* Remove entry from MGM */ - if (be32_to_cpu(mgm->next_gid_index) >> 5) { - err = mthca_READ_MGM(dev, - be32_to_cpu(mgm->next_gid_index) >> 5, + int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6; + if (amgm_index_to_free) { + err = mthca_READ_MGM(dev, amgm_index_to_free, mailbox, &status); if (err) goto out; @@ -332,9 +340,13 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = -EINVAL; goto out; } + if (amgm_index_to_free) { + BUG_ON(amgm_index_to_free < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); + } } else { /* Remove entry from AMGM */ - index = be32_to_cpu(mgm->next_gid_index) >> 5; + int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; err = mthca_READ_MGM(dev, prev, mailbox, &status); if (err) goto out; @@ -344,7 +356,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) goto out; } - mgm->next_gid_index = cpu_to_be32(index << 5); + mgm->next_gid_index = cpu_to_be32(curr_next_index << 6); err = mthca_WRITE_MGM(dev, prev, mailbox, &status); if (err) @@ -354,10 +366,13 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = -EINVAL; goto out; } + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); } out: up(&dev->mcg_table.sem); + err_sem: mthca_free_mailbox(dev, mailbox); return err; } @@ -365,11 +380,12 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) int __devinit mthca_init_mcg_table(struct mthca_dev *dev) { int err; + int table_size = dev->limits.num_mgms + dev->limits.num_amgms; err = mthca_alloc_init(&dev->mcg_table.alloc, - dev->limits.num_amgms, - dev->limits.num_amgms - 1, - 0); + table_size, + table_size - 1, + dev->limits.num_mgms); if (err) return err; -- cgit v1.2.3 From 0f8e8f9607d77ffc1f9820446dfcf781e96fdfd4 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 6 Jan 2006 13:13:32 -0800 Subject: IB/mthca: Fill in vendor_err field in completion with error Fill vendor_err field in completion with error. Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_cq.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index fcef8dc2c121..96f1a86bf049 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -128,12 +128,12 @@ struct mthca_err_cqe { __be32 my_qpn; u32 reserved1[3]; u8 syndrome; - u8 reserved2; + u8 vendor_err; __be16 db_cnt; - u32 reserved3; + u32 reserved2; __be32 wqe; u8 opcode; - u8 reserved4[2]; + u8 reserved3[2]; u8 owner; }; @@ -342,8 +342,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, } /* - * For completions in error, only work request ID, status (and - * freed resource count for RD) have to be set. + * For completions in error, only work request ID, status, vendor error + * (and freed resource count for RD) have to be set. */ switch (cqe->syndrome) { case SYNDROME_LOCAL_LENGTH_ERR: @@ -405,6 +405,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, break; } + entry->vendor_err = cqe->vendor_err; + /* * Mem-free HCAs always generate one CQE per WQE, even in the * error case, so we don't have to check the doorbell count, etc. -- cgit v1.2.3 From 036d25f79ddfbc9878da24ef8e468a6d22caa605 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 6 Jan 2006 16:19:26 -0500 Subject: [ACPI] linux-acpi@vger.kernel.org replaces acpi-devel@lists.sourceforge.net Signed-off-by: Len Brown --- Documentation/pm.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/pm.txt b/Documentation/pm.txt index 2ea1149bf6b0..79c0f32a760e 100644 --- a/Documentation/pm.txt +++ b/Documentation/pm.txt @@ -218,7 +218,7 @@ proceed in the opposite direction. Q: Who do I contact for additional information about enabling power management for my specific driver/device? -ACPI Development mailing list: acpi-devel@lists.sourceforge.net +ACPI Development mailing list: linux-acpi@vger.kernel.org System Interface -- OBSOLETE, DO NOT USE! ----------------************************* -- cgit v1.2.3 From 4de144bf721e46e7ccc8fed45b20a640cc364904 Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Fri, 6 Jan 2006 13:23:58 -0800 Subject: IB/mthca: Add support for automatic path migration (APM) Add code to modify QP operation to handle setting alternate paths for connected QPs. Signed-off-by: Dotan Barak Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_qp.c | 57 ++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index ff2def3e9dd1..564b6d51c394 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -549,6 +549,25 @@ static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr, return cpu_to_be32(hw_access_flags); } +static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path) +{ + path->g_mylmc = ah->src_path_bits & 0x7f; + path->rlid = cpu_to_be16(ah->dlid); + path->static_rate = !!ah->static_rate; + + if (ah->ah_flags & IB_AH_GRH) { + path->g_mylmc |= 1 << 7; + path->mgid_index = ah->grh.sgid_index; + path->hop_limit = ah->grh.hop_limit; + path->sl_tclass_flowlabel = + cpu_to_be32((ah->sl << 28) | + (ah->grh.traffic_class << 20) | + (ah->grh.flow_label)); + memcpy(path->rgid, ah->grh.dgid.raw, 16); + } else + path->sl_tclass_flowlabel = cpu_to_be32(ah->sl << 28); +} + int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) { struct mthca_dev *dev = to_mdev(ibqp->device); @@ -712,28 +731,14 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_RNR_RETRY) { - qp_context->pri_path.rnr_retry = attr->rnr_retry << 5; - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY); + qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry = + attr->rnr_retry << 5; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | + MTHCA_QP_OPTPAR_ALT_RNR_RETRY); } if (attr_mask & IB_QP_AV) { - qp_context->pri_path.g_mylmc = attr->ah_attr.src_path_bits & 0x7f; - qp_context->pri_path.rlid = cpu_to_be16(attr->ah_attr.dlid); - qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate; - if (attr->ah_attr.ah_flags & IB_AH_GRH) { - qp_context->pri_path.g_mylmc |= 1 << 7; - qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index; - qp_context->pri_path.hop_limit = attr->ah_attr.grh.hop_limit; - qp_context->pri_path.sl_tclass_flowlabel = - cpu_to_be32((attr->ah_attr.sl << 28) | - (attr->ah_attr.grh.traffic_class << 20) | - (attr->ah_attr.grh.flow_label)); - memcpy(qp_context->pri_path.rgid, - attr->ah_attr.grh.dgid.raw, 16); - } else { - qp_context->pri_path.sl_tclass_flowlabel = - cpu_to_be32(attr->ah_attr.sl << 28); - } + mthca_path_set(&attr->ah_attr, &qp_context->pri_path); qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); } @@ -742,7 +747,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT); } - /* XXX alt_path */ + if (attr_mask & IB_QP_ALT_PATH) { + if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) { + mthca_dbg(dev, "Alternate port number (%u) is invalid\n", + attr->alt_port_num); + return -EINVAL; + } + + mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path); + qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | + attr->alt_port_num << 24); + qp_context->alt_path.ackto = attr->alt_timeout << 3; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH); + } /* leave rdd as 0 */ qp_context->pd = cpu_to_be32(to_mpd(ibqp->pd)->pd_num); -- cgit v1.2.3 From d51bfb7852d0e524074ad1cf04e4c3026d75d652 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 6 Jan 2006 22:35:59 +0100 Subject: kbuild: introduce escsq to escapre single quotes This makes things a little bit more reader friendly and gvim is less confused. Signed-off-by: Sam Ravnborg --- scripts/Kbuild.include | 13 +++++++++---- scripts/Makefile.build | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index db3c708e546b..0168d6c37075 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -3,6 +3,7 @@ # Convinient variables comma := , +squote := ' empty := space := $(empty) $(empty) @@ -11,6 +12,10 @@ space := $(empty) $(empty) # contain a comma depfile = $(subst $(comma),_,$(@D)/.$(@F).d) +### +# Escape single quote for use in echo statements +escsq = $(subst $(squote),'\$(squote)',$1) + ### # filechk is used to check if the content of a generated file is updated. # Sample usage: @@ -47,7 +52,7 @@ build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj # If quiet is set, only print short version of command cmd = @$(if $($(quiet)cmd_$(1)),\ - echo ' $(subst ','\'',$($(quiet)cmd_$(1)))' &&) $(cmd_$(1)) + echo ' $(call escsq,$($(quiet)cmd_$(1)))' &&) $(cmd_$(1)) # Add $(obj)/ for paths that is not absolute objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) @@ -68,7 +73,7 @@ endif # echo command. Short version is $(quiet) equals quiet, otherwise full command echo-cmd = $(if $($(quiet)cmd_$(1)), \ - echo ' $(subst ','\'',$($(quiet)cmd_$(1)))';) + echo ' $(call escsq,$($(quiet)cmd_$(1)))';) # function to only execute the passed command if necessary # >'< substitution is for echo to work, >$< substitution to preserve $ when reloading .cmd file @@ -78,7 +83,7 @@ if_changed = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ), \ @set -e; \ $(echo-cmd) \ $(cmd_$(1)); \ - echo 'cmd_$@ := $(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).cmd) + echo 'cmd_$@ := $(subst $$,$$$$,$(call escsq,$(cmd_$(1))))' > $(@D)/.$(@F).cmd) # execute the command and also postprocess generated .d dependencies # file @@ -87,7 +92,7 @@ if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\ @set -e; \ $(echo-cmd) \ $(cmd_$(1)); \ - scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(subst ','\'',$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \ + scripts/basic/fixdep $(depfile) $@ '$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))' > $(@D)/.$(@F).tmp; \ rm -f $(depfile); \ mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 506e3f3befe3..c33e62bde6b0 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -179,10 +179,10 @@ endif define rule_cc_o_c $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ $(cmd_checksrc) \ - $(if $($(quiet)cmd_cc_o_c),echo ' $(subst ','\'',$($(quiet)cmd_cc_o_c))';) \ + $(if $($(quiet)cmd_cc_o_c),echo ' $(call escsq,$($(quiet)cmd_cc_o_c))';) \ $(cmd_cc_o_c); \ $(cmd_modversions) \ - scripts/basic/fixdep $(depfile) $@ '$(subst ','\'',$(cmd_cc_o_c))' > $(@D)/.$(@F).tmp; \ + scripts/basic/fixdep $(depfile) $@ '$(call escsq,$(cmd_cc_o_c))' > $(@D)/.$(@F).tmp; \ rm -f $(depfile); \ mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd endef -- cgit v1.2.3 From b4ca1a3f8ca24033d7b7ef595faef97d9f8b2326 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 6 Jan 2006 16:21:19 -0800 Subject: IB/uverbs: Fix reference counting on error paths If an operation fails after incrementing an object's reference count, then it should decrement the reference count on the error path. Signed-off-by: Jack Morgenstein Signed-off-by: Michael S. Tsirkin Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_cmd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a57d021d435a..6985a57fa6ae 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -489,6 +489,7 @@ err_idr: err_unreg: ib_dereg_mr(mr); + atomic_dec(&pd->usecnt); err_up: up(&ib_uverbs_idr_mutex); @@ -935,6 +936,11 @@ err_idr: err_destroy: ib_destroy_qp(qp); + atomic_dec(&pd->usecnt); + atomic_dec(&attr.send_cq->usecnt); + atomic_dec(&attr.recv_cq->usecnt); + if (attr.srq) + atomic_dec(&attr.srq->usecnt); err_up: up(&ib_uverbs_idr_mutex); @@ -1729,6 +1735,7 @@ err_idr: err_destroy: ib_destroy_srq(srq); + atomic_dec(&pd->usecnt); err_up: up(&ib_uverbs_idr_mutex); -- cgit v1.2.3 From ea5d4a6ad2bfd1006790666981645cab43d3afbd Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 6 Jan 2006 16:24:45 -0800 Subject: IB/uverbs: set ah_flags when creating address handle AH attribute's ah_flags need to be set according to the is_global flag passed in from userspace. Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_cmd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 6985a57fa6ae..12d6cc0a7f80 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -1454,6 +1454,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, attr.sl = cmd.attr.sl; attr.src_path_bits = cmd.attr.src_path_bits; attr.static_rate = cmd.attr.static_rate; + attr.ah_flags = cmd.attr.is_global ? IB_AH_GRH : 0; attr.port_num = cmd.attr.port_num; attr.grh.flow_label = cmd.attr.grh.flow_label; attr.grh.sgid_index = cmd.attr.grh.sgid_index; -- cgit v1.2.3 From ac4e7b35579de55db50d602a472858867808a9c3 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Fri, 6 Jan 2006 16:43:14 -0800 Subject: IB/uverbs: Release event file reference on ib_uverbs_create_cq() error ib_uverbs_create_cq() should release the completion channel event file if an error occurs after it looks it up. Also, if userspace asks for a completion channel and we don't find it, an error should be returned instead of silently creating a CQ without a completion channel. Signed-off-by: Jack Morgenstein Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_cmd.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 12d6cc0a7f80..a02c5a05c984 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -594,13 +594,18 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, if (cmd.comp_vector >= file->device->num_comp_vectors) return -EINVAL; - if (cmd.comp_channel >= 0) - ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); - uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; + if (cmd.comp_channel >= 0) { + ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); + if (!ev_file) { + ret = -EINVAL; + goto err; + } + } + uobj->uobject.user_handle = cmd.user_handle; uobj->uobject.context = file->ucontext; uobj->uverbs_file = file; @@ -664,6 +669,8 @@ err_up: ib_destroy_cq(cq); err: + if (ev_file) + ib_uverbs_release_ucq(file, ev_file, uobj); kfree(uobj); return ret; } -- cgit v1.2.3 From 4f8448dfe8d3804fadad90c9b77494238b4a4eae Mon Sep 17 00:00:00 2001 From: Ralph Campbell Date: Fri, 6 Jan 2006 16:43:47 -0800 Subject: IB: Set GIDs correctly in ib_create_ah_from_wc() ib_create_ah_from_wc() doesn't create the correct return address (AH) when there is a GRH present (source & dest GIDs need to be swapped). Signed-off-by: Ralph Campbell Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/verbs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 4c15e112736c..c857361be449 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -107,9 +107,9 @@ struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, if (wc->wc_flags & IB_WC_GRH) { ah_attr.ah_flags = IB_AH_GRH; - ah_attr.grh.dgid = grh->dgid; + ah_attr.grh.dgid = grh->sgid; - ret = ib_find_cached_gid(pd->device, &grh->sgid, &port_num, + ret = ib_find_cached_gid(pd->device, &grh->dgid, &port_num, &gid_index); if (ret) return ERR_PTR(ret); -- cgit v1.2.3 From d479e908457f4972205fcafa054f8030e91781ef Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 6 Jan 2006 16:47:00 -0500 Subject: [ACPI] move some run-time structure inits to compile time acpi_processor_limit_fops.write was written at run time, but can be initiailized at compile-time instead. Similar for acpi_video_bus_POST_fops.write and friends, but keep doing those at runtime to avoid prototype-hell. Signed-off-by: Arjan van de Ven Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 2 -- drivers/acpi/processor_perflib.c | 2 +- drivers/acpi/processor_thermal.c | 1 + drivers/acpi/processor_throttling.c | 1 + drivers/acpi/video.c | 8 ++++---- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 1278aca96fe3..60e550f1f955 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -357,7 +357,6 @@ static int acpi_processor_add_fs(struct acpi_device *device) ACPI_PROCESSOR_FILE_THROTTLING)); else { entry->proc_fops = &acpi_processor_throttling_fops; - entry->proc_fops->write = acpi_processor_write_throttling; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } @@ -372,7 +371,6 @@ static int acpi_processor_add_fs(struct acpi_device *device) ACPI_PROCESSOR_FILE_LIMIT)); else { entry->proc_fops = &acpi_processor_limit_fops; - entry->proc_fops->write = acpi_processor_write_limit; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 22c7bb66c200..0c0234e18261 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -520,8 +520,8 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr) "Unable to create '%s' fs entry\n", ACPI_PROCESSOR_FILE_PERFORMANCE)); else { + acpi_processor_perf_fops.write = acpi_processor_write_performance; entry->proc_fops = &acpi_processor_perf_fops; - entry->proc_fops->write = acpi_processor_write_performance; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index dc9817cfb882..22fc9e28a58d 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -394,6 +394,7 @@ ssize_t acpi_processor_write_limit(struct file * file, struct file_operations acpi_processor_limit_fops = { .open = acpi_processor_limit_open_fs, .read = seq_read, + .write = acpi_processor_write_limit, .llseek = seq_lseek, .release = single_release, }; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 74a52d4e79ae..5cd056abfcfb 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -337,6 +337,7 @@ ssize_t acpi_processor_write_throttling(struct file * file, struct file_operations acpi_processor_throttling_fops = { .open = acpi_processor_throttling_open_fs, .read = seq_read, + .write = acpi_processor_write_throttling, .llseek = seq_lseek, .release = single_release, }; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index d10668f14699..bd4887518373 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -920,8 +920,8 @@ static int acpi_video_device_add_fs(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'state' fs entry\n")); else { + acpi_video_device_state_fops.write = acpi_video_device_write_state; entry->proc_fops = &acpi_video_device_state_fops; - entry->proc_fops->write = acpi_video_device_write_state; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } @@ -934,8 +934,8 @@ static int acpi_video_device_add_fs(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'brightness' fs entry\n")); else { + acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness; entry->proc_fops = &acpi_video_device_brightness_fops; - entry->proc_fops->write = acpi_video_device_write_brightness; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } @@ -1239,8 +1239,8 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST' fs entry\n")); else { + acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; entry->proc_fops = &acpi_video_bus_POST_fops; - entry->proc_fops->write = acpi_video_bus_write_POST; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } @@ -1253,8 +1253,8 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'DOS' fs entry\n")); else { + acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; entry->proc_fops = &acpi_video_bus_DOS_fops; - entry->proc_fops->write = acpi_video_bus_write_DOS; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } -- cgit v1.2.3 From 35f652b5ef4ef145ac5514f6302b3f4cebfbbad4 Mon Sep 17 00:00:00 2001 From: Benoit Boissinot Date: Fri, 6 Jan 2006 01:31:00 -0500 Subject: [ACPI] fix acpi_cpufreq.c build warrning Signed-off-by: Benoit Boissinot Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 31ce890865d5..8a5e159d8185 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -306,10 +306,6 @@ acpi_cpufreq_cpu_init ( struct cpufreq_acpi_io *data; unsigned int result = 0; - union acpi_object arg0 = {ACPI_TYPE_BUFFER}; - u32 arg0_buf[3]; - struct acpi_object_list arg_list = {1, &arg0}; - dprintk("acpi_cpufreq_cpu_init\n"); data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); -- cgit v1.2.3 From 876c184b31dc73cc3f38c5b86dee55d091a56769 Mon Sep 17 00:00:00 2001 From: Thomas Rosner Date: Fri, 6 Jan 2006 01:31:00 -0500 Subject: [ACPI] Disable C2/C3 for _all_ IBM R40e Laptops This adds all known BIOS versions of IBM R40e Laptops to the C2/C3 processor state blacklist and thus prevents them from crashing. workaround for http://bugzilla.kernel.org/show_bug.cgi?id=3549 Signed-off-by: Thomas Rosner Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 67 ++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 807b0df308f1..552420e1f890 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -95,22 +95,57 @@ static int set_max_cstate(struct dmi_system_id *id) } static struct dmi_system_id __initdata processor_power_dmi_table[] = { - {set_max_cstate, "IBM ThinkPad R40e", { - DMI_MATCH(DMI_BIOS_VENDOR, - "IBM"), - DMI_MATCH(DMI_BIOS_VERSION, - "1SET60WW")}, - (void *)1}, - {set_max_cstate, "Medion 41700", { - DMI_MATCH(DMI_BIOS_VENDOR, - "Phoenix Technologies LTD"), - DMI_MATCH(DMI_BIOS_VERSION, - "R01-A1J")}, (void *)1}, - {set_max_cstate, "Clevo 5600D", { - DMI_MATCH(DMI_BIOS_VENDOR, - "Phoenix Technologies LTD"), - DMI_MATCH(DMI_BIOS_VERSION, - "SHE845M0.86C.0013.D.0302131307")}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1}, + { set_max_cstate, "IBM ThinkPad R40e", { + DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), + DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1}, + { set_max_cstate, "Medion 41700", { + DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), + DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1}, + { set_max_cstate, "Clevo 5600D", { + DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), + DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")}, (void *)2}, {}, }; -- cgit v1.2.3 From d758a8fa8ce0566947677f7e70bf70c57ad9445c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 6 Jan 2006 01:31:00 -0500 Subject: [ACPI] fix kernel-doc warnings in acpi/scan.c Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- Documentation/DocBook/kernel-api.tmpl | 1 + drivers/acpi/scan.c | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 767433bdbc40..3c47a3f0dc55 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -369,6 +369,7 @@ X!Edrivers/acpi/motherboard.c X!Edrivers/acpi/bus.c --> !Edrivers/acpi/scan.c +!Idrivers/acpi/scan.c diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0745d20afb8c..3b26a7104363 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -475,8 +475,10 @@ static LIST_HEAD(acpi_bus_drivers); static DECLARE_MUTEX(acpi_bus_drivers_lock); /** - * acpi_bus_match - * -------------- + * acpi_bus_match - match device IDs to driver's supported IDs + * @device: the device that we are trying to match to a driver + * @driver: driver whose device id table is being checked + * * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it * matches the specified driver's criteria. */ @@ -489,8 +491,10 @@ acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver) } /** - * acpi_bus_driver_init - * -------------------- + * acpi_bus_driver_init - add a device to a driver + * @device: the device to add and initialize + * @driver: driver for the device + * * Used to initialize a device via its device driver. Called whenever a * driver is bound to a device. Invokes the driver's add() and start() ops. */ @@ -603,8 +607,9 @@ static int acpi_driver_detach(struct acpi_driver *drv) } /** - * acpi_bus_register_driver - * ------------------------ + * acpi_bus_register_driver - register a driver with the ACPI bus + * @driver: driver being registered + * * Registers a driver with the ACPI bus. Searches the namespace for all * devices that match the driver's criteria and binds. Returns the * number of devices that were claimed by the driver, or a negative @@ -633,8 +638,9 @@ int acpi_bus_register_driver(struct acpi_driver *driver) EXPORT_SYMBOL(acpi_bus_register_driver); /** - * acpi_bus_unregister_driver - * -------------------------- + * acpi_bus_unregister_driver - unregisters a driver with the APIC bus + * @driver: driver to unregister + * * Unregisters a driver with the ACPI bus. Searches the namespace for all * devices that match the driver's criteria and unbinds. */ @@ -660,8 +666,9 @@ int acpi_bus_unregister_driver(struct acpi_driver *driver) EXPORT_SYMBOL(acpi_bus_unregister_driver); /** - * acpi_bus_find_driver - * -------------------- + * acpi_bus_find_driver - check if there is a driver installed for the device + * @device: device that we are trying to find a supporting driver for + * * Parses the list of registered drivers looking for a driver applicable for * the specified device. */ -- cgit v1.2.3 From f9a204e1de73a7007de66fb289e1d64a7665c9b4 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 6 Jan 2006 01:31:00 -0500 Subject: [ACPI] remove Kconfig "default y" for laptop drivers Signed-off-by: Borislav Petkov Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fce21c257523..6d61945260a8 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -168,7 +168,6 @@ config ACPI_NUMA config ACPI_ASUS tristate "ASUS/Medion Laptop Extras" depends on X86 - default y ---help--- This driver provides support for extra features of ACPI-compatible ASUS laptops. As some of Medion laptops are made by ASUS, it may also @@ -209,7 +208,6 @@ config ACPI_IBM config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on X86 - default y ---help--- This driver adds support for access to certain system settings on "legacy free" Toshiba laptops. These laptops can be recognized by -- cgit v1.2.3 From 07b0120d53a3e7cbc88458a64a4d668fc416100f Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Fri, 6 Jan 2006 01:31:00 -0500 Subject: [PNPACPI] Ignore devices that have no resources Ignore devices that don't have a _CRS method. They are useless for the PNP layer as they don't provide any resources. Cc: Adam Belay Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 816479ad217b..e77d1feb759e 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -131,7 +131,8 @@ static int __init pnpacpi_add_device(struct acpi_device *device) struct pnp_id *dev_id; struct pnp_dev *dev; - if (!ispnpidacpi(acpi_device_hid(device)) || + status = acpi_get_handle(device->handle, "_CRS", &temp); + if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) || is_exclusive_device(device)) return 0; -- cgit v1.2.3 From c4bb6f5ad968540d7f9619565bacd18d7419b85f Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Fri, 6 Jan 2006 01:31:00 -0500 Subject: [PNPACPI] clean excluded_id_list[] Clean the blacklist. Battery, Button, Fan have no _CRS and can be removed. PCI root is in pnpbios and is harmless. Cc: Adam Belay Cc: "Li, Shaohua" Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index e77d1feb759e..f104577f73e0 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -27,12 +27,15 @@ static int num = 0; +/* We need only to blacklist devices that have already an acpi driver that + * can't use pnp layer. We don't need to blacklist device that are directly + * used by the kernel (PCI root, ...), as it is harmless and there were + * already present in pnpbios. But there is an exception for devices that + * have irqs (PIC, Timer) because we call acpi_register_gsi. + * Finaly only devices that have a CRS method need to be in this list. + */ static char __initdata excluded_id_list[] = - "PNP0C0A," /* Battery */ - "PNP0C0C,PNP0C0E,PNP0C0D," /* Button */ "PNP0C09," /* EC */ - "PNP0C0B," /* Fan */ - "PNP0A03," /* PCI root */ "PNP0C0F," /* Link device */ "PNP0000," /* PIC */ "PNP0100," /* Timer */ -- cgit v1.2.3 From f99c89297cd6995ccad6394c87383941c2570fe9 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Sat, 7 Jan 2006 10:44:32 +0000 Subject: [ARM] 3232/1: i.MX Frame Buffer undeclared "dev" variable fix Patch from Pavel Pisa Correction of the code broken by update whole-tree platform devices update. Signed-off-by: Pavel Pisa Signed-off-by: Sascha Hauer Signed-off-by: Russell King --- drivers/video/imxfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 5924cc225c95..1718baaeed2a 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -554,7 +554,7 @@ static int __init imxfb_probe(struct platform_device *pdev) inf = pdev->dev.platform_data; if(!inf) { - dev_err(dev,"No platform_data available\n"); + dev_err(&pdev->dev,"No platform_data available\n"); return -ENOMEM; } @@ -579,7 +579,7 @@ static int __init imxfb_probe(struct platform_device *pdev) if (!inf->fixed_screen_cpu) { ret = imxfb_map_video_memory(info); if (ret) { - dev_err(dev, "Failed to allocate video RAM: %d\n", ret); + dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto failed_map; } @@ -608,7 +608,7 @@ static int __init imxfb_probe(struct platform_device *pdev) imxfb_set_par(info); ret = register_framebuffer(info); if (ret < 0) { - dev_err(dev, "failed to register framebuffer\n"); + dev_err(&pdev->dev, "failed to register framebuffer\n"); goto failed_register; } -- cgit v1.2.3 From 2c041f4b9be5cecbd0a042ecd9122a9db6f50416 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sat, 7 Jan 2006 11:12:26 +0000 Subject: [ARM] 3235/1: SharpSL PM: Fix a gcc4 build error Patch from Richard Purdie Fix a gcc4 build error (incomplete element type) in the pxa SharpSL PM code. Signed-off-by: Richard Purdie Signed-off-by: Russell King --- arch/arm/mach-pxa/corgi_pm.c | 1 - arch/arm/mach-pxa/sharpsl.h | 1 + arch/arm/mach-pxa/sharpsl_pm.c | 1 - arch/arm/mach-pxa/spitz_pm.c | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c index de8b2403c929..7a1ab73e9e10 100644 --- a/arch/arm/mach-pxa/corgi_pm.c +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h index 92b793050509..da4769caaf72 100644 --- a/arch/arm/mach-pxa/sharpsl.h +++ b/arch/arm/mach-pxa/sharpsl.h @@ -7,6 +7,7 @@ * */ +#include /* * SharpSL SSP Driver diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index f6fefb181411..6d402b262d8a 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "sharpsl.h" struct battery_thresh spitz_battery_levels_acin[] = { diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c index 76a5c26dea0b..5e5bdc898482 100644 --- a/arch/arm/mach-pxa/spitz_pm.c +++ b/arch/arm/mach-pxa/spitz_pm.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 6351610d6906aacbf9176cbdd045dd3876eec4c0 Mon Sep 17 00:00:00 2001 From: Andre McCurdy Date: Sat, 7 Jan 2006 11:39:20 +0000 Subject: [ARM] 3239/1: Add ARM optimised swab32 Patch from Andre McCurdy Replaces generic swab32 routine with a more ARM friendly version. Reduces kernel text size by approx 1200 bytes when compiled with 3.4.4 and approx 2400 bytes with 4.0.2 Probably some performance benefit as well. Signed-off-by: Andre McCurdy Signed-off-by: Russell King --- include/asm-arm/byteorder.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/asm-arm/byteorder.h b/include/asm-arm/byteorder.h index d648a1915c33..af42f449b9a6 100644 --- a/include/asm-arm/byteorder.h +++ b/include/asm-arm/byteorder.h @@ -15,9 +15,22 @@ #ifndef __ASM_ARM_BYTEORDER_H #define __ASM_ARM_BYTEORDER_H - #include +static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) +{ + __u32 t; + + t = x ^ ((x << 16) | (x >> 16)); /* eor r1,r0,r0,ror #16 */ + x = (x << 24) | (x >> 8); /* mov r0,r0,ror #8 */ + t &= ~0x00FF0000; /* bic r1,r1,#0x00FF0000 */ + x ^= (t >> 8); /* eor r0,r0,r1,lsr #8 */ + + return x; +} + +#define __arch__swab32(x) ___arch__swab32(x) + #if !defined(__STRICT_ANSI__) || defined(__KERNEL__) # define __BYTEORDER_HAS_U64__ # define __SWAB_64_THRU_32__ -- cgit v1.2.3 From a62c80e559809e6c7851ec04d30575e85ad6f6ed Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 7 Jan 2006 13:52:45 +0000 Subject: [ARM] Move AMBA include files to include/linux/amba/ Since the ARM AMBA bus is used on MIPS as well as ARM, we need to make the bus available for other architectures to use. Move the AMBA include files from include/asm-arm/hardware/ to include/linux/amba/ Signed-off-by: Russell King --- arch/arm/common/amba.c | 2 +- arch/arm/mach-aaec2000/core.c | 2 +- arch/arm/mach-aaec2000/core.h | 2 +- arch/arm/mach-integrator/core.c | 2 +- arch/arm/mach-integrator/impd1.c | 4 +- arch/arm/mach-integrator/integrator_ap.c | 4 +- arch/arm/mach-integrator/integrator_cp.c | 6 +- arch/arm/mach-integrator/time.c | 2 +- arch/arm/mach-realview/core.c | 4 +- arch/arm/mach-realview/core.h | 3 +- arch/arm/mach-realview/realview_eb.c | 2 +- arch/arm/mach-versatile/core.c | 4 +- arch/arm/mach-versatile/core.h | 2 +- arch/arm/mach-versatile/versatile_ab.c | 2 +- arch/arm/mach-versatile/versatile_pb.c | 2 +- drivers/input/serio/ambakmi.c | 4 +- drivers/mmc/mmci.c | 2 +- drivers/serial/amba-pl010.c | 4 +- drivers/serial/amba-pl011.c | 4 +- drivers/video/amba-clcd.c | 5 +- include/asm-arm/arch-integrator/debug-macro.S | 2 +- include/asm-arm/arch-realview/debug-macro.S | 2 +- include/asm-arm/arch-versatile/debug-macro.S | 2 +- include/asm-arm/hardware/amba.h | 55 ------ include/asm-arm/hardware/amba_clcd.h | 271 -------------------------- include/asm-arm/hardware/amba_kmi.h | 92 --------- include/asm-arm/hardware/amba_serial.h | 161 --------------- include/linux/amba/bus.h | 55 ++++++ include/linux/amba/clcd.h | 271 ++++++++++++++++++++++++++ include/linux/amba/kmi.h | 92 +++++++++ include/linux/amba/serial.h | 161 +++++++++++++++ sound/arm/aaci.c | 2 +- 32 files changed, 614 insertions(+), 614 deletions(-) delete mode 100644 include/asm-arm/hardware/amba.h delete mode 100644 include/asm-arm/hardware/amba_clcd.h delete mode 100644 include/asm-arm/hardware/amba_kmi.h delete mode 100644 include/asm-arm/hardware/amba_serial.h create mode 100644 include/linux/amba/bus.h create mode 100644 include/linux/amba/clcd.h create mode 100644 include/linux/amba/kmi.h create mode 100644 include/linux/amba/serial.h diff --git a/arch/arm/common/amba.c b/arch/arm/common/amba.c index e1013112c354..2bb0ce81bb69 100644 --- a/arch/arm/common/amba.c +++ b/arch/arm/common/amba.c @@ -12,10 +12,10 @@ #include #include #include +#include #include #include -#include #include #define to_amba_device(d) container_of(d, struct amba_device, dev) diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index 4e706d9ad368..dce4815cf53c 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c @@ -20,11 +20,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/arch/arm/mach-aaec2000/core.h b/arch/arm/mach-aaec2000/core.h index daefc0ea14a1..b6029a95f19c 100644 --- a/arch/arm/mach-aaec2000/core.h +++ b/arch/arm/mach-aaec2000/core.h @@ -9,7 +9,7 @@ * */ -#include +#include struct sys_timer; diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index dacbf504dae2..20071a2767cc 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -15,11 +15,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index a4bafee77a06..a85d471c5bfa 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -18,11 +18,11 @@ #include #include #include +#include +#include #include #include -#include -#include #include #include #include diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 4c0f7c65facf..3afedeb56a6e 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -32,8 +34,6 @@ #include #include /* HZ */ #include -#include -#include #include diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 93f7ccb22c27..16cf2482a3e9 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -16,15 +16,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include -#include -#include -#include #include #include diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index 1a844ca139e0..9f46aaef8968 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c @@ -14,8 +14,8 @@ #include #include #include +#include -#include #include #include #include diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index af6580f1ceb8..4a222f59f2cf 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -24,14 +24,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include -#include #include #include diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index c06e6041df41..93e86d9f439c 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -22,7 +22,8 @@ #ifndef __ASM_ARCH_REALVIEW_H #define __ASM_ARCH_REALVIEW_H -#include +#include + #include #include diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 7dc32503fdf2..112f7592aca9 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index a1ca46630dda..90023745b23a 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -25,14 +25,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include -#include #include #include diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h index 588c20669d5d..afcaa858eb1f 100644 --- a/arch/arm/mach-versatile/core.h +++ b/arch/arm/mach-versatile/core.h @@ -22,7 +22,7 @@ #ifndef __ASM_ARCH_VERSATILE_H #define __ASM_ARCH_VERSATILE_H -#include +#include extern void __init versatile_init(void); extern void __init versatile_init_irq(void); diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c index 8b0b3bef24ae..e74c8a2fbb95 100644 --- a/arch/arm/mach-versatile/versatile_ab.c +++ b/arch/arm/mach-versatile/versatile_ab.c @@ -23,12 +23,12 @@ #include #include #include +#include #include #include #include #include -#include #include diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c index 7c3078c38916..22d5ca07f75d 100644 --- a/arch/arm/mach-versatile/versatile_pb.c +++ b/arch/arm/mach-versatile/versatile_pb.c @@ -23,12 +23,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index d847ed51cfb1..cbab5d26377b 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -19,11 +19,11 @@ #include #include #include +#include +#include #include #include -#include -#include #include #define KMI_BASE (kmi->base) diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 31b0b6d612bf..57375bc12372 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -19,12 +19,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index ddd0307fece2..48f6e872314b 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -47,12 +47,12 @@ #include #include #include +#include +#include #include #include #include -#include -#include #define UART_NR 2 diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 531b0e4f25e5..4ae4dff59795 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -47,12 +47,12 @@ #include #include #include +#include +#include #include #include -#include #include -#include #define UART_NR 14 diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 69421c86252c..3358a1429651 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -21,13 +21,12 @@ #include #include #include +#include +#include #include -#include #include -#include - #define to_clcd(info) container_of(info, struct clcd_fb, fb) /* This is limited to 16 characters when displayed by X startup */ diff --git a/include/asm-arm/arch-integrator/debug-macro.S b/include/asm-arm/arch-integrator/debug-macro.S index 484a1aa47098..031d30941791 100644 --- a/include/asm-arm/arch-integrator/debug-macro.S +++ b/include/asm-arm/arch-integrator/debug-macro.S @@ -11,7 +11,7 @@ * */ -#include +#include .macro addruart,rx mrc p15, 0, \rx, c1, c0 diff --git a/include/asm-arm/arch-realview/debug-macro.S b/include/asm-arm/arch-realview/debug-macro.S index ed28bd012236..017ad996848d 100644 --- a/include/asm-arm/arch-realview/debug-macro.S +++ b/include/asm-arm/arch-realview/debug-macro.S @@ -11,7 +11,7 @@ * */ -#include +#include .macro addruart,rx mrc p15, 0, \rx, c1, c0 diff --git a/include/asm-arm/arch-versatile/debug-macro.S b/include/asm-arm/arch-versatile/debug-macro.S index 89e38ac1444e..ef6167116dbb 100644 --- a/include/asm-arm/arch-versatile/debug-macro.S +++ b/include/asm-arm/arch-versatile/debug-macro.S @@ -11,7 +11,7 @@ * */ -#include +#include .macro addruart,rx mrc p15, 0, \rx, c1, c0 diff --git a/include/asm-arm/hardware/amba.h b/include/asm-arm/hardware/amba.h deleted file mode 100644 index 51e6e54b2aa1..000000000000 --- a/include/asm-arm/hardware/amba.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * linux/include/asm-arm/hardware/amba.h - * - * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef ASMARM_AMBA_H -#define ASMARM_AMBA_H - -#define AMBA_NR_IRQS 2 - -struct amba_device { - struct device dev; - struct resource res; - u64 dma_mask; - unsigned int periphid; - unsigned int irq[AMBA_NR_IRQS]; -}; - -struct amba_id { - unsigned int id; - unsigned int mask; - void *data; -}; - -struct amba_driver { - struct device_driver drv; - int (*probe)(struct amba_device *, void *); - int (*remove)(struct amba_device *); - void (*shutdown)(struct amba_device *); - int (*suspend)(struct amba_device *, pm_message_t); - int (*resume)(struct amba_device *); - struct amba_id *id_table; -}; - -#define amba_get_drvdata(d) dev_get_drvdata(&d->dev) -#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p) - -int amba_driver_register(struct amba_driver *); -void amba_driver_unregister(struct amba_driver *); -int amba_device_register(struct amba_device *, struct resource *); -void amba_device_unregister(struct amba_device *); -struct amba_device *amba_find_device(const char *, struct device *, unsigned int, unsigned int); -int amba_request_regions(struct amba_device *, const char *); -void amba_release_regions(struct amba_device *); - -#define amba_config(d) (((d)->periphid >> 24) & 0xff) -#define amba_rev(d) (((d)->periphid >> 20) & 0x0f) -#define amba_manf(d) (((d)->periphid >> 12) & 0xff) -#define amba_part(d) ((d)->periphid & 0xfff) - -#endif diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h deleted file mode 100644 index 6b8d73dc1ab0..000000000000 --- a/include/asm-arm/hardware/amba_clcd.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel. - * - * David A Rusling - * - * Copyright (C) 2001 ARM Limited - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ -#include -#include - -/* - * CLCD Controller Internal Register addresses - */ -#define CLCD_TIM0 0x00000000 -#define CLCD_TIM1 0x00000004 -#define CLCD_TIM2 0x00000008 -#define CLCD_TIM3 0x0000000c -#define CLCD_UBAS 0x00000010 -#define CLCD_LBAS 0x00000014 - -#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW) -#define CLCD_IENB 0x00000018 -#define CLCD_CNTL 0x0000001c -#else -/* - * Someone rearranged these two registers on the Versatile - * platform... - */ -#define CLCD_IENB 0x0000001c -#define CLCD_CNTL 0x00000018 -#endif - -#define CLCD_STAT 0x00000020 -#define CLCD_INTR 0x00000024 -#define CLCD_UCUR 0x00000028 -#define CLCD_LCUR 0x0000002C -#define CLCD_PALL 0x00000200 -#define CLCD_PALETTE 0x00000200 - -#define TIM2_CLKSEL (1 << 5) -#define TIM2_IVS (1 << 11) -#define TIM2_IHS (1 << 12) -#define TIM2_IPC (1 << 13) -#define TIM2_IOE (1 << 14) -#define TIM2_BCD (1 << 26) - -#define CNTL_LCDEN (1 << 0) -#define CNTL_LCDBPP1 (0 << 1) -#define CNTL_LCDBPP2 (1 << 1) -#define CNTL_LCDBPP4 (2 << 1) -#define CNTL_LCDBPP8 (3 << 1) -#define CNTL_LCDBPP16 (4 << 1) -#define CNTL_LCDBPP24 (5 << 1) -#define CNTL_LCDBW (1 << 4) -#define CNTL_LCDTFT (1 << 5) -#define CNTL_LCDMONO8 (1 << 6) -#define CNTL_LCDDUAL (1 << 7) -#define CNTL_BGR (1 << 8) -#define CNTL_BEBO (1 << 9) -#define CNTL_BEPO (1 << 10) -#define CNTL_LCDPWR (1 << 11) -#define CNTL_LCDVCOMP(x) ((x) << 12) -#define CNTL_LDMAFIFOTIME (1 << 15) -#define CNTL_WATERMARK (1 << 16) - -struct clcd_panel { - struct fb_videomode mode; - signed short width; /* width in mm */ - signed short height; /* height in mm */ - u32 tim2; - u32 tim3; - u32 cntl; - unsigned int bpp:8, - fixedtimings:1, - grayscale:1; - unsigned int connector; -}; - -struct clcd_regs { - u32 tim0; - u32 tim1; - u32 tim2; - u32 tim3; - u32 cntl; - unsigned long pixclock; -}; - -struct clcd_fb; - -/* - * the board-type specific routines - */ -struct clcd_board { - const char *name; - - /* - * Optional. Check whether the var structure is acceptable - * for this display. - */ - int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var); - - /* - * Compulsary. Decode fb->fb.var into regs->*. In the case of - * fixed timing, set regs->* to the register values required. - */ - void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs); - - /* - * Optional. Disable any extra display hardware. - */ - void (*disable)(struct clcd_fb *); - - /* - * Optional. Enable any extra display hardware. - */ - void (*enable)(struct clcd_fb *); - - /* - * Setup platform specific parts of CLCD driver - */ - int (*setup)(struct clcd_fb *); - - /* - * mmap the framebuffer memory - */ - int (*mmap)(struct clcd_fb *, struct vm_area_struct *); - - /* - * Remove platform specific parts of CLCD driver - */ - void (*remove)(struct clcd_fb *); -}; - -struct amba_device; -struct clk; - -/* this data structure describes each frame buffer device we find */ -struct clcd_fb { - struct fb_info fb; - struct amba_device *dev; - struct clk *clk; - struct clcd_panel *panel; - struct clcd_board *board; - void *board_data; - void __iomem *regs; - u32 clcd_cntl; - u32 cmap[16]; -}; - -static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) -{ - u32 val, cpl; - - /* - * Program the CLCD controller registers and start the CLCD - */ - val = ((fb->fb.var.xres / 16) - 1) << 2; - val |= (fb->fb.var.hsync_len - 1) << 8; - val |= (fb->fb.var.right_margin - 1) << 16; - val |= (fb->fb.var.left_margin - 1) << 24; - regs->tim0 = val; - - val = fb->fb.var.yres; - if (fb->panel->cntl & CNTL_LCDDUAL) - val /= 2; - val -= 1; - val |= (fb->fb.var.vsync_len - 1) << 10; - val |= fb->fb.var.lower_margin << 16; - val |= fb->fb.var.upper_margin << 24; - regs->tim1 = val; - - val = fb->panel->tim2; - val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS; - val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS; - - cpl = fb->fb.var.xres_virtual; - if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */ - /* / 1 */; - else if (!fb->fb.var.grayscale) /* STN color */ - cpl = cpl * 8 / 3; - else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */ - cpl /= 8; - else /* STN monochrome, 4bit */ - cpl /= 4; - - regs->tim2 = val | ((cpl - 1) << 16); - - regs->tim3 = fb->panel->tim3; - - val = fb->panel->cntl; - if (fb->fb.var.grayscale) - val |= CNTL_LCDBW; - - switch (fb->fb.var.bits_per_pixel) { - case 1: - val |= CNTL_LCDBPP1; - break; - case 2: - val |= CNTL_LCDBPP2; - break; - case 4: - val |= CNTL_LCDBPP4; - break; - case 8: - val |= CNTL_LCDBPP8; - break; - case 16: - val |= CNTL_LCDBPP16; - break; - case 32: - val |= CNTL_LCDBPP24; - break; - } - - regs->cntl = val; - regs->pixclock = fb->fb.var.pixclock; -} - -static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var) -{ - var->xres_virtual = var->xres = (var->xres + 15) & ~15; - var->yres_virtual = var->yres = (var->yres + 1) & ~1; - -#define CHECK(e,l,h) (var->e < l || var->e > h) - if (CHECK(right_margin, (5+1), 256) || /* back porch */ - CHECK(left_margin, (5+1), 256) || /* front porch */ - CHECK(hsync_len, (5+1), 256) || - var->xres > 4096 || - var->lower_margin > 255 || /* back porch */ - var->upper_margin > 255 || /* front porch */ - var->vsync_len > 32 || - var->yres > 1024) - return -EINVAL; -#undef CHECK - - /* single panel mode: PCD = max(PCD, 1) */ - /* dual panel mode: PCD = max(PCD, 5) */ - - /* - * You can't change the grayscale setting, and - * we can only do non-interlaced video. - */ - if (var->grayscale != fb->fb.var.grayscale || - (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - return -EINVAL; - -#define CHECK(e) (var->e != fb->fb.var.e) - if (fb->panel->fixedtimings && - (CHECK(xres) || - CHECK(yres) || - CHECK(bits_per_pixel) || - CHECK(pixclock) || - CHECK(left_margin) || - CHECK(right_margin) || - CHECK(upper_margin) || - CHECK(lower_margin) || - CHECK(hsync_len) || - CHECK(vsync_len) || - CHECK(sync))) - return -EINVAL; -#undef CHECK - - var->nonstd = 0; - var->accel_flags = 0; - - return 0; -} diff --git a/include/asm-arm/hardware/amba_kmi.h b/include/asm-arm/hardware/amba_kmi.h deleted file mode 100644 index a39e5be751b3..000000000000 --- a/include/asm-arm/hardware/amba_kmi.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * linux/include/asm-arm/hardware/amba_kmi.h - * - * Internal header file for AMBA KMI ports - * - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * --------------------------------------------------------------------------- - * From ARM PrimeCell(tm) PS2 Keyboard/Mouse Interface (PL050) Technical - * Reference Manual - ARM DDI 0143B - see http://www.arm.com/ - * --------------------------------------------------------------------------- - */ -#ifndef ASM_ARM_HARDWARE_AMBA_KMI_H -#define ASM_ARM_HARDWARE_AMBA_KMI_H - -/* - * KMI control register: - * KMICR_TYPE 0 = PS2/AT mode, 1 = No line control bit mode - * KMICR_RXINTREN 1 = enable RX interrupts - * KMICR_TXINTREN 1 = enable TX interrupts - * KMICR_EN 1 = enable KMI - * KMICR_FD 1 = force KMI data low - * KMICR_FC 1 = force KMI clock low - */ -#define KMICR (KMI_BASE + 0x00) -#define KMICR_TYPE (1 << 5) -#define KMICR_RXINTREN (1 << 4) -#define KMICR_TXINTREN (1 << 3) -#define KMICR_EN (1 << 2) -#define KMICR_FD (1 << 1) -#define KMICR_FC (1 << 0) - -/* - * KMI status register: - * KMISTAT_TXEMPTY 1 = transmitter register empty - * KMISTAT_TXBUSY 1 = currently sending data - * KMISTAT_RXFULL 1 = receiver register ready to be read - * KMISTAT_RXBUSY 1 = currently receiving data - * KMISTAT_RXPARITY parity of last databyte received - * KMISTAT_IC current level of KMI clock input - * KMISTAT_ID current level of KMI data input - */ -#define KMISTAT (KMI_BASE + 0x04) -#define KMISTAT_TXEMPTY (1 << 6) -#define KMISTAT_TXBUSY (1 << 5) -#define KMISTAT_RXFULL (1 << 4) -#define KMISTAT_RXBUSY (1 << 3) -#define KMISTAT_RXPARITY (1 << 2) -#define KMISTAT_IC (1 << 1) -#define KMISTAT_ID (1 << 0) - -/* - * KMI data register - */ -#define KMIDATA (KMI_BASE + 0x08) - -/* - * KMI clock divisor: to generate 8MHz internal clock - * div = (ref / 8MHz) - 1; 0 <= div <= 15 - */ -#define KMICLKDIV (KMI_BASE + 0x0c) - -/* - * KMI interrupt register: - * KMIIR_TXINTR 1 = transmit interrupt asserted - * KMIIR_RXINTR 1 = receive interrupt asserted - */ -#define KMIIR (KMI_BASE + 0x10) -#define KMIIR_TXINTR (1 << 1) -#define KMIIR_RXINTR (1 << 0) - -/* - * The size of the KMI primecell - */ -#define KMI_SIZE (0x100) - -#endif diff --git a/include/asm-arm/hardware/amba_serial.h b/include/asm-arm/hardware/amba_serial.h deleted file mode 100644 index dc726ffccebd..000000000000 --- a/include/asm-arm/hardware/amba_serial.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * linux/include/asm-arm/hardware/serial_amba.h - * - * Internal header file for AMBA serial ports - * - * Copyright (C) ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H -#define ASM_ARM_HARDWARE_SERIAL_AMBA_H - -/* ------------------------------------------------------------------------------- - * From AMBA UART (PL010) Block Specification - * ------------------------------------------------------------------------------- - * UART Register Offsets. - */ -#define UART01x_DR 0x00 /* Data read or written from the interface. */ -#define UART01x_RSR 0x04 /* Receive status register (Read). */ -#define UART01x_ECR 0x04 /* Error clear register (Write). */ -#define UART010_LCRH 0x08 /* Line control register, high byte. */ -#define UART010_LCRM 0x0C /* Line control register, middle byte. */ -#define UART010_LCRL 0x10 /* Line control register, low byte. */ -#define UART010_CR 0x14 /* Control register. */ -#define UART01x_FR 0x18 /* Flag register (Read only). */ -#define UART010_IIR 0x1C /* Interrupt indentification register (Read). */ -#define UART010_ICR 0x1C /* Interrupt clear register (Write). */ -#define UART01x_ILPR 0x20 /* IrDA low power counter register. */ -#define UART011_IBRD 0x24 /* Integer baud rate divisor register. */ -#define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */ -#define UART011_LCRH 0x2c /* Line control register. */ -#define UART011_CR 0x30 /* Control register. */ -#define UART011_IFLS 0x34 /* Interrupt fifo level select. */ -#define UART011_IMSC 0x38 /* Interrupt mask. */ -#define UART011_RIS 0x3c /* Raw interrupt status. */ -#define UART011_MIS 0x40 /* Masked interrupt status. */ -#define UART011_ICR 0x44 /* Interrupt clear register. */ -#define UART011_DMACR 0x48 /* DMA control register. */ - -#define UART011_DR_OE (1 << 11) -#define UART011_DR_BE (1 << 10) -#define UART011_DR_PE (1 << 9) -#define UART011_DR_FE (1 << 8) - -#define UART01x_RSR_OE 0x08 -#define UART01x_RSR_BE 0x04 -#define UART01x_RSR_PE 0x02 -#define UART01x_RSR_FE 0x01 - -#define UART011_FR_RI 0x100 -#define UART011_FR_TXFE 0x080 -#define UART011_FR_RXFF 0x040 -#define UART01x_FR_TXFF 0x020 -#define UART01x_FR_RXFE 0x010 -#define UART01x_FR_BUSY 0x008 -#define UART01x_FR_DCD 0x004 -#define UART01x_FR_DSR 0x002 -#define UART01x_FR_CTS 0x001 -#define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) - -#define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ -#define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */ -#define UART011_CR_OUT2 0x2000 /* OUT2 */ -#define UART011_CR_OUT1 0x1000 /* OUT1 */ -#define UART011_CR_RTS 0x0800 /* RTS */ -#define UART011_CR_DTR 0x0400 /* DTR */ -#define UART011_CR_RXE 0x0200 /* receive enable */ -#define UART011_CR_TXE 0x0100 /* transmit enable */ -#define UART011_CR_LBE 0x0080 /* loopback enable */ -#define UART010_CR_RTIE 0x0040 -#define UART010_CR_TIE 0x0020 -#define UART010_CR_RIE 0x0010 -#define UART010_CR_MSIE 0x0008 -#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ -#define UART01x_CR_SIREN 0x0002 /* SIR enable */ -#define UART01x_CR_UARTEN 0x0001 /* UART enable */ - -#define UART011_LCRH_SPS 0x80 -#define UART01x_LCRH_WLEN_8 0x60 -#define UART01x_LCRH_WLEN_7 0x40 -#define UART01x_LCRH_WLEN_6 0x20 -#define UART01x_LCRH_WLEN_5 0x00 -#define UART01x_LCRH_FEN 0x10 -#define UART01x_LCRH_STP2 0x08 -#define UART01x_LCRH_EPS 0x04 -#define UART01x_LCRH_PEN 0x02 -#define UART01x_LCRH_BRK 0x01 - -#define UART010_IIR_RTIS 0x08 -#define UART010_IIR_TIS 0x04 -#define UART010_IIR_RIS 0x02 -#define UART010_IIR_MIS 0x01 - -#define UART011_IFLS_RX1_8 (0 << 3) -#define UART011_IFLS_RX2_8 (1 << 3) -#define UART011_IFLS_RX4_8 (2 << 3) -#define UART011_IFLS_RX6_8 (3 << 3) -#define UART011_IFLS_RX7_8 (4 << 3) -#define UART011_IFLS_TX1_8 (0 << 0) -#define UART011_IFLS_TX2_8 (1 << 0) -#define UART011_IFLS_TX4_8 (2 << 0) -#define UART011_IFLS_TX6_8 (3 << 0) -#define UART011_IFLS_TX7_8 (4 << 0) - -#define UART011_OEIM (1 << 10) /* overrun error interrupt mask */ -#define UART011_BEIM (1 << 9) /* break error interrupt mask */ -#define UART011_PEIM (1 << 8) /* parity error interrupt mask */ -#define UART011_FEIM (1 << 7) /* framing error interrupt mask */ -#define UART011_RTIM (1 << 6) /* receive timeout interrupt mask */ -#define UART011_TXIM (1 << 5) /* transmit interrupt mask */ -#define UART011_RXIM (1 << 4) /* receive interrupt mask */ -#define UART011_DSRMIM (1 << 3) /* DSR interrupt mask */ -#define UART011_DCDMIM (1 << 2) /* DCD interrupt mask */ -#define UART011_CTSMIM (1 << 1) /* CTS interrupt mask */ -#define UART011_RIMIM (1 << 0) /* RI interrupt mask */ - -#define UART011_OEIS (1 << 10) /* overrun error interrupt status */ -#define UART011_BEIS (1 << 9) /* break error interrupt status */ -#define UART011_PEIS (1 << 8) /* parity error interrupt status */ -#define UART011_FEIS (1 << 7) /* framing error interrupt status */ -#define UART011_RTIS (1 << 6) /* receive timeout interrupt status */ -#define UART011_TXIS (1 << 5) /* transmit interrupt status */ -#define UART011_RXIS (1 << 4) /* receive interrupt status */ -#define UART011_DSRMIS (1 << 3) /* DSR interrupt status */ -#define UART011_DCDMIS (1 << 2) /* DCD interrupt status */ -#define UART011_CTSMIS (1 << 1) /* CTS interrupt status */ -#define UART011_RIMIS (1 << 0) /* RI interrupt status */ - -#define UART011_OEIC (1 << 10) /* overrun error interrupt clear */ -#define UART011_BEIC (1 << 9) /* break error interrupt clear */ -#define UART011_PEIC (1 << 8) /* parity error interrupt clear */ -#define UART011_FEIC (1 << 7) /* framing error interrupt clear */ -#define UART011_RTIC (1 << 6) /* receive timeout interrupt clear */ -#define UART011_TXIC (1 << 5) /* transmit interrupt clear */ -#define UART011_RXIC (1 << 4) /* receive interrupt clear */ -#define UART011_DSRMIC (1 << 3) /* DSR interrupt clear */ -#define UART011_DCDMIC (1 << 2) /* DCD interrupt clear */ -#define UART011_CTSMIC (1 << 1) /* CTS interrupt clear */ -#define UART011_RIMIC (1 << 0) /* RI interrupt clear */ - -#define UART011_DMAONERR (1 << 2) /* disable dma on error */ -#define UART011_TXDMAE (1 << 1) /* enable transmit dma */ -#define UART011_RXDMAE (1 << 0) /* enable receive dma */ - -#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE) -#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS) - -#endif diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h new file mode 100644 index 000000000000..51e6e54b2aa1 --- /dev/null +++ b/include/linux/amba/bus.h @@ -0,0 +1,55 @@ +/* + * linux/include/asm-arm/hardware/amba.h + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef ASMARM_AMBA_H +#define ASMARM_AMBA_H + +#define AMBA_NR_IRQS 2 + +struct amba_device { + struct device dev; + struct resource res; + u64 dma_mask; + unsigned int periphid; + unsigned int irq[AMBA_NR_IRQS]; +}; + +struct amba_id { + unsigned int id; + unsigned int mask; + void *data; +}; + +struct amba_driver { + struct device_driver drv; + int (*probe)(struct amba_device *, void *); + int (*remove)(struct amba_device *); + void (*shutdown)(struct amba_device *); + int (*suspend)(struct amba_device *, pm_message_t); + int (*resume)(struct amba_device *); + struct amba_id *id_table; +}; + +#define amba_get_drvdata(d) dev_get_drvdata(&d->dev) +#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p) + +int amba_driver_register(struct amba_driver *); +void amba_driver_unregister(struct amba_driver *); +int amba_device_register(struct amba_device *, struct resource *); +void amba_device_unregister(struct amba_device *); +struct amba_device *amba_find_device(const char *, struct device *, unsigned int, unsigned int); +int amba_request_regions(struct amba_device *, const char *); +void amba_release_regions(struct amba_device *); + +#define amba_config(d) (((d)->periphid >> 24) & 0xff) +#define amba_rev(d) (((d)->periphid >> 20) & 0x0f) +#define amba_manf(d) (((d)->periphid >> 12) & 0xff) +#define amba_part(d) ((d)->periphid & 0xfff) + +#endif diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h new file mode 100644 index 000000000000..6b8d73dc1ab0 --- /dev/null +++ b/include/linux/amba/clcd.h @@ -0,0 +1,271 @@ +/* + * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel. + * + * David A Rusling + * + * Copyright (C) 2001 ARM Limited + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#include +#include + +/* + * CLCD Controller Internal Register addresses + */ +#define CLCD_TIM0 0x00000000 +#define CLCD_TIM1 0x00000004 +#define CLCD_TIM2 0x00000008 +#define CLCD_TIM3 0x0000000c +#define CLCD_UBAS 0x00000010 +#define CLCD_LBAS 0x00000014 + +#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW) +#define CLCD_IENB 0x00000018 +#define CLCD_CNTL 0x0000001c +#else +/* + * Someone rearranged these two registers on the Versatile + * platform... + */ +#define CLCD_IENB 0x0000001c +#define CLCD_CNTL 0x00000018 +#endif + +#define CLCD_STAT 0x00000020 +#define CLCD_INTR 0x00000024 +#define CLCD_UCUR 0x00000028 +#define CLCD_LCUR 0x0000002C +#define CLCD_PALL 0x00000200 +#define CLCD_PALETTE 0x00000200 + +#define TIM2_CLKSEL (1 << 5) +#define TIM2_IVS (1 << 11) +#define TIM2_IHS (1 << 12) +#define TIM2_IPC (1 << 13) +#define TIM2_IOE (1 << 14) +#define TIM2_BCD (1 << 26) + +#define CNTL_LCDEN (1 << 0) +#define CNTL_LCDBPP1 (0 << 1) +#define CNTL_LCDBPP2 (1 << 1) +#define CNTL_LCDBPP4 (2 << 1) +#define CNTL_LCDBPP8 (3 << 1) +#define CNTL_LCDBPP16 (4 << 1) +#define CNTL_LCDBPP24 (5 << 1) +#define CNTL_LCDBW (1 << 4) +#define CNTL_LCDTFT (1 << 5) +#define CNTL_LCDMONO8 (1 << 6) +#define CNTL_LCDDUAL (1 << 7) +#define CNTL_BGR (1 << 8) +#define CNTL_BEBO (1 << 9) +#define CNTL_BEPO (1 << 10) +#define CNTL_LCDPWR (1 << 11) +#define CNTL_LCDVCOMP(x) ((x) << 12) +#define CNTL_LDMAFIFOTIME (1 << 15) +#define CNTL_WATERMARK (1 << 16) + +struct clcd_panel { + struct fb_videomode mode; + signed short width; /* width in mm */ + signed short height; /* height in mm */ + u32 tim2; + u32 tim3; + u32 cntl; + unsigned int bpp:8, + fixedtimings:1, + grayscale:1; + unsigned int connector; +}; + +struct clcd_regs { + u32 tim0; + u32 tim1; + u32 tim2; + u32 tim3; + u32 cntl; + unsigned long pixclock; +}; + +struct clcd_fb; + +/* + * the board-type specific routines + */ +struct clcd_board { + const char *name; + + /* + * Optional. Check whether the var structure is acceptable + * for this display. + */ + int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var); + + /* + * Compulsary. Decode fb->fb.var into regs->*. In the case of + * fixed timing, set regs->* to the register values required. + */ + void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs); + + /* + * Optional. Disable any extra display hardware. + */ + void (*disable)(struct clcd_fb *); + + /* + * Optional. Enable any extra display hardware. + */ + void (*enable)(struct clcd_fb *); + + /* + * Setup platform specific parts of CLCD driver + */ + int (*setup)(struct clcd_fb *); + + /* + * mmap the framebuffer memory + */ + int (*mmap)(struct clcd_fb *, struct vm_area_struct *); + + /* + * Remove platform specific parts of CLCD driver + */ + void (*remove)(struct clcd_fb *); +}; + +struct amba_device; +struct clk; + +/* this data structure describes each frame buffer device we find */ +struct clcd_fb { + struct fb_info fb; + struct amba_device *dev; + struct clk *clk; + struct clcd_panel *panel; + struct clcd_board *board; + void *board_data; + void __iomem *regs; + u32 clcd_cntl; + u32 cmap[16]; +}; + +static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) +{ + u32 val, cpl; + + /* + * Program the CLCD controller registers and start the CLCD + */ + val = ((fb->fb.var.xres / 16) - 1) << 2; + val |= (fb->fb.var.hsync_len - 1) << 8; + val |= (fb->fb.var.right_margin - 1) << 16; + val |= (fb->fb.var.left_margin - 1) << 24; + regs->tim0 = val; + + val = fb->fb.var.yres; + if (fb->panel->cntl & CNTL_LCDDUAL) + val /= 2; + val -= 1; + val |= (fb->fb.var.vsync_len - 1) << 10; + val |= fb->fb.var.lower_margin << 16; + val |= fb->fb.var.upper_margin << 24; + regs->tim1 = val; + + val = fb->panel->tim2; + val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS; + val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS; + + cpl = fb->fb.var.xres_virtual; + if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */ + /* / 1 */; + else if (!fb->fb.var.grayscale) /* STN color */ + cpl = cpl * 8 / 3; + else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */ + cpl /= 8; + else /* STN monochrome, 4bit */ + cpl /= 4; + + regs->tim2 = val | ((cpl - 1) << 16); + + regs->tim3 = fb->panel->tim3; + + val = fb->panel->cntl; + if (fb->fb.var.grayscale) + val |= CNTL_LCDBW; + + switch (fb->fb.var.bits_per_pixel) { + case 1: + val |= CNTL_LCDBPP1; + break; + case 2: + val |= CNTL_LCDBPP2; + break; + case 4: + val |= CNTL_LCDBPP4; + break; + case 8: + val |= CNTL_LCDBPP8; + break; + case 16: + val |= CNTL_LCDBPP16; + break; + case 32: + val |= CNTL_LCDBPP24; + break; + } + + regs->cntl = val; + regs->pixclock = fb->fb.var.pixclock; +} + +static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var) +{ + var->xres_virtual = var->xres = (var->xres + 15) & ~15; + var->yres_virtual = var->yres = (var->yres + 1) & ~1; + +#define CHECK(e,l,h) (var->e < l || var->e > h) + if (CHECK(right_margin, (5+1), 256) || /* back porch */ + CHECK(left_margin, (5+1), 256) || /* front porch */ + CHECK(hsync_len, (5+1), 256) || + var->xres > 4096 || + var->lower_margin > 255 || /* back porch */ + var->upper_margin > 255 || /* front porch */ + var->vsync_len > 32 || + var->yres > 1024) + return -EINVAL; +#undef CHECK + + /* single panel mode: PCD = max(PCD, 1) */ + /* dual panel mode: PCD = max(PCD, 5) */ + + /* + * You can't change the grayscale setting, and + * we can only do non-interlaced video. + */ + if (var->grayscale != fb->fb.var.grayscale || + (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; + +#define CHECK(e) (var->e != fb->fb.var.e) + if (fb->panel->fixedtimings && + (CHECK(xres) || + CHECK(yres) || + CHECK(bits_per_pixel) || + CHECK(pixclock) || + CHECK(left_margin) || + CHECK(right_margin) || + CHECK(upper_margin) || + CHECK(lower_margin) || + CHECK(hsync_len) || + CHECK(vsync_len) || + CHECK(sync))) + return -EINVAL; +#undef CHECK + + var->nonstd = 0; + var->accel_flags = 0; + + return 0; +} diff --git a/include/linux/amba/kmi.h b/include/linux/amba/kmi.h new file mode 100644 index 000000000000..a39e5be751b3 --- /dev/null +++ b/include/linux/amba/kmi.h @@ -0,0 +1,92 @@ +/* + * linux/include/asm-arm/hardware/amba_kmi.h + * + * Internal header file for AMBA KMI ports + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * --------------------------------------------------------------------------- + * From ARM PrimeCell(tm) PS2 Keyboard/Mouse Interface (PL050) Technical + * Reference Manual - ARM DDI 0143B - see http://www.arm.com/ + * --------------------------------------------------------------------------- + */ +#ifndef ASM_ARM_HARDWARE_AMBA_KMI_H +#define ASM_ARM_HARDWARE_AMBA_KMI_H + +/* + * KMI control register: + * KMICR_TYPE 0 = PS2/AT mode, 1 = No line control bit mode + * KMICR_RXINTREN 1 = enable RX interrupts + * KMICR_TXINTREN 1 = enable TX interrupts + * KMICR_EN 1 = enable KMI + * KMICR_FD 1 = force KMI data low + * KMICR_FC 1 = force KMI clock low + */ +#define KMICR (KMI_BASE + 0x00) +#define KMICR_TYPE (1 << 5) +#define KMICR_RXINTREN (1 << 4) +#define KMICR_TXINTREN (1 << 3) +#define KMICR_EN (1 << 2) +#define KMICR_FD (1 << 1) +#define KMICR_FC (1 << 0) + +/* + * KMI status register: + * KMISTAT_TXEMPTY 1 = transmitter register empty + * KMISTAT_TXBUSY 1 = currently sending data + * KMISTAT_RXFULL 1 = receiver register ready to be read + * KMISTAT_RXBUSY 1 = currently receiving data + * KMISTAT_RXPARITY parity of last databyte received + * KMISTAT_IC current level of KMI clock input + * KMISTAT_ID current level of KMI data input + */ +#define KMISTAT (KMI_BASE + 0x04) +#define KMISTAT_TXEMPTY (1 << 6) +#define KMISTAT_TXBUSY (1 << 5) +#define KMISTAT_RXFULL (1 << 4) +#define KMISTAT_RXBUSY (1 << 3) +#define KMISTAT_RXPARITY (1 << 2) +#define KMISTAT_IC (1 << 1) +#define KMISTAT_ID (1 << 0) + +/* + * KMI data register + */ +#define KMIDATA (KMI_BASE + 0x08) + +/* + * KMI clock divisor: to generate 8MHz internal clock + * div = (ref / 8MHz) - 1; 0 <= div <= 15 + */ +#define KMICLKDIV (KMI_BASE + 0x0c) + +/* + * KMI interrupt register: + * KMIIR_TXINTR 1 = transmit interrupt asserted + * KMIIR_RXINTR 1 = receive interrupt asserted + */ +#define KMIIR (KMI_BASE + 0x10) +#define KMIIR_TXINTR (1 << 1) +#define KMIIR_RXINTR (1 << 0) + +/* + * The size of the KMI primecell + */ +#define KMI_SIZE (0x100) + +#endif diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h new file mode 100644 index 000000000000..dc726ffccebd --- /dev/null +++ b/include/linux/amba/serial.h @@ -0,0 +1,161 @@ +/* + * linux/include/asm-arm/hardware/serial_amba.h + * + * Internal header file for AMBA serial ports + * + * Copyright (C) ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H +#define ASM_ARM_HARDWARE_SERIAL_AMBA_H + +/* ------------------------------------------------------------------------------- + * From AMBA UART (PL010) Block Specification + * ------------------------------------------------------------------------------- + * UART Register Offsets. + */ +#define UART01x_DR 0x00 /* Data read or written from the interface. */ +#define UART01x_RSR 0x04 /* Receive status register (Read). */ +#define UART01x_ECR 0x04 /* Error clear register (Write). */ +#define UART010_LCRH 0x08 /* Line control register, high byte. */ +#define UART010_LCRM 0x0C /* Line control register, middle byte. */ +#define UART010_LCRL 0x10 /* Line control register, low byte. */ +#define UART010_CR 0x14 /* Control register. */ +#define UART01x_FR 0x18 /* Flag register (Read only). */ +#define UART010_IIR 0x1C /* Interrupt indentification register (Read). */ +#define UART010_ICR 0x1C /* Interrupt clear register (Write). */ +#define UART01x_ILPR 0x20 /* IrDA low power counter register. */ +#define UART011_IBRD 0x24 /* Integer baud rate divisor register. */ +#define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */ +#define UART011_LCRH 0x2c /* Line control register. */ +#define UART011_CR 0x30 /* Control register. */ +#define UART011_IFLS 0x34 /* Interrupt fifo level select. */ +#define UART011_IMSC 0x38 /* Interrupt mask. */ +#define UART011_RIS 0x3c /* Raw interrupt status. */ +#define UART011_MIS 0x40 /* Masked interrupt status. */ +#define UART011_ICR 0x44 /* Interrupt clear register. */ +#define UART011_DMACR 0x48 /* DMA control register. */ + +#define UART011_DR_OE (1 << 11) +#define UART011_DR_BE (1 << 10) +#define UART011_DR_PE (1 << 9) +#define UART011_DR_FE (1 << 8) + +#define UART01x_RSR_OE 0x08 +#define UART01x_RSR_BE 0x04 +#define UART01x_RSR_PE 0x02 +#define UART01x_RSR_FE 0x01 + +#define UART011_FR_RI 0x100 +#define UART011_FR_TXFE 0x080 +#define UART011_FR_RXFF 0x040 +#define UART01x_FR_TXFF 0x020 +#define UART01x_FR_RXFE 0x010 +#define UART01x_FR_BUSY 0x008 +#define UART01x_FR_DCD 0x004 +#define UART01x_FR_DSR 0x002 +#define UART01x_FR_CTS 0x001 +#define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) + +#define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ +#define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */ +#define UART011_CR_OUT2 0x2000 /* OUT2 */ +#define UART011_CR_OUT1 0x1000 /* OUT1 */ +#define UART011_CR_RTS 0x0800 /* RTS */ +#define UART011_CR_DTR 0x0400 /* DTR */ +#define UART011_CR_RXE 0x0200 /* receive enable */ +#define UART011_CR_TXE 0x0100 /* transmit enable */ +#define UART011_CR_LBE 0x0080 /* loopback enable */ +#define UART010_CR_RTIE 0x0040 +#define UART010_CR_TIE 0x0020 +#define UART010_CR_RIE 0x0010 +#define UART010_CR_MSIE 0x0008 +#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */ +#define UART01x_CR_SIREN 0x0002 /* SIR enable */ +#define UART01x_CR_UARTEN 0x0001 /* UART enable */ + +#define UART011_LCRH_SPS 0x80 +#define UART01x_LCRH_WLEN_8 0x60 +#define UART01x_LCRH_WLEN_7 0x40 +#define UART01x_LCRH_WLEN_6 0x20 +#define UART01x_LCRH_WLEN_5 0x00 +#define UART01x_LCRH_FEN 0x10 +#define UART01x_LCRH_STP2 0x08 +#define UART01x_LCRH_EPS 0x04 +#define UART01x_LCRH_PEN 0x02 +#define UART01x_LCRH_BRK 0x01 + +#define UART010_IIR_RTIS 0x08 +#define UART010_IIR_TIS 0x04 +#define UART010_IIR_RIS 0x02 +#define UART010_IIR_MIS 0x01 + +#define UART011_IFLS_RX1_8 (0 << 3) +#define UART011_IFLS_RX2_8 (1 << 3) +#define UART011_IFLS_RX4_8 (2 << 3) +#define UART011_IFLS_RX6_8 (3 << 3) +#define UART011_IFLS_RX7_8 (4 << 3) +#define UART011_IFLS_TX1_8 (0 << 0) +#define UART011_IFLS_TX2_8 (1 << 0) +#define UART011_IFLS_TX4_8 (2 << 0) +#define UART011_IFLS_TX6_8 (3 << 0) +#define UART011_IFLS_TX7_8 (4 << 0) + +#define UART011_OEIM (1 << 10) /* overrun error interrupt mask */ +#define UART011_BEIM (1 << 9) /* break error interrupt mask */ +#define UART011_PEIM (1 << 8) /* parity error interrupt mask */ +#define UART011_FEIM (1 << 7) /* framing error interrupt mask */ +#define UART011_RTIM (1 << 6) /* receive timeout interrupt mask */ +#define UART011_TXIM (1 << 5) /* transmit interrupt mask */ +#define UART011_RXIM (1 << 4) /* receive interrupt mask */ +#define UART011_DSRMIM (1 << 3) /* DSR interrupt mask */ +#define UART011_DCDMIM (1 << 2) /* DCD interrupt mask */ +#define UART011_CTSMIM (1 << 1) /* CTS interrupt mask */ +#define UART011_RIMIM (1 << 0) /* RI interrupt mask */ + +#define UART011_OEIS (1 << 10) /* overrun error interrupt status */ +#define UART011_BEIS (1 << 9) /* break error interrupt status */ +#define UART011_PEIS (1 << 8) /* parity error interrupt status */ +#define UART011_FEIS (1 << 7) /* framing error interrupt status */ +#define UART011_RTIS (1 << 6) /* receive timeout interrupt status */ +#define UART011_TXIS (1 << 5) /* transmit interrupt status */ +#define UART011_RXIS (1 << 4) /* receive interrupt status */ +#define UART011_DSRMIS (1 << 3) /* DSR interrupt status */ +#define UART011_DCDMIS (1 << 2) /* DCD interrupt status */ +#define UART011_CTSMIS (1 << 1) /* CTS interrupt status */ +#define UART011_RIMIS (1 << 0) /* RI interrupt status */ + +#define UART011_OEIC (1 << 10) /* overrun error interrupt clear */ +#define UART011_BEIC (1 << 9) /* break error interrupt clear */ +#define UART011_PEIC (1 << 8) /* parity error interrupt clear */ +#define UART011_FEIC (1 << 7) /* framing error interrupt clear */ +#define UART011_RTIC (1 << 6) /* receive timeout interrupt clear */ +#define UART011_TXIC (1 << 5) /* transmit interrupt clear */ +#define UART011_RXIC (1 << 4) /* receive interrupt clear */ +#define UART011_DSRMIC (1 << 3) /* DSR interrupt clear */ +#define UART011_DCDMIC (1 << 2) /* DCD interrupt clear */ +#define UART011_CTSMIC (1 << 1) /* CTS interrupt clear */ +#define UART011_RIMIC (1 << 0) /* RI interrupt clear */ + +#define UART011_DMAONERR (1 << 2) /* disable dma on error */ +#define UART011_TXDMAE (1 << 1) /* enable transmit dma */ +#define UART011_RXDMAE (1 << 0) /* enable receive dma */ + +#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE) +#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS) + +#endif diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 559ead6367da..5b6cae50d0d5 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include -#include #include #include -- cgit v1.2.3 From de1d815fccee1f4766a7e56054ab0ec3f6f3a7db Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 7 Jan 2006 14:54:15 +0000 Subject: [ARM] Move AMBA bus code to drivers/amba/ Make the AMBA bus code visible to other architectures. Signed-off-by: Russell King --- arch/arm/common/Makefile | 1 - arch/arm/common/amba.c | 359 ----------------------------------------------- drivers/Makefile | 1 + drivers/amba/Makefile | 2 + drivers/amba/bus.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 362 insertions(+), 360 deletions(-) delete mode 100644 arch/arm/common/amba.c create mode 100644 drivers/amba/Makefile create mode 100644 drivers/amba/bus.c diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 2685051b3013..ec8d17c96906 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -3,7 +3,6 @@ # obj-y += rtctime.o -obj-$(CONFIG_ARM_AMBA) += amba.o obj-$(CONFIG_ARM_GIC) += gic.o obj-$(CONFIG_ICST525) += icst525.o obj-$(CONFIG_ICST307) += icst307.o diff --git a/arch/arm/common/amba.c b/arch/arm/common/amba.c deleted file mode 100644 index 1bbdd1693d57..000000000000 --- a/arch/arm/common/amba.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * linux/arch/arm/common/amba.c - * - * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define to_amba_device(d) container_of(d, struct amba_device, dev) -#define to_amba_driver(d) container_of(d, struct amba_driver, drv) - -static struct amba_id * -amba_lookup(struct amba_id *table, struct amba_device *dev) -{ - int ret = 0; - - while (table->mask) { - ret = (dev->periphid & table->mask) == table->id; - if (ret) - break; - table++; - } - - return ret ? table : NULL; -} - -static int amba_match(struct device *dev, struct device_driver *drv) -{ - struct amba_device *pcdev = to_amba_device(dev); - struct amba_driver *pcdrv = to_amba_driver(drv); - - return amba_lookup(pcdrv->id_table, pcdev) != NULL; -} - -#ifdef CONFIG_HOTPLUG -static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) -{ - struct amba_device *pcdev = to_amba_device(dev); - - if (nr_env < 2) - return -ENOMEM; - - snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid); - *envp++ = buf; - *envp++ = NULL; - return 0; -} -#else -#define amba_uevent NULL -#endif - -static int amba_suspend(struct device *dev, pm_message_t state) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - int ret = 0; - - if (dev->driver && drv->suspend) - ret = drv->suspend(to_amba_device(dev), state); - return ret; -} - -static int amba_resume(struct device *dev) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - int ret = 0; - - if (dev->driver && drv->resume) - ret = drv->resume(to_amba_device(dev)); - return ret; -} - -/* - * Primecells are part of the Advanced Microcontroller Bus Architecture, - * so we call the bus "amba". - */ -static struct bus_type amba_bustype = { - .name = "amba", - .match = amba_match, - .uevent = amba_uevent, - .suspend = amba_suspend, - .resume = amba_resume, -}; - -static int __init amba_init(void) -{ - return bus_register(&amba_bustype); -} - -postcore_initcall(amba_init); - -/* - * These are the device model conversion veneers; they convert the - * device model structures to our more specific structures. - */ -static int amba_probe(struct device *dev) -{ - struct amba_device *pcdev = to_amba_device(dev); - struct amba_driver *pcdrv = to_amba_driver(dev->driver); - struct amba_id *id; - - id = amba_lookup(pcdrv->id_table, pcdev); - - return pcdrv->probe(pcdev, id); -} - -static int amba_remove(struct device *dev) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - return drv->remove(to_amba_device(dev)); -} - -static void amba_shutdown(struct device *dev) -{ - struct amba_driver *drv = to_amba_driver(dev->driver); - drv->shutdown(to_amba_device(dev)); -} - -/** - * amba_driver_register - register an AMBA device driver - * @drv: amba device driver structure - * - * Register an AMBA device driver with the Linux device model - * core. If devices pre-exist, the drivers probe function will - * be called. - */ -int amba_driver_register(struct amba_driver *drv) -{ - drv->drv.bus = &amba_bustype; - -#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn - SETFN(probe); - SETFN(remove); - SETFN(shutdown); - - return driver_register(&drv->drv); -} - -/** - * amba_driver_unregister - remove an AMBA device driver - * @drv: AMBA device driver structure to remove - * - * Unregister an AMBA device driver from the Linux device - * model. The device model will call the drivers remove function - * for each device the device driver is currently handling. - */ -void amba_driver_unregister(struct amba_driver *drv) -{ - driver_unregister(&drv->drv); -} - - -static void amba_device_release(struct device *dev) -{ - struct amba_device *d = to_amba_device(dev); - - if (d->res.parent) - release_resource(&d->res); - kfree(d); -} - -#define amba_attr(name,fmt,arg...) \ -static ssize_t show_##name(struct device *_dev, struct device_attribute *attr, char *buf) \ -{ \ - struct amba_device *dev = to_amba_device(_dev); \ - return sprintf(buf, fmt, arg); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) - -amba_attr(id, "%08x\n", dev->periphid); -amba_attr(irq0, "%u\n", dev->irq[0]); -amba_attr(irq1, "%u\n", dev->irq[1]); -amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n", - dev->res.start, dev->res.end, dev->res.flags); - -/** - * amba_device_register - register an AMBA device - * @dev: AMBA device to register - * @parent: parent memory resource - * - * Setup the AMBA device, reading the cell ID if present. - * Claim the resource, and register the AMBA device with - * the Linux device manager. - */ -int amba_device_register(struct amba_device *dev, struct resource *parent) -{ - u32 pid, cid; - void __iomem *tmp; - int i, ret; - - dev->dev.release = amba_device_release; - dev->dev.bus = &amba_bustype; - dev->dev.dma_mask = &dev->dma_mask; - dev->res.name = dev->dev.bus_id; - - if (!dev->dev.coherent_dma_mask && dev->dma_mask) - dev_warn(&dev->dev, "coherent dma mask is unset\n"); - - ret = request_resource(parent, &dev->res); - if (ret == 0) { - tmp = ioremap(dev->res.start, SZ_4K); - if (!tmp) { - ret = -ENOMEM; - goto out; - } - - for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8); - for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8); - - iounmap(tmp); - - if (cid == 0xb105f00d) - dev->periphid = pid; - - if (dev->periphid) - ret = device_register(&dev->dev); - else - ret = -ENODEV; - - if (ret == 0) { - device_create_file(&dev->dev, &dev_attr_id); - if (dev->irq[0] != NO_IRQ) - device_create_file(&dev->dev, &dev_attr_irq0); - if (dev->irq[1] != NO_IRQ) - device_create_file(&dev->dev, &dev_attr_irq1); - device_create_file(&dev->dev, &dev_attr_resource); - } else { - out: - release_resource(&dev->res); - } - } - return ret; -} - -/** - * amba_device_unregister - unregister an AMBA device - * @dev: AMBA device to remove - * - * Remove the specified AMBA device from the Linux device - * manager. All files associated with this object will be - * destroyed, and device drivers notified that the device has - * been removed. The AMBA device's resources including - * the amba_device structure will be freed once all - * references to it have been dropped. - */ -void amba_device_unregister(struct amba_device *dev) -{ - device_unregister(&dev->dev); -} - - -struct find_data { - struct amba_device *dev; - struct device *parent; - const char *busid; - unsigned int id; - unsigned int mask; -}; - -static int amba_find_match(struct device *dev, void *data) -{ - struct find_data *d = data; - struct amba_device *pcdev = to_amba_device(dev); - int r; - - r = (pcdev->periphid & d->mask) == d->id; - if (d->parent) - r &= d->parent == dev->parent; - if (d->busid) - r &= strcmp(dev->bus_id, d->busid) == 0; - - if (r) { - get_device(dev); - d->dev = pcdev; - } - - return r; -} - -/** - * amba_find_device - locate an AMBA device given a bus id - * @busid: bus id for device (or NULL) - * @parent: parent device (or NULL) - * @id: peripheral ID (or 0) - * @mask: peripheral ID mask (or 0) - * - * Return the AMBA device corresponding to the supplied parameters. - * If no device matches, returns NULL. - * - * NOTE: When a valid device is found, its refcount is - * incremented, and must be decremented before the returned - * reference. - */ -struct amba_device * -amba_find_device(const char *busid, struct device *parent, unsigned int id, - unsigned int mask) -{ - struct find_data data; - - data.dev = NULL; - data.parent = parent; - data.busid = busid; - data.id = id; - data.mask = mask; - - bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); - - return data.dev; -} - -/** - * amba_request_regions - request all mem regions associated with device - * @dev: amba_device structure for device - * @name: name, or NULL to use driver name - */ -int amba_request_regions(struct amba_device *dev, const char *name) -{ - int ret = 0; - - if (!name) - name = dev->dev.driver->name; - - if (!request_mem_region(dev->res.start, SZ_4K, name)) - ret = -EBUSY; - - return ret; -} - -/** - * amba_release_regions - release mem regions assoicated with device - * @dev: amba_device structure for device - * - * Release regions claimed by a successful call to amba_request_regions. - */ -void amba_release_regions(struct amba_device *dev) -{ - release_mem_region(dev->res.start, SZ_4K); -} - -EXPORT_SYMBOL(amba_driver_register); -EXPORT_SYMBOL(amba_driver_unregister); -EXPORT_SYMBOL(amba_device_register); -EXPORT_SYMBOL(amba_device_unregister); -EXPORT_SYMBOL(amba_find_device); -EXPORT_SYMBOL(amba_request_regions); -EXPORT_SYMBOL(amba_release_regions); diff --git a/drivers/Makefile b/drivers/Makefile index ea410b6b7644..7fc3f0f08b29 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ACPI) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so obj-$(CONFIG_PNP) += pnp/ +obj-$(CONFIG_ARM_AMBA) += amba/ # char/ comes before serial/ etc so that the VT console is the boot-time # default. diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile new file mode 100644 index 000000000000..40fe74097be2 --- /dev/null +++ b/drivers/amba/Makefile @@ -0,0 +1,2 @@ +obj-y += bus.o + diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c new file mode 100644 index 000000000000..1bbdd1693d57 --- /dev/null +++ b/drivers/amba/bus.c @@ -0,0 +1,359 @@ +/* + * linux/arch/arm/common/amba.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define to_amba_device(d) container_of(d, struct amba_device, dev) +#define to_amba_driver(d) container_of(d, struct amba_driver, drv) + +static struct amba_id * +amba_lookup(struct amba_id *table, struct amba_device *dev) +{ + int ret = 0; + + while (table->mask) { + ret = (dev->periphid & table->mask) == table->id; + if (ret) + break; + table++; + } + + return ret ? table : NULL; +} + +static int amba_match(struct device *dev, struct device_driver *drv) +{ + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(drv); + + return amba_lookup(pcdrv->id_table, pcdev) != NULL; +} + +#ifdef CONFIG_HOTPLUG +static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz) +{ + struct amba_device *pcdev = to_amba_device(dev); + + if (nr_env < 2) + return -ENOMEM; + + snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid); + *envp++ = buf; + *envp++ = NULL; + return 0; +} +#else +#define amba_uevent NULL +#endif + +static int amba_suspend(struct device *dev, pm_message_t state) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + int ret = 0; + + if (dev->driver && drv->suspend) + ret = drv->suspend(to_amba_device(dev), state); + return ret; +} + +static int amba_resume(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + int ret = 0; + + if (dev->driver && drv->resume) + ret = drv->resume(to_amba_device(dev)); + return ret; +} + +/* + * Primecells are part of the Advanced Microcontroller Bus Architecture, + * so we call the bus "amba". + */ +static struct bus_type amba_bustype = { + .name = "amba", + .match = amba_match, + .uevent = amba_uevent, + .suspend = amba_suspend, + .resume = amba_resume, +}; + +static int __init amba_init(void) +{ + return bus_register(&amba_bustype); +} + +postcore_initcall(amba_init); + +/* + * These are the device model conversion veneers; they convert the + * device model structures to our more specific structures. + */ +static int amba_probe(struct device *dev) +{ + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(dev->driver); + struct amba_id *id; + + id = amba_lookup(pcdrv->id_table, pcdev); + + return pcdrv->probe(pcdev, id); +} + +static int amba_remove(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->remove(to_amba_device(dev)); +} + +static void amba_shutdown(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + drv->shutdown(to_amba_device(dev)); +} + +/** + * amba_driver_register - register an AMBA device driver + * @drv: amba device driver structure + * + * Register an AMBA device driver with the Linux device model + * core. If devices pre-exist, the drivers probe function will + * be called. + */ +int amba_driver_register(struct amba_driver *drv) +{ + drv->drv.bus = &amba_bustype; + +#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn + SETFN(probe); + SETFN(remove); + SETFN(shutdown); + + return driver_register(&drv->drv); +} + +/** + * amba_driver_unregister - remove an AMBA device driver + * @drv: AMBA device driver structure to remove + * + * Unregister an AMBA device driver from the Linux device + * model. The device model will call the drivers remove function + * for each device the device driver is currently handling. + */ +void amba_driver_unregister(struct amba_driver *drv) +{ + driver_unregister(&drv->drv); +} + + +static void amba_device_release(struct device *dev) +{ + struct amba_device *d = to_amba_device(dev); + + if (d->res.parent) + release_resource(&d->res); + kfree(d); +} + +#define amba_attr(name,fmt,arg...) \ +static ssize_t show_##name(struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + struct amba_device *dev = to_amba_device(_dev); \ + return sprintf(buf, fmt, arg); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +amba_attr(id, "%08x\n", dev->periphid); +amba_attr(irq0, "%u\n", dev->irq[0]); +amba_attr(irq1, "%u\n", dev->irq[1]); +amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n", + dev->res.start, dev->res.end, dev->res.flags); + +/** + * amba_device_register - register an AMBA device + * @dev: AMBA device to register + * @parent: parent memory resource + * + * Setup the AMBA device, reading the cell ID if present. + * Claim the resource, and register the AMBA device with + * the Linux device manager. + */ +int amba_device_register(struct amba_device *dev, struct resource *parent) +{ + u32 pid, cid; + void __iomem *tmp; + int i, ret; + + dev->dev.release = amba_device_release; + dev->dev.bus = &amba_bustype; + dev->dev.dma_mask = &dev->dma_mask; + dev->res.name = dev->dev.bus_id; + + if (!dev->dev.coherent_dma_mask && dev->dma_mask) + dev_warn(&dev->dev, "coherent dma mask is unset\n"); + + ret = request_resource(parent, &dev->res); + if (ret == 0) { + tmp = ioremap(dev->res.start, SZ_4K); + if (!tmp) { + ret = -ENOMEM; + goto out; + } + + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8); + for (cid = 0, i = 0; i < 4; i++) + cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8); + + iounmap(tmp); + + if (cid == 0xb105f00d) + dev->periphid = pid; + + if (dev->periphid) + ret = device_register(&dev->dev); + else + ret = -ENODEV; + + if (ret == 0) { + device_create_file(&dev->dev, &dev_attr_id); + if (dev->irq[0] != NO_IRQ) + device_create_file(&dev->dev, &dev_attr_irq0); + if (dev->irq[1] != NO_IRQ) + device_create_file(&dev->dev, &dev_attr_irq1); + device_create_file(&dev->dev, &dev_attr_resource); + } else { + out: + release_resource(&dev->res); + } + } + return ret; +} + +/** + * amba_device_unregister - unregister an AMBA device + * @dev: AMBA device to remove + * + * Remove the specified AMBA device from the Linux device + * manager. All files associated with this object will be + * destroyed, and device drivers notified that the device has + * been removed. The AMBA device's resources including + * the amba_device structure will be freed once all + * references to it have been dropped. + */ +void amba_device_unregister(struct amba_device *dev) +{ + device_unregister(&dev->dev); +} + + +struct find_data { + struct amba_device *dev; + struct device *parent; + const char *busid; + unsigned int id; + unsigned int mask; +}; + +static int amba_find_match(struct device *dev, void *data) +{ + struct find_data *d = data; + struct amba_device *pcdev = to_amba_device(dev); + int r; + + r = (pcdev->periphid & d->mask) == d->id; + if (d->parent) + r &= d->parent == dev->parent; + if (d->busid) + r &= strcmp(dev->bus_id, d->busid) == 0; + + if (r) { + get_device(dev); + d->dev = pcdev; + } + + return r; +} + +/** + * amba_find_device - locate an AMBA device given a bus id + * @busid: bus id for device (or NULL) + * @parent: parent device (or NULL) + * @id: peripheral ID (or 0) + * @mask: peripheral ID mask (or 0) + * + * Return the AMBA device corresponding to the supplied parameters. + * If no device matches, returns NULL. + * + * NOTE: When a valid device is found, its refcount is + * incremented, and must be decremented before the returned + * reference. + */ +struct amba_device * +amba_find_device(const char *busid, struct device *parent, unsigned int id, + unsigned int mask) +{ + struct find_data data; + + data.dev = NULL; + data.parent = parent; + data.busid = busid; + data.id = id; + data.mask = mask; + + bus_for_each_dev(&amba_bustype, NULL, &data, amba_find_match); + + return data.dev; +} + +/** + * amba_request_regions - request all mem regions associated with device + * @dev: amba_device structure for device + * @name: name, or NULL to use driver name + */ +int amba_request_regions(struct amba_device *dev, const char *name) +{ + int ret = 0; + + if (!name) + name = dev->dev.driver->name; + + if (!request_mem_region(dev->res.start, SZ_4K, name)) + ret = -EBUSY; + + return ret; +} + +/** + * amba_release_regions - release mem regions assoicated with device + * @dev: amba_device structure for device + * + * Release regions claimed by a successful call to amba_request_regions. + */ +void amba_release_regions(struct amba_device *dev) +{ + release_mem_region(dev->res.start, SZ_4K); +} + +EXPORT_SYMBOL(amba_driver_register); +EXPORT_SYMBOL(amba_driver_unregister); +EXPORT_SYMBOL(amba_device_register); +EXPORT_SYMBOL(amba_device_unregister); +EXPORT_SYMBOL(amba_find_device); +EXPORT_SYMBOL(amba_request_regions); +EXPORT_SYMBOL(amba_release_regions); -- cgit v1.2.3 From f8ce25476d5f12ffa29b885e49c38cd95053437e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 7 Jan 2006 16:15:52 +0000 Subject: [ARM] Move asm/hardware/clock.h to linux/clk.h This is needs to be visible to other architectures using the AMBA bus and peripherals. Signed-off-by: Russell King --- arch/arm/mach-aaec2000/clock.c | 2 +- arch/arm/mach-integrator/clock.c | 2 +- arch/arm/mach-omap1/board-palmte.c | 2 +- arch/arm/mach-omap1/clock.c | 2 +- arch/arm/mach-omap1/serial.c | 2 +- arch/arm/mach-omap2/clock.c | 2 +- arch/arm/mach-omap2/serial.c | 2 +- arch/arm/mach-omap2/timer-gp.c | 3 +- arch/arm/mach-realview/clock.c | 2 +- arch/arm/mach-s3c2410/clock.c | 3 +- arch/arm/mach-s3c2410/s3c2440-clock.c | 3 +- arch/arm/mach-s3c2410/s3c2440.c | 2 +- arch/arm/mach-s3c2410/time.c | 2 +- arch/arm/mach-versatile/clock.c | 2 +- arch/arm/plat-omap/clock.c | 2 +- arch/arm/plat-omap/common.c | 2 +- arch/arm/plat-omap/cpu-omap.c | 3 +- arch/arm/plat-omap/gpio.c | 2 +- arch/arm/plat-omap/mcbsp.c | 3 +- arch/arm/plat-omap/ocpi.c | 2 +- drivers/char/s3c2410-rtc.c | 2 +- drivers/char/watchdog/s3c2410_wdt.c | 2 +- drivers/i2c/busses/i2c-s3c2410.c | 2 +- drivers/input/serio/ambakmi.c | 2 +- drivers/mmc/mmci.c | 2 +- drivers/mtd/nand/s3c2410.c | 2 +- drivers/serial/amba-pl011.c | 2 +- drivers/serial/s3c2410.c | 2 +- drivers/usb/host/ohci-omap.c | 2 +- drivers/usb/host/ohci-s3c2410.c | 2 +- drivers/video/amba-clcd.c | 2 +- drivers/video/s3c2410fb.c | 2 +- include/asm-arm/arch-omap/system.h | 3 +- include/asm-arm/hardware/clock.h | 124 ---------------------------------- include/linux/clk.h | 124 ++++++++++++++++++++++++++++++++++ 35 files changed, 159 insertions(+), 161 deletions(-) delete mode 100644 include/asm-arm/hardware/clock.h create mode 100644 include/linux/clk.h diff --git a/arch/arm/mach-aaec2000/clock.c b/arch/arm/mach-aaec2000/clock.c index 828208348b76..1c84c60941e1 100644 --- a/arch/arm/mach-aaec2000/clock.c +++ b/arch/arm/mach-aaec2000/clock.c @@ -15,9 +15,9 @@ #include #include #include +#include #include -#include #include "clock.h" diff --git a/arch/arm/mach-integrator/clock.c b/arch/arm/mach-integrator/clock.c index bbfe46cd91fe..40684e01e865 100644 --- a/arch/arm/mach-integrator/clock.c +++ b/arch/arm/mach-integrator/clock.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include #include #include "clock.h" diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c index 540b20d78cca..5c975eb5c34b 100644 --- a/arch/arm/mach-omap1/board-palmte.c +++ b/arch/arm/mach-omap1/board-palmte.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,6 @@ #include #include #include -#include static void __init omap_generic_init_irq(void) { diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 4277eee44ed5..9d862f86bba6 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -16,9 +16,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 6810cfb84462..fcfb81d13cfe 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -17,10 +17,10 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 85818d9f2635..5407b9549150 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -22,10 +22,10 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index f4df04fe1dd8..e1bd46a96e11 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -16,9 +16,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 9ec11443200f..23d36b1c40fe 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -21,10 +21,11 @@ #include #include #include +#include + #include #include #include -#include #define OMAP2_GP_TIMER1_BASE 0x48028000 #define OMAP2_GP_TIMER2_BASE 0x4802a000 diff --git a/arch/arm/mach-realview/clock.c b/arch/arm/mach-realview/clock.c index 331e1b483aa7..ec3f7e798623 100644 --- a/arch/arm/mach-realview/clock.c +++ b/arch/arm/mach-realview/clock.c @@ -13,9 +13,9 @@ #include #include #include +#include #include -#include #include #include "clock.h" diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index 77f321fac281..5830ae3ddd19 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -34,16 +34,15 @@ #include #include #include - #include #include +#include #include #include #include #include -#include #include #include "clock.h" diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c index c67e0979aec3..b557a2be8a01 100644 --- a/arch/arm/mach-s3c2410/s3c2440-clock.c +++ b/arch/arm/mach-s3c2410/s3c2440-clock.c @@ -29,16 +29,15 @@ #include #include #include - #include #include +#include #include #include #include #include -#include #include #include "clock.h" diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index 4d63e7133b48..b7fe6d9453fb 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c index 9acda44b25a6..10a2976aefdd 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/mach-s3c2410/time.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include "clock.h" #include "cpu.h" diff --git a/arch/arm/mach-versatile/clock.c b/arch/arm/mach-versatile/clock.c index ada3142da8dc..dcf10014f5cd 100644 --- a/arch/arm/mach-versatile/clock.c +++ b/arch/arm/mach-versatile/clock.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include #include #include "clock.h" diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 7ce39b986e23..84fd65656fcf 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -19,10 +19,10 @@ #include #include #include +#include #include #include -#include #include diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index ccdb452630cf..adffc5a859ee 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -18,12 +18,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index fd894bb00107..98edc9fdd6d1 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -19,13 +19,12 @@ #include #include #include +#include #include #include #include -#include - /* TODO: Add support for SDRAM timing changes */ int omap_verify_speed(struct cpufreq_policy *policy) diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 76f721d85137..ca3681a824ac 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -19,9 +19,9 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index ea9475c86656..be0e0f32a598 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -30,8 +31,6 @@ #include #include -#include - #ifdef CONFIG_MCBSP_DEBUG #define DBG(x...) printk(x) #else diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c index b86148227480..e40fcc8b43d4 100644 --- a/arch/arm/plat-omap/ocpi.c +++ b/arch/arm/plat-omap/ocpi.c @@ -31,9 +31,9 @@ #include #include #include +#include #include -#include #include #define OCPI_BASE 0xfffec320 diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index 3df7a574267b..2e308657f6f6 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,6 @@ #include -#include #include /* need this for the RTC_AF definitions */ diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 621e8a99e733..9dc54736e4eb 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -46,12 +46,12 @@ #include #include #include +#include #include #include #include -#include #undef S3C24XX_VA_WATCHDOG #define S3C24XX_VA_WATCHDOG (0) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 2a2f86d8c2d8..f7d40f8e5f5c 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -34,12 +34,12 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index cbab5d26377b..3df5eedf8f31 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -21,10 +21,10 @@ #include #include #include +#include #include #include -#include #define KMI_BASE (kmi->base) diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 57375bc12372..a0cd916ab792 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -20,12 +20,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include "mmci.h" diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b796a9a6b924..5b55599739f3 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -60,7 +61,6 @@ #include #include -#include #include #include diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 4ae4dff59795..129670556162 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -49,10 +49,10 @@ #include #include #include +#include #include #include -#include #define UART_NR 14 diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index eb47f5b71aeb..fe83ce6fef52 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -72,12 +72,12 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index c9e29d808711..3785b3f7df1b 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -17,6 +17,7 @@ #include /* SA_INTERRUPT */ #include #include +#include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include /* OMAP-1510 OHCI has its own MMU for DMA */ diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index add198a4be79..372527a83593 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -20,9 +20,9 @@ */ #include +#include #include -#include #include #define valid_port(idx) ((idx) == 1 || (idx) == 2) diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 3358a1429651..0da4083ba908 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -23,9 +23,9 @@ #include #include #include +#include #include -#include #define to_clcd(info) container_of(info, struct clcd_fb, fb) diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index d9c08cc7ac44..fe99d17a21d7 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -96,7 +97,6 @@ #include #include #include -#include #ifdef CONFIG_PM #include diff --git a/include/asm-arm/arch-omap/system.h b/include/asm-arm/arch-omap/system.h index 9af415d2944a..6724a81bd10b 100644 --- a/include/asm-arm/arch-omap/system.h +++ b/include/asm-arm/arch-omap/system.h @@ -5,8 +5,9 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H #include +#include + #include -#include #include #include diff --git a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h deleted file mode 100644 index 69f33215e437..000000000000 --- a/include/asm-arm/hardware/clock.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * linux/include/asm-arm/hardware/clock.h - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef ASMARM_CLOCK_H -#define ASMARM_CLOCK_H - -struct device; - -/* - * The base API. - */ - - -/* - * struct clk - an machine class defined object / cookie. - */ -struct clk; - -/** - * clk_get - lookup and obtain a reference to a clock producer. - * @dev: device for clock "consumer" - * @id: clock comsumer ID - * - * Returns a struct clk corresponding to the clock producer, or - * valid IS_ERR() condition containing errno. The implementation - * uses @dev and @id to determine the clock consumer, and thereby - * the clock producer. (IOW, @id may be identical strings, but - * clk_get may return different clock producers depending on @dev.) - * - * Drivers must assume that the clock source is not enabled. - */ -struct clk *clk_get(struct device *dev, const char *id); - -/** - * clk_enable - inform the system when the clock source should be running. - * @clk: clock source - * - * If the clock can not be enabled/disabled, this should return success. - * - * Returns success (0) or negative errno. - */ -int clk_enable(struct clk *clk); - -/** - * clk_disable - inform the system when the clock source is no longer required. - * @clk: clock source - * - * Inform the system that a clock source is no longer required by - * a driver and may be shut down. - * - * Implementation detail: if the clock source is shared between - * multiple drivers, clk_enable() calls must be balanced by the - * same number of clk_disable() calls for the clock source to be - * disabled. - */ -void clk_disable(struct clk *clk); - -/** - * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. - * This is only valid once the clock source has been enabled. - * @clk: clock source - */ -unsigned long clk_get_rate(struct clk *clk); - -/** - * clk_put - "free" the clock source - * @clk: clock source - * - * Note: drivers must ensure that all clk_enable calls made on this - * clock source are balanced by clk_disable calls prior to calling - * this function. - */ -void clk_put(struct clk *clk); - - -/* - * The remaining APIs are optional for machine class support. - */ - - -/** - * clk_round_rate - adjust a rate to the exact rate a clock can provide - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns rounded clock rate in Hz, or negative errno. - */ -long clk_round_rate(struct clk *clk, unsigned long rate); - -/** - * clk_set_rate - set the clock rate for a clock source - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns success (0) or negative errno. - */ -int clk_set_rate(struct clk *clk, unsigned long rate); - -/** - * clk_set_parent - set the parent clock source for this clock - * @clk: clock source - * @parent: parent clock source - * - * Returns success (0) or negative errno. - */ -int clk_set_parent(struct clk *clk, struct clk *parent); - -/** - * clk_get_parent - get the parent clock source for this clock - * @clk: clock source - * - * Returns struct clk corresponding to parent clock source, or - * valid IS_ERR() condition containing errno. - */ -struct clk *clk_get_parent(struct clk *clk); - -#endif diff --git a/include/linux/clk.h b/include/linux/clk.h new file mode 100644 index 000000000000..12848f81bb37 --- /dev/null +++ b/include/linux/clk.h @@ -0,0 +1,124 @@ +/* + * linux/include/linux/clk.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef ASMARM_CLOCK_H +#define ASMARM_CLOCK_H + +struct device; + +/* + * The base API. + */ + + +/* + * struct clk - an machine class defined object / cookie. + */ +struct clk; + +/** + * clk_get - lookup and obtain a reference to a clock producer. + * @dev: device for clock "consumer" + * @id: clock comsumer ID + * + * Returns a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. (IOW, @id may be identical strings, but + * clk_get may return different clock producers depending on @dev.) + * + * Drivers must assume that the clock source is not enabled. + */ +struct clk *clk_get(struct device *dev, const char *id); + +/** + * clk_enable - inform the system when the clock source should be running. + * @clk: clock source + * + * If the clock can not be enabled/disabled, this should return success. + * + * Returns success (0) or negative errno. + */ +int clk_enable(struct clk *clk); + +/** + * clk_disable - inform the system when the clock source is no longer required. + * @clk: clock source + * + * Inform the system that a clock source is no longer required by + * a driver and may be shut down. + * + * Implementation detail: if the clock source is shared between + * multiple drivers, clk_enable() calls must be balanced by the + * same number of clk_disable() calls for the clock source to be + * disabled. + */ +void clk_disable(struct clk *clk); + +/** + * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. + * This is only valid once the clock source has been enabled. + * @clk: clock source + */ +unsigned long clk_get_rate(struct clk *clk); + +/** + * clk_put - "free" the clock source + * @clk: clock source + * + * Note: drivers must ensure that all clk_enable calls made on this + * clock source are balanced by clk_disable calls prior to calling + * this function. + */ +void clk_put(struct clk *clk); + + +/* + * The remaining APIs are optional for machine class support. + */ + + +/** + * clk_round_rate - adjust a rate to the exact rate a clock can provide + * @clk: clock source + * @rate: desired clock rate in Hz + * + * Returns rounded clock rate in Hz, or negative errno. + */ +long clk_round_rate(struct clk *clk, unsigned long rate); + +/** + * clk_set_rate - set the clock rate for a clock source + * @clk: clock source + * @rate: desired clock rate in Hz + * + * Returns success (0) or negative errno. + */ +int clk_set_rate(struct clk *clk, unsigned long rate); + +/** + * clk_set_parent - set the parent clock source for this clock + * @clk: clock source + * @parent: parent clock source + * + * Returns success (0) or negative errno. + */ +int clk_set_parent(struct clk *clk, struct clk *parent); + +/** + * clk_get_parent - get the parent clock source for this clock + * @clk: clock source + * + * Returns struct clk corresponding to parent clock source, or + * valid IS_ERR() condition containing errno. + */ +struct clk *clk_get_parent(struct clk *clk); + +#endif -- cgit v1.2.3 From 736ce43295682d060f2b93624b4a339f9af6aab1 Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Sat, 7 Jan 2006 11:35:05 -0500 Subject: Input: ibmasm - convert to dynamic input_dev allocation Update the ibmasm driver to use the dynamic allocation of input_dev structs to work with the sysfs subsystem. Vojtech: Fixed some problems/bugs in the patch. Dmitry: Fixed some more. Signed-off-by: Vernon Mauery Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/misc/ibmasm/ibmasm.h | 6 ++-- drivers/misc/ibmasm/remote.c | 76 ++++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index d7e20a34f88d..1cef2387fa65 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -141,8 +141,8 @@ struct reverse_heartbeat { }; struct ibmasm_remote { - struct input_dev keybd_dev; - struct input_dev mouse_dev; + struct input_dev *keybd_dev; + struct input_dev *mouse_dev; }; struct service_processor { @@ -157,7 +157,7 @@ struct service_processor { char dirname[IBMASM_NAME_SIZE]; char devname[IBMASM_NAME_SIZE]; unsigned int number; - struct ibmasm_remote *remote; + struct ibmasm_remote remote; int serial_line; struct device *dev; }; diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c index d3c48d23ee51..1abd0c58ae27 100644 --- a/drivers/misc/ibmasm/remote.c +++ b/drivers/misc/ibmasm/remote.c @@ -203,9 +203,9 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp, print_input(&input); if (input.type == INPUT_TYPE_MOUSE) { - send_mouse_event(&sp->remote->mouse_dev, regs, &input); + send_mouse_event(sp->remote.mouse_dev, regs, &input); } else if (input.type == INPUT_TYPE_KEYBOARD) { - send_keyboard_event(&sp->remote->keybd_dev, regs, &input); + send_keyboard_event(sp->remote.keybd_dev, regs, &input); } else break; @@ -217,56 +217,70 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp, int ibmasm_init_remote_input_dev(struct service_processor *sp) { /* set up the mouse input device */ - struct ibmasm_remote *remote; + struct input_dev *mouse_dev, *keybd_dev; struct pci_dev *pdev = to_pci_dev(sp->dev); + int error = -ENOMEM; int i; - sp->remote = remote = kmalloc(sizeof(*remote), GFP_KERNEL); - if (!remote) - return -ENOMEM; + sp->remote.mouse_dev = mouse_dev = input_allocate_device(); + sp->remote.keybd_dev = keybd_dev = input_allocate_device(); - memset(remote, 0, sizeof(*remote)); + if (!mouse_dev || !keybd_dev) + goto err_free_devices; - remote->mouse_dev.private = remote; - init_input_dev(&remote->mouse_dev); - remote->mouse_dev.id.vendor = pdev->vendor; - remote->mouse_dev.id.product = pdev->device; - remote->mouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - remote->mouse_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | + mouse_dev->id.bustype = BUS_PCI; + mouse_dev->id.vendor = pdev->vendor; + mouse_dev->id.product = pdev->device; + mouse_dev->id.version = 1; + mouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + mouse_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); - set_bit(BTN_TOUCH, remote->mouse_dev.keybit); - remote->mouse_dev.name = remote_mouse_name; - input_set_abs_params(&remote->mouse_dev, ABS_X, 0, xmax, 0, 0); - input_set_abs_params(&remote->mouse_dev, ABS_Y, 0, ymax, 0, 0); + set_bit(BTN_TOUCH, mouse_dev->keybit); + mouse_dev->name = remote_mouse_name; + input_set_abs_params(mouse_dev, ABS_X, 0, xmax, 0, 0); + input_set_abs_params(mouse_dev, ABS_Y, 0, ymax, 0, 0); - remote->keybd_dev.private = remote; - init_input_dev(&remote->keybd_dev); - remote->keybd_dev.id.vendor = pdev->vendor; - remote->keybd_dev.id.product = pdev->device; - remote->keybd_dev.evbit[0] = BIT(EV_KEY); - remote->keybd_dev.name = remote_keybd_name; + mouse_dev->id.bustype = BUS_PCI; + keybd_dev->id.vendor = pdev->vendor; + keybd_dev->id.product = pdev->device; + mouse_dev->id.version = 2; + keybd_dev->evbit[0] = BIT(EV_KEY); + keybd_dev->name = remote_keybd_name; - for (i=0; ikeybd_dev.keybit); + set_bit(xlate_high[i], keybd_dev->keybit); if (xlate[i]) - set_bit(xlate[i], remote->keybd_dev.keybit); + set_bit(xlate[i], keybd_dev->keybit); } - input_register_device(&remote->mouse_dev); - input_register_device(&remote->keybd_dev); + error = input_register_device(mouse_dev); + if (error) + goto err_free_devices; + + error = input_register_device(keybd_dev); + if (error) + goto err_unregister_mouse_dev; + enable_mouse_interrupts(sp); printk(KERN_INFO "ibmasm remote responding to events on RSA card %d\n", sp->number); return 0; + + err_unregister_mouse_dev: + input_unregister_device(mouse_dev); + err_free_devices: + input_free_device(mouse_dev); + input_free_device(keybd_dev); + + return error; } void ibmasm_free_remote_input_dev(struct service_processor *sp) { disable_mouse_interrupts(sp); - input_unregister_device(&sp->remote->keybd_dev); - input_unregister_device(&sp->remote->mouse_dev); - kfree(sp->remote); + input_unregister_device(sp->remote.mouse_dev); + input_unregister_device(sp->remote.keybd_dev); } -- cgit v1.2.3 From fe5dd7c73d328b255286b6b65ca19dd34447f709 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 7 Jan 2006 16:55:50 +0000 Subject: [ARM] byteorder.h needs linux/compiler.h Signed-off-by: Russell King --- include/asm-arm/byteorder.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/byteorder.h b/include/asm-arm/byteorder.h index af42f449b9a6..741f5bc5d016 100644 --- a/include/asm-arm/byteorder.h +++ b/include/asm-arm/byteorder.h @@ -15,6 +15,7 @@ #ifndef __ASM_ARM_BYTEORDER_H #define __ASM_ARM_BYTEORDER_H +#include #include static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) -- cgit v1.2.3 From d354d9afe923eb08f7ee89128b38ddb6415de01d Mon Sep 17 00:00:00 2001 From: Knut Petersen Date: Sat, 7 Jan 2006 10:22:04 +0100 Subject: [PATCH] fbcon: don´t call set_par() in fbcon_init() if vc_mode == KD_GRAPHICS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing prevents a user to modprobe a framebuffer driver from e.g. the xterm prompt. As a result, the set_par() function of the driver will be called from fbcon_init(). This is fatal as a lot of X / framebuffer combinations are unable to recover from set_par() reprogramming the graphics controller in KD_GRAPHICS mode. It is also unnecessary as the set_par() function will be called during a switch to KD_TEXT anyway. Because of this no side effects are possible. Signed-off-by: Knut Petersen Signed-off-by: Linus Torvalds --- drivers/video/console/fbcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 3660e51b2612..50e4c4eb491f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1110,7 +1110,7 @@ static void fbcon_init(struct vc_data *vc, int init) * * We need to do it in fbcon_init() to prevent screen corruption. */ - if (CON_IS_VISIBLE(vc)) { + if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) info->fbops->fb_set_par(info); -- cgit v1.2.3 From aa0e4e4aea8d9e0a559a884336d728f0263063e0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 Jan 2006 22:55:39 -0800 Subject: [DCCP]: ipv6.c needs net/ip6_checksum.c Reported by Dave Jones. Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index c609dc78f487..683250a05f58 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "dccp.h" -- cgit v1.2.3 From ee2e6841b934d76cb944a3390bbea84da777d4fa Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 6 Jan 2006 22:59:43 -0800 Subject: [XFRM]: Fix sparse warning. security/selinux/xfrm.c:155:10: warning: Using plain integer as NULL pointer Signed-off-by: Luiz Capitulino Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- security/selinux/xfrm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 5b7776504e4c..b2af7ca496c1 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -146,7 +146,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us return rc; out: - *ctxp = 0; + *ctxp = NULL; kfree(ctx); return rc; } -- cgit v1.2.3 From 16a6677fdf1d1194f688f8291b06fbaff248c353 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:01:48 -0800 Subject: [XFRM]: Netfilter IPsec output hooks Call netfilter hooks before IPsec transforms. Packets visit the FORWARD/LOCAL_OUT and POST_ROUTING hook before the first encapsulation and the LOCAL_OUT and POST_ROUTING hook before each following tunnel mode transform. Patch from Herbert Xu : Move the loop from dst_output into xfrm4_output/xfrm6_output since they're the only ones who need to it. xfrm{4,6}_output_one() processes the first SA all subsequent transport mode SAs and is called in a loop that calls the netfilter hooks between each two calls. In order to avoid the tail call issue, I've added the inline function nf_hook which is nf_hook_slow plus the empty list check. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter.h | 61 +++++++++++++++++++++++--------------- include/net/dst.h | 11 +------ net/ipv4/xfrm4_output.c | 71 +++++++++++++++++++++++++++++++++----------- net/ipv6/xfrm6_output.c | 75 +++++++++++++++++++++++++++++++++++------------ 4 files changed, 148 insertions(+), 70 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index be365e70ee99..79bb977afeac 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -168,6 +168,37 @@ void nf_log_packet(int pf, const struct net_device *out, struct nf_loginfo *li, const char *fmt, ...); + +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb, + struct net_device *indev, struct net_device *outdev, + int (*okfn)(struct sk_buff *), int thresh); + +/** + * nf_hook_thresh - call a netfilter hook + * + * Returns 1 if the hook has allowed the packet to pass. The function + * okfn must be invoked by the caller in this case. Any other return + * value indicates the packet has been consumed by the hook. + */ +static inline int nf_hook_thresh(int pf, unsigned int hook, + struct sk_buff **pskb, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *), int thresh) +{ +#ifndef CONFIG_NETFILTER_DEBUG + if (list_empty(&nf_hooks[pf][hook])) + return 1; +#endif + return nf_hook_slow(pf, hook, pskb, indev, outdev, okfn, thresh); +} + +static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb, + struct net_device *indev, struct net_device *outdev, + int (*okfn)(struct sk_buff *)) +{ + return nf_hook_thresh(pf, hook, pskb, indev, outdev, okfn, INT_MIN); +} /* Activate hook; either okfn or kfree_skb called, unless a hook returns NF_STOLEN (in which case, it's up to the hook to deal with @@ -188,35 +219,17 @@ void nf_log_packet(int pf, /* This is gross, but inline doesn't cut it for avoiding the function call in fast path: gcc doesn't inline (needs value tracking?). --RR */ -#ifdef CONFIG_NETFILTER_DEBUG -#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ -({int __ret; \ -if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \ - __ret = (okfn)(skb); \ -__ret;}) -#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \ -({int __ret; \ -if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1) \ - __ret = (okfn)(skb); \ -__ret;}) -#else -#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ -({int __ret; \ -if (list_empty(&nf_hooks[pf][hook]) || \ - (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \ - __ret = (okfn)(skb); \ -__ret;}) + +/* HX: It's slightly less gross now. */ + #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \ ({int __ret; \ -if (list_empty(&nf_hooks[pf][hook]) || \ - (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1) \ +if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)\ __ret = (okfn)(skb); \ __ret;}) -#endif -int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb, - struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *), int thresh); +#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ + NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN) /* Call setsockopt() */ int nf_setsockopt(struct sock *sk, int pf, int optval, char __user *opt, diff --git a/include/net/dst.h b/include/net/dst.h index bee8b84d329d..5161e89017f9 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -225,16 +225,7 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout) /* Output packet to network from transport. */ static inline int dst_output(struct sk_buff *skb) { - int err; - - for (;;) { - err = skb->dst->output(skb); - - if (likely(err == 0)) - return err; - if (unlikely(err != NET_XMIT_BYPASS)) - return err; - } + return skb->dst->output(skb); } /* Input packet from network to transport. */ diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 66620a95942a..51fabb8f7c54 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -8,8 +8,10 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include +#include #include #include #include @@ -95,7 +97,7 @@ out: return ret; } -int xfrm4_output(struct sk_buff *skb) +static int xfrm4_output_one(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; @@ -113,27 +115,32 @@ int xfrm4_output(struct sk_buff *skb) goto error_nolock; } - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, skb); - if (err) - goto error; + do { + spin_lock_bh(&x->lock); + err = xfrm_state_check(x, skb); + if (err) + goto error; - xfrm4_encap(skb); + xfrm4_encap(skb); - err = x->type->output(x, skb); - if (err) - goto error; + err = x->type->output(x, skb); + if (err) + goto error; - x->curlft.bytes += skb->len; - x->curlft.packets++; + x->curlft.bytes += skb->len; + x->curlft.packets++; - spin_unlock_bh(&x->lock); + spin_unlock_bh(&x->lock); - if (!(skb->dst = dst_pop(dst))) { - err = -EHOSTUNREACH; - goto error_nolock; - } - err = NET_XMIT_BYPASS; + if (!(skb->dst = dst_pop(dst))) { + err = -EHOSTUNREACH; + goto error_nolock; + } + dst = skb->dst; + x = dst->xfrm; + } while (x && !x->props.mode); + + err = 0; out_exit: return err; @@ -143,3 +150,33 @@ error_nolock: kfree_skb(skb); goto out_exit; } + +static int xfrm4_output_finish(struct sk_buff *skb) +{ + int err; + + while (likely((err = xfrm4_output_one(skb)) == 0)) { + nf_reset(skb); + + err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL, + skb->dst->dev, dst_output); + if (unlikely(err != 1)) + break; + + if (!skb->dst->xfrm) + return dst_output(skb); + + err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL, + skb->dst->dev, xfrm4_output_finish); + if (unlikely(err != 1)) + break; + } + + return err; +} + +int xfrm4_output(struct sk_buff *skb) +{ + return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, + xfrm4_output_finish); +} diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 6b9867717d11..fc0ea38953c4 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -9,9 +9,11 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include +#include #include #include #include @@ -92,7 +94,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) return ret; } -int xfrm6_output(struct sk_buff *skb) +static int xfrm6_output_one(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; @@ -110,29 +112,34 @@ int xfrm6_output(struct sk_buff *skb) goto error_nolock; } - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, skb); - if (err) - goto error; + do { + spin_lock_bh(&x->lock); + err = xfrm_state_check(x, skb); + if (err) + goto error; - xfrm6_encap(skb); + xfrm6_encap(skb); - err = x->type->output(x, skb); - if (err) - goto error; + err = x->type->output(x, skb); + if (err) + goto error; - x->curlft.bytes += skb->len; - x->curlft.packets++; + x->curlft.bytes += skb->len; + x->curlft.packets++; - spin_unlock_bh(&x->lock); + spin_unlock_bh(&x->lock); - skb->nh.raw = skb->data; - - if (!(skb->dst = dst_pop(dst))) { - err = -EHOSTUNREACH; - goto error_nolock; - } - err = NET_XMIT_BYPASS; + skb->nh.raw = skb->data; + + if (!(skb->dst = dst_pop(dst))) { + err = -EHOSTUNREACH; + goto error_nolock; + } + dst = skb->dst; + x = dst->xfrm; + } while (x && !x->props.mode); + + err = 0; out_exit: return err; @@ -142,3 +149,33 @@ error_nolock: kfree_skb(skb); goto out_exit; } + +static int xfrm6_output_finish(struct sk_buff *skb) +{ + int err; + + while (likely((err = xfrm6_output_one(skb)) == 0)) { + nf_reset(skb); + + err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, &skb, NULL, + skb->dst->dev, dst_output); + if (unlikely(err != 1)) + break; + + if (!skb->dst->xfrm) + return dst_output(skb); + + err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL, + skb->dst->dev, xfrm6_output_finish); + if (unlikely(err != 1)) + break; + } + + return err; +} + +int xfrm6_output(struct sk_buff *skb) +{ + return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev, + xfrm6_output_finish); +} -- cgit v1.2.3 From 951dbc8ac714b04c36296b8b5c36c8e036ce433f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:02:34 -0800 Subject: [IPV6]: Move nextheader offset to the IP6CB Move nextheader offset to the IP6CB to make it possible to pass a packet to ip6_input_finish multiple times and have it skip already parsed headers. As a nice side effect this gets rid of the manual hopopts skipping in ip6_input_finish. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/ipv6.h | 1 + include/net/protocol.h | 2 +- include/net/xfrm.h | 6 +++--- net/dccp/ipv6.c | 2 +- net/ipv6/exthdrs.c | 19 ++++++++++++------- net/ipv6/icmp.c | 4 ++-- net/ipv6/ip6_input.c | 21 ++++++--------------- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/reassembly.c | 11 +++++------ net/ipv6/tcp_ipv6.c | 2 +- net/ipv6/udp.c | 2 +- net/ipv6/xfrm6_input.c | 8 ++++---- net/ipv6/xfrm6_tunnel.c | 6 +++--- net/sctp/ipv6.c | 2 +- 14 files changed, 42 insertions(+), 46 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 93bbed5c6cf4..5cfc71529595 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -191,6 +191,7 @@ struct inet6_skb_parm { __u16 srcrt; __u16 dst1; __u16 lastopt; + __u32 nhoff; }; #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) diff --git a/include/net/protocol.h b/include/net/protocol.h index 63f7db99c2a6..6dc5970612d7 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -43,7 +43,7 @@ struct net_protocol { #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) struct inet6_protocol { - int (*handler)(struct sk_buff **skb, unsigned int *nhoffp); + int (*handler)(struct sk_buff **skb); void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 07d7b50cdd76..297d09d28fe4 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -831,7 +831,7 @@ struct xfrm_tunnel { }; struct xfrm6_tunnel { - int (*handler)(struct sk_buff **pskb, unsigned int *nhoffp); + int (*handler)(struct sk_buff **pskb); void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); }; @@ -868,8 +868,8 @@ extern int xfrm4_rcv(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); -extern int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi); -extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); +extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi); +extern int xfrm6_rcv(struct sk_buff **pskb); extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 683250a05f58..df074259f9c3 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1029,7 +1029,7 @@ discard: return 0; } -static int dccp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int dccp_v6_rcv(struct sk_buff **pskb) { const struct dccp_hdr *dh; struct sk_buff *skb = *pskb; diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 113374dc342c..2a1e7e45b890 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -152,7 +152,7 @@ static struct tlvtype_proc tlvprocdestopt_lst[] = { {-1, NULL} }; -static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) +static int ipv6_destopt_rcv(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; struct inet6_skb_parm *opt = IP6CB(skb); @@ -169,7 +169,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp) if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { skb->h.raw += ((skb->h.raw[1]+1)<<3); - *nhoffp = opt->dst1; + opt->nhoff = opt->dst1; return 1; } @@ -192,7 +192,7 @@ void __init ipv6_destopt_init(void) NONE header. No data in packet. ********************************/ -static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp) +static int ipv6_nodata_rcv(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; @@ -215,7 +215,7 @@ void __init ipv6_nodata_init(void) Routing header. ********************************/ -static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) +static int ipv6_rthdr_rcv(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; struct inet6_skb_parm *opt = IP6CB(skb); @@ -249,7 +249,7 @@ looped_back: skb->h.raw += (hdr->hdrlen + 1) << 3; opt->dst0 = opt->dst1; opt->dst1 = 0; - *nhoffp = (&hdr->nexthdr) - skb->nh.raw; + opt->nhoff = (&hdr->nexthdr) - skb->nh.raw; return 1; } @@ -487,9 +487,14 @@ static struct tlvtype_proc tlvprochopopt_lst[] = { int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff) { - IP6CB(skb)->hop = sizeof(struct ipv6hdr); - if (ip6_parse_tlv(tlvprochopopt_lst, skb)) + struct inet6_skb_parm *opt = IP6CB(skb); + + opt->hop = sizeof(struct ipv6hdr); + if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { + skb->h.raw += (skb->h.raw[1]+1)<<3; + opt->nhoff = sizeof(struct ipv6hdr); return sizeof(struct ipv6hdr); + } return -1; } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 6ec6a2b549bb..53c81fcd20ba 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -79,7 +79,7 @@ DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly; static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL; #define icmpv6_socket __get_cpu_var(__icmpv6_socket) -static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); +static int icmpv6_rcv(struct sk_buff **pskb); static struct inet6_protocol icmpv6_protocol = { .handler = icmpv6_rcv, @@ -581,7 +581,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) * Handle icmp messages */ -static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int icmpv6_rcv(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct net_device *dev = skb->dev; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index a6026d2787d2..13d724150f33 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -97,6 +97,9 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (hdr->version != 6) goto err; + skb->h.raw = (u8 *)(hdr + 1); + IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); + pkt_len = ntohs(hdr->payload_len); /* pkt_len may be zero if Jumbo payload option is present */ @@ -111,8 +114,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt } if (hdr->nexthdr == NEXTHDR_HOP) { - skb->h.raw = (u8*)(hdr+1); - if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) { + if (ipv6_parse_hopopts(skb, IP6CB(skb)->nhoff) < 0) { IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); return 0; } @@ -143,26 +145,15 @@ static inline int ip6_input_finish(struct sk_buff *skb) int nexthdr; u8 hash; - skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr); - /* * Parse extension headers */ - nexthdr = skb->nh.ipv6h->nexthdr; - nhoff = offsetof(struct ipv6hdr, nexthdr); - - /* Skip hop-by-hop options, they are already parsed. */ - if (nexthdr == NEXTHDR_HOP) { - nhoff = sizeof(struct ipv6hdr); - nexthdr = skb->h.raw[0]; - skb->h.raw += (skb->h.raw[1]+1)<<3; - } - rcu_read_lock(); resubmit: if (!pskb_pull(skb, skb->h.raw - skb->data)) goto discard; + nhoff = IP6CB(skb)->nhoff; nexthdr = skb->nh.raw[nhoff]; raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]); @@ -194,7 +185,7 @@ resubmit: !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard; - ret = ipprot->handler(&skb, &nhoff); + ret = ipprot->handler(&skb); if (ret > 0) goto resubmit; else if (ret == 0) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index e315d0f80af1..f079621c8b67 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -510,7 +510,7 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, **/ static int -ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +ip6ip6_rcv(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct ipv6hdr *ipv6h; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 5d316cb72ec9..15e1456b3f18 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -581,7 +581,6 @@ err: * the last and the first frames arrived and all the bits are here. */ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, - unsigned int *nhoffp, struct net_device *dev) { struct sk_buff *fp, *head = fq->fragments; @@ -654,6 +653,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, head->dev = dev; skb_set_timestamp(head, &fq->stamp); head->nh.ipv6h->payload_len = htons(payload_len); + IP6CB(head)->nhoff = nhoff; *skb_in = head; @@ -663,7 +663,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); fq->fragments = NULL; - *nhoffp = nhoff; return 1; out_oversize: @@ -678,7 +677,7 @@ out_fail: return -1; } -static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) +static int ipv6_frag_rcv(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; struct net_device *dev = skb->dev; @@ -710,7 +709,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) skb->h.raw += sizeof(struct frag_hdr); IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); - *nhoffp = (u8*)fhdr - skb->nh.raw; + IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw; return 1; } @@ -722,11 +721,11 @@ static int ipv6_frag_rcv(struct sk_buff **skbp, unsigned int *nhoffp) spin_lock(&fq->lock); - ip6_frag_queue(fq, skb, fhdr, *nhoffp); + ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff); if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) - ret = ip6_frag_reasm(fq, skbp, nhoffp, dev); + ret = ip6_frag_reasm(fq, skbp, dev); spin_unlock(&fq->lock); fq_put(fq, NULL); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2947bc56d8a0..a25f4e8a8ada 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1153,7 +1153,7 @@ ipv6_pktoptions: return 0; } -static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int tcp_v6_rcv(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct tcphdr *th; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d8538dcea813..c47648892c04 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -435,7 +435,7 @@ out: read_unlock(&udp_hash_lock); } -static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int udpv6_rcv(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct sock *sk; diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 28c29d78338e..1079e47f3933 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -26,7 +26,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) IP6_ECN_set_ce(inner_iph); } -int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi) +int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi) { struct sk_buff *skb = *pskb; int err; @@ -38,7 +38,7 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, unsigned int *nhoffp, u32 spi) int nexthdr; unsigned int nhoff; - nhoff = *nhoffp; + nhoff = IP6CB(skb)->nhoff; nexthdr = skb->nh.raw[nhoff]; seq = 0; @@ -144,7 +144,7 @@ drop: EXPORT_SYMBOL(xfrm6_rcv_spi); -int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +int xfrm6_rcv(struct sk_buff **pskb) { - return xfrm6_rcv_spi(pskb, nhoffp, 0); + return xfrm6_rcv_spi(pskb, 0); } diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index fbef7826a74f..da09ff258648 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -397,7 +397,7 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) EXPORT_SYMBOL(xfrm6_tunnel_deregister); -static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int xfrm6_tunnel_rcv(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct xfrm6_tunnel *handler = xfrm6_tunnel_handler; @@ -405,11 +405,11 @@ static int xfrm6_tunnel_rcv(struct sk_buff **pskb, unsigned int *nhoffp) u32 spi; /* device-like_ip6ip6_handler() */ - if (handler && handler->handler(pskb, nhoffp) == 0) + if (handler && handler->handler(pskb) == 0) return 0; spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); - return xfrm6_rcv_spi(pskb, nhoffp, spi); + return xfrm6_rcv_spi(pskb, spi); } static void xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 15c05165c905..04c7fab4edc4 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -905,7 +905,7 @@ static struct inet_protosw sctpv6_stream_protosw = { .flags = SCTP_PROTOSW_FLAG, }; -static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +static int sctp6_rcv(struct sk_buff **pskb) { return sctp_rcv(*pskb) ? -1 : 0; } -- cgit v1.2.3 From b05e106698d9966de524e78d9da1bf6407fe0c32 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:03:34 -0800 Subject: [IPV4/6]: Netfilter IPsec input hooks When the innermost transform uses transport mode the decapsulated packet is not visible to netfilter. Pass the packet through the PRE_ROUTING and LOCAL_IN hooks again before handing it to upper layer protocols to make netfilter-visibility symetrical to the output path. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/ipv6.h | 2 ++ net/ipv4/xfrm4_input.c | 31 +++++++++++++++++++++++++++++++ net/ipv6/ip6_input.c | 2 +- net/ipv6/xfrm6_input.c | 13 +++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 860bbac4c4ee..3b1d963d396c 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -418,6 +418,8 @@ extern int ipv6_rcv(struct sk_buff *skb, struct packet_type *pt, struct net_device *orig_dev); +extern int ip6_rcv_finish(struct sk_buff *skb); + /* * upper-layer output functions */ diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 2d3849c38a0f..850d919591d1 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -45,6 +47,23 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) return xfrm_parse_spi(skb, nexthdr, spi, seq); } +#ifdef CONFIG_NETFILTER +static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) +{ + struct iphdr *iph = skb->nh.iph; + + if (skb->dst == NULL) { + if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, + skb->dev)) + goto drop; + } + return dst_input(skb); +drop: + kfree_skb(skb); + return NET_RX_DROP; +} +#endif + int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) { int err; @@ -137,6 +156,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state)); skb->sp->len += xfrm_nr; + nf_reset(skb); + if (decaps) { if (!(skb->dev->flags&IFF_LOOPBACK)) { dst_release(skb->dst); @@ -145,7 +166,17 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) netif_rx(skb); return 0; } else { +#ifdef CONFIG_NETFILTER + __skb_push(skb, skb->data - skb->nh.raw); + skb->nh.iph->tot_len = htons(skb->len); + ip_send_check(skb->nh.iph); + + NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, + xfrm4_rcv_encap_finish); + return 0; +#else return -skb->nh.iph->protocol; +#endif } drop_unlock: diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 13d724150f33..29f73592e68e 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -48,7 +48,7 @@ -static inline int ip6_rcv_finish( struct sk_buff *skb) +inline int ip6_rcv_finish( struct sk_buff *skb) { if (skb->dst == NULL) ip6_route_input(skb); diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 1079e47f3933..1ca2da68ef69 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -121,6 +123,8 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi) skb->sp->len += xfrm_nr; skb->ip_summed = CHECKSUM_NONE; + nf_reset(skb); + if (decaps) { if (!(skb->dev->flags&IFF_LOOPBACK)) { dst_release(skb->dst); @@ -129,7 +133,16 @@ int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi) netif_rx(skb); return -1; } else { +#ifdef CONFIG_NETFILTER + skb->nh.ipv6h->payload_len = htons(skb->len); + __skb_push(skb, skb->data - skb->nh.raw); + + NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, + ip6_rcv_finish); + return -1; +#else return 1; +#endif } drop_unlock: -- cgit v1.2.3 From 8cdfab8a43bb4b3da686ea503a702cb6f9f6a803 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:04:01 -0800 Subject: [IPV4]: reset IPCB flags when neccessary Reset IPSKB_XFRM_TUNNEL_SIZE flags in ipip and ip_gre hard_start_xmit function before the packet reenters IP. This is neccessary so the encapsulated packets are checked not to be oversized in xfrm4_output.c again. Reset all flags in sit when a packet changes its address family. Also remove some obsolete IPSKB flags. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/ip.h | 8 +++----- net/ipv4/ip_gre.c | 1 + net/ipv4/ipip.c | 1 + net/ipv6/sit.c | 2 ++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 7bb5804847f2..52f4d9c69704 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -37,11 +37,9 @@ struct inet_skb_parm struct ip_options opt; /* Compiled IP options */ unsigned char flags; -#define IPSKB_MASQUERADED 1 -#define IPSKB_TRANSLATED 2 -#define IPSKB_FORWARDED 4 -#define IPSKB_XFRM_TUNNEL_SIZE 8 -#define IPSKB_FRAG_COMPLETE 16 +#define IPSKB_FORWARDED 1 +#define IPSKB_XFRM_TUNNEL_SIZE 2 +#define IPSKB_FRAG_COMPLETE 4 }; struct ipcm_cookie diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 912c42f57c79..65c3a91ed85e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -832,6 +832,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, gre_hlen); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~IPSKB_XFRM_TUNNEL_SIZE; dst_release(skb->dst); skb->dst = &rt->u.dst; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 35571cff81c6..078b59be91f4 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -621,6 +621,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~IPSKB_XFRM_TUNNEL_SIZE; dst_release(skb->dst); skb->dst = &rt->u.dst; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 577d49732b0f..02872ae8a439 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -381,6 +381,7 @@ static int ipip6_rcv(struct sk_buff *skb) skb->mac.raw = skb->nh.raw; skb->nh.raw = skb->data; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + IPCB(skb)->flags = 0; skb->protocol = htons(ETH_P_IPV6); skb->pkt_type = PACKET_HOST; tunnel->stat.rx_packets++; @@ -552,6 +553,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags = 0; dst_release(skb->dst); skb->dst = &rt->u.dst; -- cgit v1.2.3 From 3e3850e989c5d2eb1aab6f0fd9257759f0f4cbc6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:04:54 -0800 Subject: [NETFILTER]: Fix xfrm lookup in ip_route_me_harder/ip6_route_me_harder ip_route_me_harder doesn't use the port numbers of the xfrm lookup and uses ip_route_input for non-local addresses which doesn't do a xfrm lookup, ip6_route_me_harder doesn't do a xfrm lookup at all. Use xfrm_decode_session and do the lookup manually, make sure both only do the lookup if the packet hasn't been transformed already. Makeing sure the lookup only happens once needs a new field in the IP6CB, which exceeds the size of skb->cb. The size of skb->cb is increased to 48b. Apparently the IPv6 mobile extensions need some more room anyway. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/ipv6.h | 3 +++ include/linux/skbuff.h | 2 +- include/net/ip.h | 3 ++- include/net/xfrm.h | 2 +- net/ipv4/ip_gre.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv4/netfilter.c | 12 ++++++++++-- net/ipv4/xfrm4_output.c | 1 + net/ipv6/netfilter.c | 9 ++++++++- net/ipv6/xfrm6_output.c | 1 + net/xfrm/xfrm_policy.c | 9 +++++---- 11 files changed, 34 insertions(+), 12 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 5cfc71529595..9c8f4c9ed429 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -192,6 +192,9 @@ struct inet6_skb_parm { __u16 dst1; __u16 lastopt; __u32 nhoff; + __u16 flags; + +#define IP6SKB_XFRM_TRANSFORMED 1 }; #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 483cfc47ec34..e5fd66c5650b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -251,7 +251,7 @@ struct sk_buff { * want to keep them across layers you have to do a skb_clone() * first. This is owned by whoever has the skb queued ATM. */ - char cb[40]; + char cb[48]; unsigned int len, data_len, diff --git a/include/net/ip.h b/include/net/ip.h index 52f4d9c69704..a494d04e5dea 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -39,7 +39,8 @@ struct inet_skb_parm #define IPSKB_FORWARDED 1 #define IPSKB_XFRM_TUNNEL_SIZE 2 -#define IPSKB_FRAG_COMPLETE 4 +#define IPSKB_XFRM_TRANSFORMED 4 +#define IPSKB_FRAG_COMPLETE 8 }; struct ipcm_cookie diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 297d09d28fe4..d6111a2f0a23 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -668,7 +668,7 @@ static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *s return xfrm_policy_check(sk, dir, skb, AF_INET6); } - +extern int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family); extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 65c3a91ed85e..de16e944777f 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -832,7 +832,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, gre_hlen); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - IPCB(skb)->flags &= ~IPSKB_XFRM_TUNNEL_SIZE; + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE|IPSKB_XFRM_TRANSFORMED); dst_release(skb->dst); skb->dst = &rt->u.dst; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 078b59be91f4..bbd85f5ec985 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -621,7 +621,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - IPCB(skb)->flags &= ~IPSKB_XFRM_TUNNEL_SIZE; + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE|IPSKB_XFRM_TRANSFORMED); dst_release(skb->dst); skb->dst = &rt->u.dst; diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index ae0779d82c5d..4c637a1cbd23 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -7,11 +7,13 @@ #include #include +#include #include #include #include #include -#include +#include +#include /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ int ip_route_me_harder(struct sk_buff **pskb) @@ -33,7 +35,6 @@ int ip_route_me_harder(struct sk_buff **pskb) #ifdef CONFIG_IP_ROUTE_FWMARK fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; #endif - fl.proto = iph->protocol; if (ip_route_output_key(&rt, &fl) != 0) return -1; @@ -60,6 +61,13 @@ int ip_route_me_harder(struct sk_buff **pskb) if ((*pskb)->dst->error) return -1; +#ifdef CONFIG_XFRM + if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED) && + xfrm_decode_session(*pskb, &fl, AF_INET) == 0) + if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0)) + return -1; +#endif + /* Change in oif may mean change in hh_len. */ hh_len = (*pskb)->dst->dev->hard_header_len; if (skb_headroom(*pskb) < hh_len) { diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 51fabb8f7c54..160c48800ab8 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -140,6 +140,7 @@ static int xfrm4_output_one(struct sk_buff *skb) x = dst->xfrm; } while (x && !x->props.mode); + IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; err = 0; out_exit: diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index f8626ebf90fd..b63678328a3b 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -10,6 +10,7 @@ #include #include #include +#include int ip6_route_me_harder(struct sk_buff *skb) { @@ -21,11 +22,17 @@ int ip6_route_me_harder(struct sk_buff *skb) { .ip6_u = { .daddr = iph->daddr, .saddr = iph->saddr, } }, - .proto = iph->nexthdr, }; dst = ip6_route_output(skb->sk, &fl); +#ifdef CONFIG_XFRM + if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && + xfrm_decode_session(skb, &fl, AF_INET6) == 0) + if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0)) + return -1; +#endif + if (dst->error) { IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index fc0ea38953c4..80242172a5df 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -139,6 +139,7 @@ static int xfrm6_output_one(struct sk_buff *skb) x = dst->xfrm; } while (x && !x->props.mode); + IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; err = 0; out_exit: diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 64a447375fdb..f2edc9225b6a 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -951,8 +951,8 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, return start; } -static int -_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) +int +xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) { struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); @@ -963,6 +963,7 @@ _decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) xfrm_policy_put_afinfo(afinfo); return 0; } +EXPORT_SYMBOL(xfrm_decode_session); static inline int secpath_has_tunnel(struct sec_path *sp, int k) { @@ -982,7 +983,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, u8 fl_dir = policy_to_flow_dir(dir); u32 sk_sid; - if (_decode_session(skb, &fl, family) < 0) + if (xfrm_decode_session(skb, &fl, family) < 0) return 0; sk_sid = security_sk_sid(sk, &fl, fl_dir); @@ -1055,7 +1056,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { struct flowi fl; - if (_decode_session(skb, &fl, family) < 0) + if (xfrm_decode_session(skb, &fl, family) < 0) return 0; return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; -- cgit v1.2.3 From 4e8e9de7c25315669e2d5565acc50ec379522c28 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:05:17 -0800 Subject: [NETFILTER]: Use conntrack information to determine if packet was NATed Preparation for IPsec support for NAT: Use conntrack information instead of saving the saving and comparing the addresses to determine if a packet was NATed and needs to be rerouted to make it easier to extend the key. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_nat_standalone.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index f04111f74e09..1bb50897a5a2 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -162,18 +162,20 @@ ip_nat_in(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - u_int32_t saddr, daddr; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; unsigned int ret; - saddr = (*pskb)->nh.iph->saddr; - daddr = (*pskb)->nh.iph->daddr; - ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN - && ((*pskb)->nh.iph->saddr != saddr - || (*pskb)->nh.iph->daddr != daddr)) { - dst_release((*pskb)->dst); - (*pskb)->dst = NULL; + && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.src.ip != + ct->tuplehash[!dir].tuple.dst.ip) { + dst_release((*pskb)->dst); + (*pskb)->dst = NULL; + } } return ret; } @@ -200,7 +202,8 @@ ip_nat_local_fn(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - u_int32_t saddr, daddr; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; unsigned int ret; /* root is playing with raw sockets. */ @@ -208,14 +211,15 @@ ip_nat_local_fn(unsigned int hooknum, || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; - saddr = (*pskb)->nh.iph->saddr; - daddr = (*pskb)->nh.iph->daddr; - ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN - && ((*pskb)->nh.iph->saddr != saddr - || (*pskb)->nh.iph->daddr != daddr)) - return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.dst.ip != + ct->tuplehash[!dir].tuple.src.ip) + return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + } return ret; } -- cgit v1.2.3 From 5c901daaea3be0d900b3ae1fc9b5f64ff94e4f02 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:05:36 -0800 Subject: [NETFILTER]: Redo policy lookups after NAT when neccessary When NAT changes the key used for the xfrm lookup it needs to be done again. If a new policy is returned in POST_ROUTING the packet needs to be passed to xfrm4_output_one manually after all hooks were called because POST_ROUTING is called with fixed okfn (ip_finish_output). Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/xfrm.h | 1 + net/ipv4/ip_output.c | 5 +++++ net/ipv4/netfilter/ip_nat_standalone.c | 27 +++++++++++++++++++++++++-- net/ipv4/xfrm4_output.c | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index d6111a2f0a23..d09ca0e7d139 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -866,6 +866,7 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm4_rcv(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); +extern int xfrm4_output_finish(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); extern int xfrm6_rcv_spi(struct sk_buff **pskb, u32 spi); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8b1c9bd0091e..59fdac3a099a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -202,6 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb) static inline int ip_finish_output(struct sk_buff *skb) { +#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) + /* Policy lookup after SNAT yielded a new policy */ + if (skb->dst->xfrm != NULL) + return xfrm4_output_finish(skb); +#endif if (skb->len > dst_mtu(skb->dst) && !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) return ip_fragment(skb, ip_finish_output2); diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 1bb50897a5a2..b518697af4db 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + unsigned int ret; + /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; - return ip_nat_fn(hooknum, pskb, in, out, okfn); + ret = ip_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN + && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.src.ip != + ct->tuplehash[!dir].tuple.dst.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.src.u.all != + ct->tuplehash[!dir].tuple.dst.u.all +#endif + ) + return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + } + return ret; } static unsigned int @@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum, enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.ip != - ct->tuplehash[!dir].tuple.src.ip) + ct->tuplehash[!dir].tuple.src.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.dst.u.all != + ct->tuplehash[dir].tuple.src.u.all +#endif + ) return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; } return ret; diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 160c48800ab8..d4df0ddd424b 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -152,7 +152,7 @@ error_nolock: goto out_exit; } -static int xfrm4_output_finish(struct sk_buff *skb) +int xfrm4_output_finish(struct sk_buff *skb) { int err; -- cgit v1.2.3 From b59c270104f03960069596722fea70340579244d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:06:10 -0800 Subject: [NETFILTER]: Keep conntrack reference until IPsec policy checks are done Keep the conntrack reference until policy checks have been performed for IPsec NAT support. The reference needs to be dropped before a packet is queued to avoid having the conntrack module unloadable. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 1 + net/ipv4/ip_input.c | 15 ++++++--------- net/ipv4/raw.c | 1 + net/ipv4/tcp_ipv4.c | 1 + net/ipv4/udp.c | 2 ++ net/sctp/input.c | 1 + 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 3f244670764a..23ba177c1150 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1099,6 +1099,7 @@ int dccp_v4_destroy_sock(struct sock *sk) kfree_skb(sk->sk_send_head); sk->sk_send_head = NULL; } + nf_reset(skb); /* Clean up a referenced DCCP bind bucket. */ if (inet_csk(sk)->icsk_bind_hash != NULL) diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index e45846ae570b..18d7fad474d7 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -185,7 +185,6 @@ int ip_call_ra_chain(struct sk_buff *skb) raw_rcv(last, skb2); } last = sk; - nf_reset(skb); } } @@ -204,10 +203,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) __skb_pull(skb, ihl); - /* Free reference early: we don't need it any more, and it may - hold ip_conntrack module loaded indefinitely. */ - nf_reset(skb); - /* Point into the IP datagram, just past the header. */ skb->h.raw = skb->data; @@ -232,10 +227,12 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { int ret; - if (!ipprot->no_policy && - !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - goto out; + if (!ipprot->no_policy) { + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { + kfree_skb(skb); + goto out; + } + nf_reset(skb); } ret = ipprot->handler(skb); if (ret < 0) { diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 4b0d7e4d6269..165a4d81efa4 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -255,6 +255,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) kfree_skb(skb); return NET_RX_DROP; } + nf_reset(skb); skb_push(skb, skb->data - skb->nh.raw); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index e9f83e5b28ce..6ea353907af5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1080,6 +1080,7 @@ process: if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; + nf_reset(skb); if (sk_filter(sk, skb, 0)) goto discard_and_relse; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 223abaa72bc5..00840474a449 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -989,6 +989,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) kfree_skb(skb); return -1; } + nf_reset(skb); if (up->encap_type) { /* @@ -1149,6 +1150,7 @@ int udp_rcv(struct sk_buff *skb) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto drop; + nf_reset(skb); /* No socket. Drop packet silently, if checksum is wrong */ if (udp_checksum_complete(skb)) diff --git a/net/sctp/input.c b/net/sctp/input.c index 238f1bffa684..4aa6fc60357c 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -225,6 +225,7 @@ int sctp_rcv(struct sk_buff *skb) if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) goto discard_release; + nf_reset(skb); ret = sk_filter(sk, skb, 1); if (ret) -- cgit v1.2.3 From eb9c7ebe6980c41cf6ae889e301c3b49f473ee9f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:06:30 -0800 Subject: [NETFILTER]: Handle NAT in IPsec policy checks Handle NAT of decapsulated IPsec packets by reconstructing the struct flowi of the original packet from the conntrack information for IPsec policy checks. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter.h | 16 +++++++++++ net/dccp/ipv4.c | 2 +- net/ipv4/netfilter.c | 3 ++ net/ipv4/netfilter/ip_nat_standalone.c | 50 ++++++++++++++++++++++++++++++++-- net/xfrm/xfrm_policy.c | 2 ++ 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 79bb977afeac..84506dfa1f37 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -274,6 +274,20 @@ struct nf_queue_rerouter { extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer); extern int nf_unregister_queue_rerouter(int pf); +#include +extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); + +static inline void +nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) +{ +#ifdef CONFIG_IP_NF_NAT_NEEDED + void (*decodefn)(struct sk_buff *, struct flowi *); + + if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL) + decodefn(skb, fl); +#endif +} + #ifdef CONFIG_PROC_FS #include extern struct proc_dir_entry *proc_net_netfilter; @@ -282,6 +296,8 @@ extern struct proc_dir_entry *proc_net_netfilter; #else /* !CONFIG_NETFILTER */ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} +static inline void +nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {} #endif /*CONFIG_NETFILTER*/ #endif /*__KERNEL__*/ diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 23ba177c1150..00f983226672 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -986,6 +986,7 @@ int dccp_v4_rcv(struct sk_buff *skb) if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; + nf_reset(skb); return sk_receive_skb(sk, skb); @@ -1099,7 +1100,6 @@ int dccp_v4_destroy_sock(struct sock *sk) kfree_skb(sk->sk_send_head); sk->sk_send_head = NULL; } - nf_reset(skb); /* Clean up a referenced DCCP bind bucket. */ if (inet_csk(sk)->icsk_bind_hash != NULL) diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 4c637a1cbd23..3321092b0914 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -86,6 +86,9 @@ int ip_route_me_harder(struct sk_buff **pskb) } EXPORT_SYMBOL(ip_route_me_harder); +void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *); +EXPORT_SYMBOL(ip_nat_decode_session); + /* * Extra routing may needed on local out, as the QUEUE target never * returns control to the table. diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index b518697af4db..8b8a1f00bbf4 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -55,6 +55,44 @@ : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ : "*ERROR*"))) +#ifdef CONFIG_XFRM +static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) +{ + struct ip_conntrack *ct; + struct ip_conntrack_tuple *t; + enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; + unsigned long statusbit; + + ct = ip_conntrack_get(skb, &ctinfo); + if (ct == NULL) + return; + dir = CTINFO2DIR(ctinfo); + t = &ct->tuplehash[dir].tuple; + + if (dir == IP_CT_DIR_ORIGINAL) + statusbit = IPS_DST_NAT; + else + statusbit = IPS_SRC_NAT; + + if (ct->status & statusbit) { + fl->fl4_dst = t->dst.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_dport = t->dst.u.tcp.port; + } + + statusbit ^= IPS_NAT_MASK; + + if (ct->status & statusbit) { + fl->fl4_src = t->src.ip; + if (t->dst.protonum == IPPROTO_TCP || + t->dst.protonum == IPPROTO_UDP) + fl->fl_ip_sport = t->src.u.tcp.port; + } +} +#endif + static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, @@ -330,10 +368,14 @@ static int init_or_cleanup(int init) if (!init) goto cleanup; +#ifdef CONFIG_XFRM + BUG_ON(ip_nat_decode_session != NULL); + ip_nat_decode_session = nat_decode_session; +#endif ret = ip_nat_rule_init(); if (ret < 0) { printk("ip_nat_init: can't setup rules.\n"); - goto cleanup_nothing; + goto cleanup_decode_session; } ret = nf_register_hook(&ip_nat_in_ops); if (ret < 0) { @@ -381,7 +423,11 @@ static int init_or_cleanup(int init) nf_unregister_hook(&ip_nat_in_ops); cleanup_rule_init: ip_nat_rule_cleanup(); - cleanup_nothing: + cleanup_decode_session: +#ifdef CONFIG_XFRM + ip_nat_decode_session = NULL; + synchronize_net(); +#endif return ret; } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f2edc9225b6a..59614a994b4e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -985,6 +986,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, if (xfrm_decode_session(skb, &fl, family) < 0) return 0; + nf_nat_decode_session(skb, &fl, family); sk_sid = security_sk_sid(sk, &fl, fl_dir); -- cgit v1.2.3 From e16a8f0b8c53312beb1d8b52e463aae79aa809c7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 6 Jan 2006 23:06:48 -0800 Subject: [NETFILTER]: Add ipt_policy/ip6t_policy matches Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ipt_policy.h | 52 +++++++++ include/linux/netfilter_ipv6/ip6t_policy.h | 52 +++++++++ net/ipv4/netfilter/Kconfig | 10 ++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_policy.c | 170 ++++++++++++++++++++++++++++ net/ipv6/netfilter/Kconfig | 10 ++ net/ipv6/netfilter/Makefile | 1 + net/ipv6/netfilter/ip6t_policy.c | 175 +++++++++++++++++++++++++++++ 8 files changed, 471 insertions(+) create mode 100644 include/linux/netfilter_ipv4/ipt_policy.h create mode 100644 include/linux/netfilter_ipv6/ip6t_policy.h create mode 100644 net/ipv4/netfilter/ipt_policy.c create mode 100644 net/ipv6/netfilter/ip6t_policy.c diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h new file mode 100644 index 000000000000..7fd1bec453f1 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_policy.h @@ -0,0 +1,52 @@ +#ifndef _IPT_POLICY_H +#define _IPT_POLICY_H + +#define IPT_POLICY_MAX_ELEM 4 + +enum ipt_policy_flags +{ + IPT_POLICY_MATCH_IN = 0x1, + IPT_POLICY_MATCH_OUT = 0x2, + IPT_POLICY_MATCH_NONE = 0x4, + IPT_POLICY_MATCH_STRICT = 0x8, +}; + +enum ipt_policy_modes +{ + IPT_POLICY_MODE_TRANSPORT, + IPT_POLICY_MODE_TUNNEL +}; + +struct ipt_policy_spec +{ + u_int8_t saddr:1, + daddr:1, + proto:1, + mode:1, + spi:1, + reqid:1; +}; + +struct ipt_policy_elem +{ + u_int32_t saddr; + u_int32_t smask; + u_int32_t daddr; + u_int32_t dmask; + u_int32_t spi; + u_int32_t reqid; + u_int8_t proto; + u_int8_t mode; + + struct ipt_policy_spec match; + struct ipt_policy_spec invert; +}; + +struct ipt_policy_info +{ + struct ipt_policy_elem pol[IPT_POLICY_MAX_ELEM]; + u_int16_t flags; + u_int16_t len; +}; + +#endif /* _IPT_POLICY_H */ diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h new file mode 100644 index 000000000000..5a93afcd2ff1 --- /dev/null +++ b/include/linux/netfilter_ipv6/ip6t_policy.h @@ -0,0 +1,52 @@ +#ifndef _IP6T_POLICY_H +#define _IP6T_POLICY_H + +#define IP6T_POLICY_MAX_ELEM 4 + +enum ip6t_policy_flags +{ + IP6T_POLICY_MATCH_IN = 0x1, + IP6T_POLICY_MATCH_OUT = 0x2, + IP6T_POLICY_MATCH_NONE = 0x4, + IP6T_POLICY_MATCH_STRICT = 0x8, +}; + +enum ip6t_policy_modes +{ + IP6T_POLICY_MODE_TRANSPORT, + IP6T_POLICY_MODE_TUNNEL +}; + +struct ip6t_policy_spec +{ + u_int8_t saddr:1, + daddr:1, + proto:1, + mode:1, + spi:1, + reqid:1; +}; + +struct ip6t_policy_elem +{ + struct in6_addr saddr; + struct in6_addr smask; + struct in6_addr daddr; + struct in6_addr dmask; + u_int32_t spi; + u_int32_t reqid; + u_int8_t proto; + u_int8_t mode; + + struct ip6t_policy_spec match; + struct ip6t_policy_spec invert; +}; + +struct ip6t_policy_info +{ + struct ip6t_policy_elem pol[IP6T_POLICY_MAX_ELEM]; + u_int16_t flags; + u_int16_t len; +}; + +#endif /* _IP6T_POLICY_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 88a60650e6b8..a9893ec03e02 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -487,6 +487,16 @@ config IP_NF_MATCH_STRING To compile it as a module, choose M here. If unsure, say N. +config IP_NF_MATCH_POLICY + tristate "IPsec policy match support" + depends on IP_NF_IPTABLES && XFRM + help + Policy matching allows you to match packets based on the + IPsec policy that was used during decapsulation/will + be used during encapsulation. + + To compile it as a module, choose M here. If unsure, say N. + # `filter', generic and specific targets config IP_NF_FILTER tristate "Packet filtering" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index d0a447e520a2..549b01a648b3 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o +obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c new file mode 100644 index 000000000000..709debcc69c9 --- /dev/null +++ b/net/ipv4/netfilter/ipt_policy.c @@ -0,0 +1,170 @@ +/* IP tables module for matching IPsec policy + * + * Copyright (c) 2004,2005 Patrick McHardy, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("IPtables IPsec policy matching module"); +MODULE_LICENSE("GPL"); + + +static inline int +match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e) +{ +#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) + + return MATCH(saddr, x->props.saddr.a4 & e->smask) && + MATCH(daddr, x->id.daddr.a4 & e->dmask) && + MATCH(proto, x->id.proto) && + MATCH(mode, x->props.mode) && + MATCH(spi, x->id.spi) && + MATCH(reqid, x->props.reqid); +} + +static int +match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info) +{ + const struct ipt_policy_elem *e; + struct sec_path *sp = skb->sp; + int strict = info->flags & IPT_POLICY_MATCH_STRICT; + int i, pos; + + if (sp == NULL) + return -1; + if (strict && info->len != sp->len) + return 0; + + for (i = sp->len - 1; i >= 0; i--) { + pos = strict ? i - sp->len + 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(sp->x[i].xvec, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int +match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info) +{ + const struct ipt_policy_elem *e; + struct dst_entry *dst = skb->dst; + int strict = info->flags & IPT_POLICY_MATCH_STRICT; + int i, pos; + + if (dst->xfrm == NULL) + return -1; + + for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { + pos = strict ? i : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(dst->xfrm, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, int offset, int *hotdrop) +{ + const struct ipt_policy_info *info = matchinfo; + int ret; + + if (info->flags & IPT_POLICY_MATCH_IN) + ret = match_policy_in(skb, info); + else + ret = match_policy_out(skb, info); + + if (ret < 0) + ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0; + else if (info->flags & IPT_POLICY_MATCH_NONE) + ret = 0; + + return ret; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_policy_info *info = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(*info))) { + printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n", + matchsize, IPT_ALIGN(sizeof(*info))); + return 0; + } + if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) { + printk(KERN_ERR "ipt_policy: neither incoming nor " + "outgoing policy selected\n"); + return 0; + } + if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN) + && info->flags & IPT_POLICY_MATCH_OUT) { + printk(KERN_ERR "ipt_policy: output policy not valid in " + "PRE_ROUTING and INPUT\n"); + return 0; + } + if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT) + && info->flags & IPT_POLICY_MATCH_IN) { + printk(KERN_ERR "ipt_policy: input policy not valid in " + "POST_ROUTING and OUTPUT\n"); + return 0; + } + if (info->len > IPT_POLICY_MAX_ELEM) { + printk(KERN_ERR "ipt_policy: too many policy elements\n"); + return 0; + } + + return 1; +} + +static struct ipt_match policy_match = { + .name = "policy", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ipt_register_match(&policy_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&policy_match); +} + +module_init(init); +module_exit(fini); diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 04912f9b35c3..105dd69ee9fb 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -179,6 +179,16 @@ config IP6_NF_MATCH_PHYSDEV To compile it as a module, choose M here. If unsure, say N. +config IP6_NF_MATCH_POLICY + tristate "IPsec policy match support" + depends on IP6_NF_IPTABLES && XFRM + help + Policy matching allows you to match packets based on the + IPsec policy that was used during decapsulation/will + be used during encapsulation. + + To compile it as a module, choose M here. If unsure, say N. + # The targets config IP6_NF_FILTER tristate "Packet filtering" diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 9ab5b2ca1f59..c0c809b426e8 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o +obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c new file mode 100644 index 000000000000..13fedad48c1d --- /dev/null +++ b/net/ipv6/netfilter/ip6t_policy.c @@ -0,0 +1,175 @@ +/* IP tables module for matching IPsec policy + * + * Copyright (c) 2004,2005 Patrick McHardy, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("IPtables IPsec policy matching module"); +MODULE_LICENSE("GPL"); + + +static inline int +match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e) +{ +#define MATCH_ADDR(x,y,z) (!e->match.x || \ + ((ip6_masked_addrcmp((z), &e->x, &e->y)) == 0) ^ e->invert.x) +#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) + + return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) && + MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) && + MATCH(proto, x->id.proto) && + MATCH(mode, x->props.mode) && + MATCH(spi, x->id.spi) && + MATCH(reqid, x->props.reqid); +} + +static int +match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info) +{ + const struct ip6t_policy_elem *e; + struct sec_path *sp = skb->sp; + int strict = info->flags & IP6T_POLICY_MATCH_STRICT; + int i, pos; + + if (sp == NULL) + return -1; + if (strict && info->len != sp->len) + return 0; + + for (i = sp->len - 1; i >= 0; i--) { + pos = strict ? i - sp->len + 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(sp->x[i].xvec, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int +match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info) +{ + const struct ip6t_policy_elem *e; + struct dst_entry *dst = skb->dst; + int strict = info->flags & IP6T_POLICY_MATCH_STRICT; + int i, pos; + + if (dst->xfrm == NULL) + return -1; + + for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { + pos = strict ? i : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(dst->xfrm, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + unsigned int protoff, + int *hotdrop) +{ + const struct ip6t_policy_info *info = matchinfo; + int ret; + + if (info->flags & IP6T_POLICY_MATCH_IN) + ret = match_policy_in(skb, info); + else + ret = match_policy_out(skb, info); + + if (ret < 0) + ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0; + else if (info->flags & IP6T_POLICY_MATCH_NONE) + ret = 0; + + return ret; +} + +static int checkentry(const char *tablename, const struct ip6t_ip6 *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + struct ip6t_policy_info *info = matchinfo; + + if (matchsize != IP6T_ALIGN(sizeof(*info))) { + printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n", + matchsize, IP6T_ALIGN(sizeof(*info))); + return 0; + } + if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) { + printk(KERN_ERR "ip6t_policy: neither incoming nor " + "outgoing policy selected\n"); + return 0; + } + if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN) + && info->flags & IP6T_POLICY_MATCH_OUT) { + printk(KERN_ERR "ip6t_policy: output policy not valid in " + "PRE_ROUTING and INPUT\n"); + return 0; + } + if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT) + && info->flags & IP6T_POLICY_MATCH_IN) { + printk(KERN_ERR "ip6t_policy: input policy not valid in " + "POST_ROUTING and OUTPUT\n"); + return 0; + } + if (info->len > IP6T_POLICY_MAX_ELEM) { + printk(KERN_ERR "ip6t_policy: too many policy elements\n"); + return 0; + } + + return 1; +} + +static struct ip6t_match policy_match = { + .name = "policy", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ip6t_register_match(&policy_match); +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&policy_match); +} + +module_init(init); +module_exit(fini); -- cgit v1.2.3 From b341387225832c392ed83b9f89d15668b033a106 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 6 Jan 2006 23:08:42 -0800 Subject: [AX25/MKISS]: unbalanced spinlock_bh in ax_encaps() The unlocking disappeared during commit 5793f4be23f0171b4999ca68a39a9157b44139f3. Signed-off-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/hamradio/mkiss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 3e9accf137e7..41b3d83c2ab8 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -524,6 +524,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; + spin_unlock_bh(&ax->buflock); } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ -- cgit v1.2.3 From da7bc6ee8ee3976696fc740065362ca442eb61c9 Mon Sep 17 00:00:00 2001 From: Joe Kappus Date: Fri, 6 Jan 2006 23:15:04 -0800 Subject: [NETFILTER]: ip_conntrack_proto_sctp.c needs linux/interrupt.h Signed-off-by: Joe Kappus Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_conntrack_proto_sctp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c index 977fb59d4563..0b25050981a1 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From f53b61d8c385140fe7f09e0c9187ae813ee9f330 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 7 Jan 2006 12:50:27 -0800 Subject: [NETFILTER]: Add dummy nf_hook{_thresh}() when NETFILTER is disabled. Signed-off-by: David S. Miller --- include/linux/netfilter.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 84506dfa1f37..4cf6088625c1 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -295,7 +295,22 @@ extern struct proc_dir_entry *proc_net_netfilter; #else /* !CONFIG_NETFILTER */ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) +static inline int nf_hook_thresh(int pf, unsigned int hook, + struct sk_buff **pskb, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *), int thresh) +{ + return okfn(*pskb); +} +static inline int nf_hook(int pf, unsigned int hook, struct sk_buff **pskb, + struct net_device *indev, struct net_device *outdev, + int (*okfn)(struct sk_buff *)) +{ + return okfn(*pskb); +} static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} +struct flowi; static inline void nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {} #endif /*CONFIG_NETFILTER*/ -- cgit v1.2.3 From 97dc627fb3471664c72d0933790a90ba3f91e131 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 7 Jan 2006 13:23:39 -0800 Subject: [IPV4]: make ip_fragment() static Since there's no longer any external user of ip_fragment() we can make it static. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- include/net/ip.h | 1 - net/ipv4/ip_output.c | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index a494d04e5dea..8de0697b364c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -94,7 +94,6 @@ extern int ip_local_deliver(struct sk_buff *skb); extern int ip_mr_input(struct sk_buff *skb); extern int ip_output(struct sk_buff *skb); extern int ip_mc_output(struct sk_buff *skb); -extern int ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*)); extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); extern int ip_queue_xmit(struct sk_buff *skb, int ipfragok); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 59fdac3a099a..c2169b47ddfd 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -85,6 +85,8 @@ int sysctl_ip_default_ttl = IPDEFTTL; +static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)); + /* Generate a checksum for an outgoing IP datagram. */ __inline__ void ip_send_check(struct iphdr *iph) { @@ -414,7 +416,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) * single device frame, and queue such a frame for sending. */ -int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) +static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) { struct iphdr *iph; int raw = 0; @@ -1396,7 +1398,6 @@ void __init ip_init(void) #endif } -EXPORT_SYMBOL(ip_fragment); EXPORT_SYMBOL(ip_generic_getfrag); EXPORT_SYMBOL(ip_queue_xmit); EXPORT_SYMBOL(ip_send_check); -- cgit v1.2.3 From 9f5336e21893fafd232a9a02cfa7588ad153889a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 7 Jan 2006 13:24:25 -0800 Subject: [IPV6]: small cleanups This patch contains the following cleanups: - addrconf.c: make addrconf_dad_stop() static - inet6_connection_sock.c should #include for getting the prototypes of it's global functions Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 +- net/ipv6/inet6_connection_sock.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 704fb73e6c5f..e53e421eeee9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1228,7 +1228,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) /* Gets referenced address, destroys ifaddr */ -void addrconf_dad_stop(struct inet6_ifaddr *ifp) +static void addrconf_dad_stop(struct inet6_ifaddr *ifp) { if (ifp->flags&IFA_F_PERMANENT) { spin_lock_bh(&ifp->lock); diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 792f90f0f9ec..f8f3a37a1494 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -25,6 +25,7 @@ #include #include #include +#include int inet6_csk_bind_conflict(const struct sock *sk, const struct inet_bind_bucket *tb) -- cgit v1.2.3 From f61051cd2fc58546f28c226933942d4360810ffb Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 7 Jan 2006 23:11:23 +0000 Subject: [SERIAL] Fix clocal wakeup problem Jim Alexander reported a problem where "if one calls open() in blocking mode with CLOCAL off, the 8250.c driver under the 2.6 kernel (or at least 2.6.8 and 2.6.10) does not wake up the blocked process when DCD is asserted." Fix this by enabling modem status interrupts immediately before we read the carrier detect status. Thanks to Jim for reporting the problem and testing the fix. Signed-off-by: Russell King --- drivers/serial/serial_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 34c576dfad8d..9589509fc5bd 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1440,6 +1440,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * modem is ready for us. */ spin_lock_irq(&port->lock); + port->ops->enable_ms(port); mctrl = port->ops->get_mctrl(port); spin_unlock_irq(&port->lock); if (mctrl & TIOCM_CAR) -- cgit v1.2.3 From a61c2d78ce61e67baf27c43f6721db87a27ac762 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 7 Jan 2006 23:18:19 +0000 Subject: [SERIAL] Make the number of UARTs registered configurable. Also add a nr_uarts module option to the 8250 code to override this, up to a maximum of CONFIG_SERIAL_8250_NR_UARTS This should appease people who complain about a proliferation of /dev/ttyS & /sysfs nodes whilst at the same time allowing a single kernel image to support the rarer occasions of lots of devices. Signed-off-by: Dave Jones --- Documentation/kernel-parameters.txt | 2 ++ drivers/serial/8250.c | 28 ++++++++++++++++++---------- drivers/serial/Kconfig | 10 ++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index acb010bb087b..0dc848bf0b56 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -998,6 +998,8 @@ running once the system is up. nowb [ARM] + nr_uarts= [SERIAL] maximum number of UARTs to be registered. + opl3= [HW,OSS] Format: diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 1891cf5bdeef..e8454611cb65 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -54,6 +54,8 @@ */ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; +static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; + /* * Debugging. */ @@ -2118,7 +2120,7 @@ static void __init serial8250_isa_init_ports(void) return; first = 0; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; up->port.line = i; @@ -2137,7 +2139,7 @@ static void __init serial8250_isa_init_ports(void) } for (i = 0, up = serial8250_ports; - i < ARRAY_SIZE(old_serial_port) && i < UART_NR; + i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++, up++) { up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); @@ -2159,7 +2161,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) serial8250_isa_init_ports(); - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; up->port.dev = dev; @@ -2262,7 +2264,7 @@ static int serial8250_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index >= UART_NR) + if (co->index >= nr_uarts) co->index = 0; port = &serial8250_ports[co->index].port; if (!port->iobase && !port->membase) @@ -2298,7 +2300,7 @@ static int __init find_port(struct uart_port *p) int line; struct uart_port *port; - for (line = 0; line < UART_NR; line++) { + for (line = 0; line < nr_uarts; line++) { port = &serial8250_ports[line].port; if (uart_match_port(p, port)) return line; @@ -2420,7 +2422,7 @@ static int __devexit serial8250_remove(struct platform_device *dev) { int i; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; if (up->port.dev == &dev->dev) @@ -2487,7 +2489,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * /* * First, find a port entry which matches. */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; @@ -2496,7 +2498,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * free entry. We look for one which hasn't been previously * used (indicated by zero iobase). */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN && serial8250_ports[i].port.iobase == 0) return &serial8250_ports[i]; @@ -2505,7 +2507,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * That also failed. Last resort is to find any entry which * doesn't have a real port associated with it. */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN) return &serial8250_ports[i]; @@ -2590,8 +2592,11 @@ static int __init serial8250_init(void) { int ret, i; + if (nr_uarts > UART_NR) + nr_uarts = UART_NR; + printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ " - "%d ports, IRQ sharing %sabled\n", (int) UART_NR, + "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); for (i = 0; i < NR_IRQS; i++) @@ -2651,6 +2656,9 @@ module_param(share_irqs, uint, 0644); MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" " (unsafe)"); +module_param(nr_uarts, uint, 0644); +MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); + #ifdef CONFIG_SERIAL_8250_RSA module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 812bae62c8ec..3fd5b999fdac 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -95,6 +95,16 @@ config SERIAL_8250_NR_UARTS PCI enumeration and any ports that may be added at run-time via hot-plug, or any ISA multi-port serial cards. +config SERIAL_8250_RUNTIME_UARTS + int "Number of 8250/16550 serial ports to register at runtime" + depends on SERIAL_8250 + default "4" + help + Set this to the maximum number of serial ports you want + the kernel to register at boot time. This can be overriden + with the module parameter "nr_uarts", or boot-time parameter + 8250.nr_uarts + config SERIAL_8250_EXTENDED bool "Extended 8250/16550 serial driver options" depends on SERIAL_8250 -- cgit v1.2.3 From 757b18661ea0a0d890e8ce7b1a391e5b7d417d78 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 7 Jan 2006 13:19:00 -0500 Subject: [ACPI] make two processor functions static acpi_processor_write_throttling() acpi_processor_write_limit() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/processor_thermal.c | 6 +++--- drivers/acpi/processor_throttling.c | 6 +++--- include/acpi/processor.h | 6 ------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 22fc9e28a58d..f99ad05cd6a2 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -348,9 +348,9 @@ static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -ssize_t acpi_processor_write_limit(struct file * file, - const char __user * buffer, - size_t count, loff_t * data) +static ssize_t acpi_processor_write_limit(struct file * file, + const char __user * buffer, + size_t count, loff_t * data) { int result = 0; struct seq_file *m = (struct seq_file *)file->private_data; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 5cd056abfcfb..b966549ec000 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -306,9 +306,9 @@ static int acpi_processor_throttling_open_fs(struct inode *inode, PDE(inode)->data); } -ssize_t acpi_processor_write_throttling(struct file * file, - const char __user * buffer, - size_t count, loff_t * data) +static ssize_t acpi_processor_write_throttling(struct file * file, + const char __user * buffer, + size_t count, loff_t * data) { int result = 0; struct seq_file *m = (struct seq_file *)file->private_data; diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 7a00d5089de9..edb5a8919cb6 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -235,9 +235,6 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr) /* in processor_throttling.c */ int acpi_processor_get_throttling_info(struct acpi_processor *pr); int acpi_processor_set_throttling(struct acpi_processor *pr, int state); -ssize_t acpi_processor_write_throttling(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); extern struct file_operations acpi_processor_throttling_fops; /* in processor_idle.c */ @@ -249,9 +246,6 @@ int acpi_processor_power_exit(struct acpi_processor *pr, /* in processor_thermal.c */ int acpi_processor_get_limit_info(struct acpi_processor *pr); -ssize_t acpi_processor_write_limit(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); extern struct file_operations acpi_processor_limit_fops; #ifdef CONFIG_CPU_FREQ -- cgit v1.2.3 From 5e68d95d155c94e45f16b521fd4e2bcd6c8481b1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 8 Jan 2006 14:21:52 +0000 Subject: [MMC] wbsd pnp suspend Allow the wbsd driver to use the new suspend/resume functions added to the PnP layer. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 106 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 4f13bd2ccf9a..60afc1235120 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1980,37 +1980,53 @@ static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) #ifdef CONFIG_PM -static int wbsd_suspend(struct platform_device *dev, pm_message_t state) +static int wbsd_suspend(struct wbsd_host *host, pm_message_t state) +{ + BUG_ON(host == NULL); + + return mmc_suspend_host(host->mmc, state); +} + +static int wbsd_resume(struct wbsd_host *host) +{ + BUG_ON(host == NULL); + + wbsd_init_device(host); + + return mmc_resume_host(host->mmc); +} + +static int wbsd_platform_suspend(struct platform_device *dev, pm_message_t state) { struct mmc_host *mmc = platform_get_drvdata(dev); struct wbsd_host *host; int ret; - if (!mmc) + if (mmc == NULL) return 0; - DBG("Suspending...\n"); - - ret = mmc_suspend_host(mmc, state); - if (!ret) - return ret; + DBGF("Suspending...\n"); host = mmc_priv(mmc); + ret = wbsd_suspend(host, state); + if (ret) + return ret; + wbsd_chip_poweroff(host); return 0; } -static int wbsd_resume(struct platform_device *dev) +static int wbsd_platform_resume(struct platform_device *dev) { struct mmc_host *mmc = platform_get_drvdata(dev); struct wbsd_host *host; - if (!mmc) + if (mmc == NULL) return 0; - DBG("Resuming...\n"); + DBGF("Resuming...\n"); host = mmc_priv(mmc); @@ -2021,15 +2037,70 @@ static int wbsd_resume(struct platform_device *dev) */ mdelay(5); - wbsd_init_device(host); + return wbsd_resume(host); +} + +#ifdef CONFIG_PNP + +static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state) +{ + struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); + struct wbsd_host *host; + + if (mmc == NULL) + return 0; - return mmc_resume_host(mmc); + DBGF("Suspending...\n"); + + host = mmc_priv(mmc); + + return wbsd_suspend(host, state); } +static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) +{ + struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); + struct wbsd_host *host; + + if (mmc == NULL) + return 0; + + DBGF("Resuming...\n"); + + host = mmc_priv(mmc); + + /* + * See if chip needs to be configured. + */ + if (host->config != 0) + { + if (!wbsd_chip_validate(host)) + { + printk(KERN_WARNING DRIVER_NAME + ": PnP active but chip not configured! " + "You probably have a buggy BIOS. " + "Configuring chip manually.\n"); + wbsd_chip_config(host); + } + } + + /* + * Allow device to initialise itself properly. + */ + mdelay(5); + + return wbsd_resume(host); +} + +#endif /* CONFIG_PNP */ + #else /* CONFIG_PM */ -#define wbsd_suspend NULL -#define wbsd_resume NULL +#define wbsd_platform_suspend NULL +#define wbsd_platform_resume NULL + +#define wbsd_pnp_suspend NULL +#define wbsd_pnp_resume NULL #endif /* CONFIG_PM */ @@ -2039,8 +2110,8 @@ static struct platform_driver wbsd_driver = { .probe = wbsd_probe, .remove = __devexit_p(wbsd_remove), - .suspend = wbsd_suspend, - .resume = wbsd_resume, + .suspend = wbsd_platform_suspend, + .resume = wbsd_platform_resume, .driver = { .name = DRIVER_NAME, }, @@ -2053,6 +2124,9 @@ static struct pnp_driver wbsd_pnp_driver = { .id_table = pnp_dev_table, .probe = wbsd_pnp_probe, .remove = __devexit_p(wbsd_pnp_remove), + + .suspend = wbsd_pnp_suspend, + .resume = wbsd_pnp_resume, }; #endif /* CONFIG_PNP */ -- cgit v1.2.3 From cb757b4eefd4600a3afa58f6983addbbe82989a8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 8 Jan 2006 14:23:02 +0000 Subject: [MMC] Support MMC version 4 cards Version 4 of the MMC specification increased the version number of the CID structure. None of the fields changed though so the only required change is adding '4' to the approved list. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/mmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6696f71363b9..bfca5c176e88 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -495,6 +495,7 @@ static void mmc_decode_cid(struct mmc_card *card) case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ + case 4: /* MMC v4 */ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); -- cgit v1.2.3 From ae215b14bdbd459afe5f371175765fae817062a8 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 8 Jan 2006 18:39:44 +0100 Subject: kconfig: factor out ncurses check in a shell script Cleaning up the lxdialog Makefile by factoring out the ncurses compatibility checks. This made the checks much more obvious and easier to extend. Signed-off-by: Sam Ravnborg --- scripts/kconfig/lxdialog/Makefile | 48 ++++++--------------- scripts/kconfig/lxdialog/check-lxdialog.sh | 67 ++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 36 deletions(-) create mode 100644 scripts/kconfig/lxdialog/check-lxdialog.sh diff --git a/scripts/kconfig/lxdialog/Makefile b/scripts/kconfig/lxdialog/Makefile index a45a13fb26ed..8f41d9a57aaa 100644 --- a/scripts/kconfig/lxdialog/Makefile +++ b/scripts/kconfig/lxdialog/Makefile @@ -1,42 +1,18 @@ -HOST_EXTRACFLAGS := -DLOCALE -ifeq ($(shell uname),SunOS) -HOST_LOADLIBES := -lcurses -else -HOST_LOADLIBES := -lncurses -endif +# Makefile to build lxdialog package +# -ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h)) - HOST_EXTRACFLAGS += -I/usr/include/ncurses -DCURSES_LOC="" -else -ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h)) - HOST_EXTRACFLAGS += -I/usr/include/ncurses -DCURSES_LOC="" -else -ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h)) - HOST_EXTRACFLAGS += -DCURSES_LOC="" -else - HOST_EXTRACFLAGS += -DCURSES_LOC="" -endif -endif -endif +check-lxdialog := $(srctree)/$(src)/check-lxdialog.sh +HOST_EXTRACFLAGS := $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) +HOST_LOADLIBES := $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags) + +HOST_EXTRACFLAGS += -DLOCALE + +.PHONY: dochecklxdialog +$(obj)/dochecklxdialog: + $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_LOADLIBES) hostprogs-y := lxdialog -always := ncurses $(hostprogs-y) +always := $(hostprogs-y) dochecklxdialog lxdialog-objs := checklist.o menubox.o textbox.o yesno.o inputbox.o \ util.o lxdialog.o msgbox.o - -.PHONY: $(obj)/ncurses -$(obj)/ncurses: - @echo "main() {}" > lxtemp.c - @if $(HOSTCC) lxtemp.c $(HOST_LOADLIBES); then \ - rm -f lxtemp.c a.out; \ - else \ - rm -f lxtemp.c; \ - echo -e "\007" ;\ - echo ">> Unable to find the Ncurses libraries." ;\ - echo ">>" ;\ - echo ">> You must install ncurses-devel in order" ;\ - echo ">> to use 'make menuconfig'" ;\ - echo ;\ - exit 1 ;\ - fi diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh new file mode 100644 index 000000000000..a3c141b49670 --- /dev/null +++ b/scripts/kconfig/lxdialog/check-lxdialog.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# Check ncurses compatibility + +# What library to link +ldflags() +{ + if [ `uname` == SunOS ]; then + echo '-lcurses' + else + echo '-lncurses' + fi +} + +# Where is ncurses.h? +ccflags() +{ + if [ -f /usr/include/ncurses/ncurses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses/curses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses.h ]; then + echo '-DCURSES_LOC=""' + else + echo '-DCURSES_LOC=""' + fi +} + +compiler="" +# Check if we can link to ncurses +check() { + echo "main() {}" | $compiler -xc - + if [ $? != 0 ]; then + echo " *** Unable to find the ncurses libraries." 1>&2 + echo " *** make menuconfig require the ncurses libraries" 1>&2 + echo " *** " 1>&2 + echo " *** Install ncurses (ncurses-devel) and try again" 1>&2 + echo " *** " 1>&2 + exit 1 + fi +} + +usage() { + printf "Usage: $0 [-check compiler options|-header|-library]\n" +} + +if [ $# == 0 ]; then + usage + exit 1 +fi + +case "$1" in + "-check") + shift + compiler="$@" + check + ;; + "-ccflags") + ccflags + ;; + "-ldflags") + ldflags + ;; + "*") + usage + exit 1 + ;; +esac -- cgit v1.2.3 From ac448afbcdcc218fd8d177960466ecc4a523722f Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Fri, 6 Jan 2006 18:28:45 -0500 Subject: kbuild: clean up asm-offsets.h creation - Move mkdir out of cmd_offsets - Add input file to sed command instead of using cat Signed-off-by: Brian Gerst Signed-off-by: Sam Ravnborg --- Kbuild | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Kbuild b/Kbuild index 79003918f37f..95d6a00bace0 100644 --- a/Kbuild +++ b/Kbuild @@ -22,8 +22,6 @@ sed-$(CONFIG_MIPS) := "/^@@@/s///p" quiet_cmd_offsets = GEN $@ define cmd_offsets - mkdir -p $(dir $@); \ - cat $< | \ (set -e; \ echo "#ifndef __ASM_OFFSETS_H__"; \ echo "#define __ASM_OFFSETS_H__"; \ @@ -34,7 +32,7 @@ define cmd_offsets echo " *"; \ echo " */"; \ echo ""; \ - sed -ne $(sed-y); \ + sed -ne $(sed-y) $<; \ echo ""; \ echo "#endif" ) > $@ endef @@ -45,5 +43,6 @@ arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE $(call if_changed_dep,cc_s_c) $(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild + $(Q)mkdir -p $(dir $@) $(call cmd,offsets) -- cgit v1.2.3 From cc6fa432f5eec26c43fd06c0314cb1c2cae6d9a1 Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Sun, 8 Jan 2006 10:53:55 -0500 Subject: modpost/file2alias: Fix typo SND_MAX should be FF_MAX Signed-off-by: Brian Gerst Signed-off-by: Sam Ravnborg --- scripts/mod/file2alias.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index e0eedffe565b..be97caf664bb 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -417,7 +417,7 @@ static int do_input_entry(const char *filename, struct input_device_id *id, do_input(alias, id->sndbit, 0, SND_MAX); sprintf(alias + strlen(alias), "f*"); if (id->flags&INPUT_DEVICE_ID_MATCH_FFBIT) - do_input(alias, id->ffbit, 0, SND_MAX); + do_input(alias, id->ffbit, 0, FF_MAX); sprintf(alias + strlen(alias), "w*"); if (id->flags&INPUT_DEVICE_ID_MATCH_SWBIT) do_input(alias, id->swbit, 0, SW_MAX); -- cgit v1.2.3 From 24d49756aa67322c2def5dc97344615572ac454e Mon Sep 17 00:00:00 2001 From: Ryan Anderson Date: Sun, 8 Jan 2006 04:35:36 -0500 Subject: kbuild: In setlocalversion change -git_dirty to just -dirty When building Debian packages directly from the git tree, the appended "git_dirty" is a problem due to the underscore. In order to cause the least problems, change that just to "dirty". Signed-off-by: Ryan Anderson Signed-off-by: Sam Ravnborg --- scripts/setlocalversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index f54dac88cfd1..9a23825218f2 100644 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -17,6 +17,6 @@ if head=`git rev-parse --verify HEAD 2>/dev/null`; then # Are there uncommitted changes? if git diff-files | read dummy; then - printf '%s' -git_dirty + printf '%s' -dirty fi fi -- cgit v1.2.3 From 50aa88e2877f1375ba79d1be7a0ff4aa563741c7 Mon Sep 17 00:00:00 2001 From: Tore Anderson Date: Sat, 7 Jan 2006 15:34:40 +0100 Subject: kbuild: ensure mrproper removes .old_version If the final linking of vmlinux fails, the file .old_version are left behind. This patch ensures the mrproper target will remove it if present. Signed-off-by: Tore Anderson Signed-off-by: Sam Ravnborg --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 599e744d3e33..50b07fa665e5 100644 --- a/Makefile +++ b/Makefile @@ -984,7 +984,7 @@ CLEAN_FILES += vmlinux System.map \ # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include2 -MRPROPER_FILES += .config .config.old include/asm .version \ +MRPROPER_FILES += .config .config.old include/asm .version .old_version \ include/linux/autoconf.h include/linux/version.h \ Module.symvers tags TAGS cscope* -- cgit v1.2.3 From 442ce844e139c1e3c23e8b4df13468041ae35721 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 6 Jan 2006 02:40:19 -0500 Subject: kbuild: reference_discarded addition Error: ./fs/quota_v2.o .opd refers to 0000000000000020 R_PPC64_ADDR64 .exit.text Been carrying this for some time in Red Hat trees. Keith Ownes commented: For our future {in}sanity, add a comment that this is the ppc .opd section, not the ia64 .opd section. ia64 .opd should not point to discarded sections. Any idea why ppc .opd points to discarded sections when ia64 does not? AFAICT no ia64 object has a useful .opd section, they are all empty or (sometimes) a dummy entry which is 1 byte long. ia64 .opd data is built at link time, not compile time. Signed-off-by: Dave Jones Signed-off-by: Sam Ravnborg --- scripts/reference_discarded.pl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/reference_discarded.pl b/scripts/reference_discarded.pl index c2d54148a91f..4ee6ab2135b3 100644 --- a/scripts/reference_discarded.pl +++ b/scripts/reference_discarded.pl @@ -71,6 +71,11 @@ foreach $object (keys(%object)) { # printf("ignoring %d conglomerate(s)\n", $ignore); # printf("Scanning objects\n"); + +# Keith Ownes commented: +# For our future {in}sanity, add a comment that this is the ppc .opd +# section, not the ia64 .opd section. +# ia64 .opd should not point to discarded sections. $errorcount = 0; foreach $object (keys(%object)) { my $from; @@ -88,6 +93,7 @@ foreach $object (keys(%object)) { ($from !~ /\.text\.exit$/ && $from !~ /\.exit\.text$/ && $from !~ /\.data\.exit$/ && + $from !~ /\.opd$/ && $from !~ /\.exit\.data$/ && $from !~ /\.altinstructions$/ && $from !~ /\.pdr$/ && -- cgit v1.2.3 From cfa7f52164d6cdcb6cea87386562c568da66ff9e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 8 Jan 2006 18:17:55 +0000 Subject: [MMC] Lindent wbsd driver Fix the coding style in the wbsd driver once and for all. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 437 +++++++++++++++++++++++------------------------------ 1 file changed, 185 insertions(+), 252 deletions(-) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 60afc1235120..f25757625361 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -90,7 +90,7 @@ static int dma = 2; * Basic functions */ -static inline void wbsd_unlock_config(struct wbsd_host* host) +static inline void wbsd_unlock_config(struct wbsd_host *host) { BUG_ON(host->config == 0); @@ -98,14 +98,14 @@ static inline void wbsd_unlock_config(struct wbsd_host* host) outb(host->unlock_code, host->config); } -static inline void wbsd_lock_config(struct wbsd_host* host) +static inline void wbsd_lock_config(struct wbsd_host *host) { BUG_ON(host->config == 0); outb(LOCK_CODE, host->config); } -static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) +static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value) { BUG_ON(host->config == 0); @@ -113,7 +113,7 @@ static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) outb(value, host->config + 1); } -static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) +static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg) { BUG_ON(host->config == 0); @@ -121,13 +121,13 @@ static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) return inb(host->config + 1); } -static inline void wbsd_write_index(struct wbsd_host* host, u8 index, u8 value) +static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value) { outb(index, host->base + WBSD_IDXR); outb(value, host->base + WBSD_DATAR); } -static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index) +static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index) { outb(index, host->base + WBSD_IDXR); return inb(host->base + WBSD_DATAR); @@ -137,7 +137,7 @@ static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index) * Common routines */ -static void wbsd_init_device(struct wbsd_host* host) +static void wbsd_init_device(struct wbsd_host *host) { u8 setup, ier; @@ -197,7 +197,7 @@ static void wbsd_init_device(struct wbsd_host* host) inb(host->base + WBSD_ISR); } -static void wbsd_reset(struct wbsd_host* host) +static void wbsd_reset(struct wbsd_host *host) { u8 setup; @@ -211,14 +211,13 @@ static void wbsd_reset(struct wbsd_host* host) wbsd_write_index(host, WBSD_IDX_SETUP, setup); } -static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq) +static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq) { unsigned long dmaflags; DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode); - if (host->dma >= 0) - { + if (host->dma >= 0) { /* * Release ISA DMA controller. */ @@ -247,7 +246,7 @@ static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq) * Scatter/gather functions */ -static inline void wbsd_init_sg(struct wbsd_host* host, struct mmc_data* data) +static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data) { /* * Get info. about SG list from data structure. @@ -259,7 +258,7 @@ static inline void wbsd_init_sg(struct wbsd_host* host, struct mmc_data* data) host->remain = host->cur_sg->length; } -static inline int wbsd_next_sg(struct wbsd_host* host) +static inline int wbsd_next_sg(struct wbsd_host *host) { /* * Skip to next SG entry. @@ -270,33 +269,32 @@ static inline int wbsd_next_sg(struct wbsd_host* host) /* * Any entries left? */ - if (host->num_sg > 0) - { - host->offset = 0; - host->remain = host->cur_sg->length; - } + if (host->num_sg > 0) { + host->offset = 0; + host->remain = host->cur_sg->length; + } return host->num_sg; } -static inline char* wbsd_kmap_sg(struct wbsd_host* host) +static inline char *wbsd_kmap_sg(struct wbsd_host *host) { host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) + host->cur_sg->offset; return host->mapped_sg; } -static inline void wbsd_kunmap_sg(struct wbsd_host* host) +static inline void wbsd_kunmap_sg(struct wbsd_host *host) { kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); } -static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data) +static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) { unsigned int len, i, size; - struct scatterlist* sg; - char* dmabuf = host->dma_buffer; - char* sgbuf; + struct scatterlist *sg; + char *dmabuf = host->dma_buffer; + char *sgbuf; size = host->size; @@ -308,8 +306,7 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data) * be the entire list though so make sure that * we do not transfer too much. */ - for (i = 0;i < len;i++) - { + for (i = 0; i < len; i++) { sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; if (size < sg[i].length) memcpy(dmabuf, sgbuf, size); @@ -337,12 +334,12 @@ static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data) host->size -= size; } -static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data) +static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) { unsigned int len, i, size; - struct scatterlist* sg; - char* dmabuf = host->dma_buffer; - char* sgbuf; + struct scatterlist *sg; + char *dmabuf = host->dma_buffer; + char *sgbuf; size = host->size; @@ -354,8 +351,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data) * be the entire list though so make sure that * we do not transfer too much. */ - for (i = 0;i < len;i++) - { + for (i = 0; i < len; i++) { sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; if (size < sg[i].length) memcpy(sgbuf, dmabuf, size); @@ -387,46 +383,38 @@ static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data) * Command handling */ -static inline void wbsd_get_short_reply(struct wbsd_host* host, - struct mmc_command* cmd) +static inline void wbsd_get_short_reply(struct wbsd_host *host, + struct mmc_command *cmd) { /* * Correct response type? */ - if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) - { + if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) { cmd->error = MMC_ERR_INVALID; return; } - cmd->resp[0] = - wbsd_read_index(host, WBSD_IDX_RESP12) << 24; - cmd->resp[0] |= - wbsd_read_index(host, WBSD_IDX_RESP13) << 16; - cmd->resp[0] |= - wbsd_read_index(host, WBSD_IDX_RESP14) << 8; - cmd->resp[0] |= - wbsd_read_index(host, WBSD_IDX_RESP15) << 0; - cmd->resp[1] = - wbsd_read_index(host, WBSD_IDX_RESP16) << 24; + cmd->resp[0] = wbsd_read_index(host, WBSD_IDX_RESP12) << 24; + cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16; + cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8; + cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0; + cmd->resp[1] = wbsd_read_index(host, WBSD_IDX_RESP16) << 24; } -static inline void wbsd_get_long_reply(struct wbsd_host* host, - struct mmc_command* cmd) +static inline void wbsd_get_long_reply(struct wbsd_host *host, + struct mmc_command *cmd) { int i; /* * Correct response type? */ - if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) - { + if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) { cmd->error = MMC_ERR_INVALID; return; } - for (i = 0;i < 4;i++) - { + for (i = 0; i < 4; i++) { cmd->resp[i] = wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24; cmd->resp[i] |= @@ -438,7 +426,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, } } -static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) +static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd) { int i; u8 status, isr; @@ -456,7 +444,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) * Send the command (CRC calculated by host). */ outb(cmd->opcode, host->base + WBSD_CMDR); - for (i = 3;i >= 0;i--) + for (i = 3; i >= 0; i--) outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR); cmd->error = MMC_ERR_NONE; @@ -471,8 +459,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) /* * Do we expect a reply? */ - if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE) - { + if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE) { /* * Read back status. */ @@ -488,8 +475,7 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC)) cmd->error = MMC_ERR_BADCRC; /* All ok */ - else - { + else { if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT) wbsd_get_short_reply(host, cmd); else @@ -504,10 +490,10 @@ static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) * Data functions */ -static void wbsd_empty_fifo(struct wbsd_host* host) +static void wbsd_empty_fifo(struct wbsd_host *host) { - struct mmc_data* data = host->mrq->cmd->data; - char* buffer; + struct mmc_data *data = host->mrq->cmd->data; + char *buffer; int i, fsr, fifo; /* @@ -522,8 +508,7 @@ static void wbsd_empty_fifo(struct wbsd_host* host) * Drain the fifo. This has a tendency to loop longer * than the FIFO length (usually one block). */ - while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) - { + while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) { /* * The size field in the FSR is broken so we have to * do some guessing. @@ -535,8 +520,7 @@ static void wbsd_empty_fifo(struct wbsd_host* host) else fifo = 1; - for (i = 0;i < fifo;i++) - { + for (i = 0; i < fifo; i++) { *buffer = inb(host->base + WBSD_DFR); buffer++; host->offset++; @@ -547,8 +531,7 @@ static void wbsd_empty_fifo(struct wbsd_host* host) /* * Transfer done? */ - if (data->bytes_xfered == host->size) - { + if (data->bytes_xfered == host->size) { wbsd_kunmap_sg(host); return; } @@ -556,15 +539,13 @@ static void wbsd_empty_fifo(struct wbsd_host* host) /* * End of scatter list entry? */ - if (host->remain == 0) - { + if (host->remain == 0) { wbsd_kunmap_sg(host); /* * Get next entry. Check if last. */ - if (!wbsd_next_sg(host)) - { + if (!wbsd_next_sg(host)) { /* * We should never reach this point. * It means that we're trying to @@ -594,10 +575,10 @@ static void wbsd_empty_fifo(struct wbsd_host* host) tasklet_schedule(&host->fifo_tasklet); } -static void wbsd_fill_fifo(struct wbsd_host* host) +static void wbsd_fill_fifo(struct wbsd_host *host) { - struct mmc_data* data = host->mrq->cmd->data; - char* buffer; + struct mmc_data *data = host->mrq->cmd->data; + char *buffer; int i, fsr, fifo; /* @@ -613,8 +594,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) * Fill the fifo. This has a tendency to loop longer * than the FIFO length (usually one block). */ - while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) - { + while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) { /* * The size field in the FSR is broken so we have to * do some guessing. @@ -626,8 +606,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) else fifo = 15; - for (i = 16;i > fifo;i--) - { + for (i = 16; i > fifo; i--) { outb(*buffer, host->base + WBSD_DFR); buffer++; host->offset++; @@ -638,8 +617,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) /* * Transfer done? */ - if (data->bytes_xfered == host->size) - { + if (data->bytes_xfered == host->size) { wbsd_kunmap_sg(host); return; } @@ -647,15 +625,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host) /* * End of scatter list entry? */ - if (host->remain == 0) - { + if (host->remain == 0) { wbsd_kunmap_sg(host); /* * Get next entry. Check if last. */ - if (!wbsd_next_sg(host)) - { + if (!wbsd_next_sg(host)) { /* * We should never reach this point. * It means that we're trying to @@ -684,7 +660,7 @@ static void wbsd_fill_fifo(struct wbsd_host* host) tasklet_schedule(&host->fifo_tasklet); } -static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) +static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) { u16 blksize; u8 setup; @@ -706,8 +682,10 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) */ if (data->timeout_ns > 127000000) wbsd_write_index(host, WBSD_IDX_TAAC, 127); - else - wbsd_write_index(host, WBSD_IDX_TAAC, data->timeout_ns/1000000); + else { + wbsd_write_index(host, WBSD_IDX_TAAC, + data->timeout_ns / 1000000); + } if (data->timeout_clks > 255) wbsd_write_index(host, WBSD_IDX_NSAC, 255); @@ -722,23 +700,18 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) * Space for CRC must be included in the size. * Two bytes are needed for each data line. */ - if (host->bus_width == MMC_BUS_WIDTH_1) - { + if (host->bus_width == MMC_BUS_WIDTH_1) { blksize = (1 << data->blksz_bits) + 2; wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); - } - else if (host->bus_width == MMC_BUS_WIDTH_4) - { + } else if (host->bus_width == MMC_BUS_WIDTH_4) { blksize = (1 << data->blksz_bits) + 2 * 4; - wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0) - | WBSD_DATA_WIDTH); + wbsd_write_index(host, WBSD_IDX_PBSMSB, + ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); - } - else - { + } else { data->error = MMC_ERR_INVALID; return; } @@ -755,14 +728,12 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) /* * DMA transfer? */ - if (host->dma >= 0) - { + if (host->dma >= 0) { /* * The buffer for DMA is only 64 kB. */ BUG_ON(host->size > 0x10000); - if (host->size > 0x10000) - { + if (host->size > 0x10000) { data->error = MMC_ERR_INVALID; return; } @@ -794,9 +765,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) * Enable DMA on the host. */ wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE); - } - else - { + } else { /* * This flag is used to keep printk * output to a minimum. @@ -817,13 +786,10 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) * Set up FIFO threshold levels (and fill * buffer if doing a write). */ - if (data->flags & MMC_DATA_READ) - { + if (data->flags & MMC_DATA_READ) { wbsd_write_index(host, WBSD_IDX_FIFOEN, WBSD_FIFOEN_FULL | 8); - } - else - { + } else { wbsd_write_index(host, WBSD_IDX_FIFOEN, WBSD_FIFOEN_EMPTY | 8); wbsd_fill_fifo(host); @@ -833,7 +799,7 @@ static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) data->error = MMC_ERR_NONE; } -static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) +static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) { unsigned long dmaflags; int count; @@ -851,16 +817,14 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) * Wait for the controller to leave data * transfer state. */ - do - { + do { status = wbsd_read_index(host, WBSD_IDX_STATUS); } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE)); /* * DMA transfer? */ - if (host->dma >= 0) - { + if (host->dma >= 0) { /* * Disable DMA on the host. */ @@ -878,16 +842,13 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) /* * Any leftover data? */ - if (count) - { + if (count) { printk(KERN_ERR "%s: Incomplete DMA transfer. " "%d bytes left.\n", mmc_hostname(host->mmc), count); data->error = MMC_ERR_FAILED; - } - else - { + } else { /* * Transfer data from DMA buffer to * SG list. @@ -910,10 +871,10 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) * * \*****************************************************************************/ -static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) +static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) { - struct wbsd_host* host = mmc_priv(mmc); - struct mmc_command* cmd; + struct wbsd_host *host = mmc_priv(mmc); + struct mmc_command *cmd; /* * Disable tasklets to avoid a deadlock. @@ -930,8 +891,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) * If there is no card in the slot then * timeout immediatly. */ - if (!(host->flags & WBSD_FCARD_PRESENT)) - { + if (!(host->flags & WBSD_FCARD_PRESENT)) { cmd->error = MMC_ERR_TIMEOUT; goto done; } @@ -939,8 +899,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) /* * Does the request include data? */ - if (cmd->data) - { + if (cmd->data) { wbsd_prepare_data(host, cmd->data); if (cmd->data->error != MMC_ERR_NONE) @@ -954,8 +913,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) * will be finished after the data has * transfered. */ - if (cmd->data && (cmd->error == MMC_ERR_NONE)) - { + if (cmd->data && (cmd->error == MMC_ERR_NONE)) { /* * Dirty fix for hardware bug. */ @@ -973,14 +931,14 @@ done: spin_unlock_bh(&host->lock); } -static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) +static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { - struct wbsd_host* host = mmc_priv(mmc); + struct wbsd_host *host = mmc_priv(mmc); u8 clk, setup, pwr; DBGF("clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", - ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, - ios->vdd, ios->bus_width); + ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, + ios->vdd, ios->bus_width); spin_lock_bh(&host->lock); @@ -1004,8 +962,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) * Only write to the clock register when * there is an actual change. */ - if (clk != host->clk) - { + if (clk != host->clk) { wbsd_write_index(host, WBSD_IDX_CLK, clk); host->clk = clk; } @@ -1013,8 +970,7 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) /* * Power up card. */ - if (ios->power_mode != MMC_POWER_OFF) - { + if (ios->power_mode != MMC_POWER_OFF) { pwr = inb(host->base + WBSD_CSR); pwr &= ~WBSD_POWER_N; outb(pwr, host->base + WBSD_CSR); @@ -1026,23 +982,19 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) * that needs to be disabled. */ setup = wbsd_read_index(host, WBSD_IDX_SETUP); - if (ios->chip_select == MMC_CS_HIGH) - { + if (ios->chip_select == MMC_CS_HIGH) { BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1); setup |= WBSD_DAT3_H; host->flags |= WBSD_FIGNORE_DETECT; - } - else - { - if (setup & WBSD_DAT3_H) - { + } else { + if (setup & WBSD_DAT3_H) { setup &= ~WBSD_DAT3_H; /* * We cannot resume card detection immediatly * because of capacitance and delays in the chip. */ - mod_timer(&host->ignore_timer, jiffies + HZ/100); + mod_timer(&host->ignore_timer, jiffies + HZ / 100); } } wbsd_write_index(host, WBSD_IDX_SETUP, setup); @@ -1056,9 +1008,9 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) spin_unlock_bh(&host->lock); } -static int wbsd_get_ro(struct mmc_host* mmc) +static int wbsd_get_ro(struct mmc_host *mmc) { - struct wbsd_host* host = mmc_priv(mmc); + struct wbsd_host *host = mmc_priv(mmc); u8 csr; spin_lock_bh(&host->lock); @@ -1096,7 +1048,7 @@ static struct mmc_host_ops wbsd_ops = { static void wbsd_reset_ignore(unsigned long data) { - struct wbsd_host *host = (struct wbsd_host*)data; + struct wbsd_host *host = (struct wbsd_host *)data; BUG_ON(host == NULL); @@ -1119,7 +1071,7 @@ static void wbsd_reset_ignore(unsigned long data) * Tasklets */ -static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host) +static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host) { WARN_ON(!host->mrq); if (!host->mrq) @@ -1138,14 +1090,13 @@ static inline struct mmc_data* wbsd_get_data(struct wbsd_host* host) static void wbsd_tasklet_card(unsigned long param) { - struct wbsd_host* host = (struct wbsd_host*)param; + struct wbsd_host *host = (struct wbsd_host *)param; u8 csr; int delay = -1; spin_lock(&host->lock); - if (host->flags & WBSD_FIGNORE_DETECT) - { + if (host->flags & WBSD_FIGNORE_DETECT) { spin_unlock(&host->lock); return; } @@ -1153,23 +1104,18 @@ static void wbsd_tasklet_card(unsigned long param) csr = inb(host->base + WBSD_CSR); WARN_ON(csr == 0xff); - if (csr & WBSD_CARDPRESENT) - { - if (!(host->flags & WBSD_FCARD_PRESENT)) - { + if (csr & WBSD_CARDPRESENT) { + if (!(host->flags & WBSD_FCARD_PRESENT)) { DBG("Card inserted\n"); host->flags |= WBSD_FCARD_PRESENT; delay = 500; } - } - else if (host->flags & WBSD_FCARD_PRESENT) - { + } else if (host->flags & WBSD_FCARD_PRESENT) { DBG("Card removed\n"); host->flags &= ~WBSD_FCARD_PRESENT; - if (host->mrq) - { + if (host->mrq) { printk(KERN_ERR "%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); wbsd_reset(host); @@ -1193,8 +1139,8 @@ static void wbsd_tasklet_card(unsigned long param) static void wbsd_tasklet_fifo(unsigned long param) { - struct wbsd_host* host = (struct wbsd_host*)param; - struct mmc_data* data; + struct wbsd_host *host = (struct wbsd_host *)param; + struct mmc_data *data; spin_lock(&host->lock); @@ -1213,8 +1159,7 @@ static void wbsd_tasklet_fifo(unsigned long param) /* * Done? */ - if (host->size == data->bytes_xfered) - { + if (host->size == data->bytes_xfered) { wbsd_write_index(host, WBSD_IDX_FIFOEN, 0); tasklet_schedule(&host->finish_tasklet); } @@ -1225,8 +1170,8 @@ end: static void wbsd_tasklet_crc(unsigned long param) { - struct wbsd_host* host = (struct wbsd_host*)param; - struct mmc_data* data; + struct wbsd_host *host = (struct wbsd_host *)param; + struct mmc_data *data; spin_lock(&host->lock); @@ -1249,8 +1194,8 @@ end: static void wbsd_tasklet_timeout(unsigned long param) { - struct wbsd_host* host = (struct wbsd_host*)param; - struct mmc_data* data; + struct wbsd_host *host = (struct wbsd_host *)param; + struct mmc_data *data; spin_lock(&host->lock); @@ -1273,8 +1218,8 @@ end: static void wbsd_tasklet_finish(unsigned long param) { - struct wbsd_host* host = (struct wbsd_host*)param; - struct mmc_data* data; + struct wbsd_host *host = (struct wbsd_host *)param; + struct mmc_data *data; spin_lock(&host->lock); @@ -1294,14 +1239,13 @@ end: static void wbsd_tasklet_block(unsigned long param) { - struct wbsd_host* host = (struct wbsd_host*)param; - struct mmc_data* data; + struct wbsd_host *host = (struct wbsd_host *)param; + struct mmc_data *data; spin_lock(&host->lock); if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) != - WBSD_CRC_OK) - { + WBSD_CRC_OK) { data = wbsd_get_data(host); if (!data) goto end; @@ -1323,7 +1267,7 @@ end: static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) { - struct wbsd_host* host = dev_id; + struct wbsd_host *host = dev_id; int isr; isr = inb(host->base + WBSD_ISR); @@ -1365,10 +1309,10 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) * Allocate/free MMC structure. */ -static int __devinit wbsd_alloc_mmc(struct device* dev) +static int __devinit wbsd_alloc_mmc(struct device *dev) { - struct mmc_host* mmc; - struct wbsd_host* host; + struct mmc_host *mmc; + struct wbsd_host *host; /* * Allocate MMC structure. @@ -1388,7 +1332,7 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) mmc->ops = &wbsd_ops; mmc->f_min = 375000; mmc->f_max = 24000000; - mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->caps = MMC_CAP_4_BIT_DATA; spin_lock_init(&host->lock); @@ -1424,10 +1368,10 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) return 0; } -static void __devexit wbsd_free_mmc(struct device* dev) +static void __devexit wbsd_free_mmc(struct device *dev) { - struct mmc_host* mmc; - struct wbsd_host* host; + struct mmc_host *mmc; + struct wbsd_host *host; mmc = dev_get_drvdata(dev); if (!mmc) @@ -1447,7 +1391,7 @@ static void __devexit wbsd_free_mmc(struct device* dev) * Scan for known chip id:s */ -static int __devinit wbsd_scan(struct wbsd_host* host) +static int __devinit wbsd_scan(struct wbsd_host *host) { int i, j, k; int id; @@ -1477,16 +1421,14 @@ static int __devinit wbsd_scan(struct wbsd_host* host) wbsd_lock_config(host); for (k = 0; k < ARRAY_SIZE(valid_ids); k++) { - if (id == valid_ids[k]) - { + if (id == valid_ids[k]) { host->chip_id = id; return 0; } } - if (id != 0xFFFF) - { + if (id != 0xFFFF) { DBG("Unknown hardware (id %x) found at %x\n", id, config_ports[i]); } @@ -1505,7 +1447,7 @@ static int __devinit wbsd_scan(struct wbsd_host* host) * Allocate/free io port ranges */ -static int __devinit wbsd_request_region(struct wbsd_host* host, int base) +static int __devinit wbsd_request_region(struct wbsd_host *host, int base) { if (io & 0x7) return -EINVAL; @@ -1518,7 +1460,7 @@ static int __devinit wbsd_request_region(struct wbsd_host* host, int base) return 0; } -static void __devexit wbsd_release_regions(struct wbsd_host* host) +static void __devexit wbsd_release_regions(struct wbsd_host *host) { if (host->base) release_region(host->base, 8); @@ -1535,7 +1477,7 @@ static void __devexit wbsd_release_regions(struct wbsd_host* host) * Allocate/free DMA port and buffer */ -static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) +static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) { if (dma < 0) return; @@ -1579,8 +1521,8 @@ kfree: */ BUG_ON(1); - dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_single(host->mmc->dev, host->dma_addr, + WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); host->dma_addr = (dma_addr_t)NULL; kfree(host->dma_buffer); @@ -1594,11 +1536,12 @@ err: "Falling back on FIFO.\n", dma); } -static void __devexit wbsd_release_dma(struct wbsd_host* host) +static void __devexit wbsd_release_dma(struct wbsd_host *host) { - if (host->dma_addr) - dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, - DMA_BIDIRECTIONAL); + if (host->dma_addr) { + dma_unmap_single(host->mmc->dev, host->dma_addr, + WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); + } kfree(host->dma_buffer); if (host->dma >= 0) free_dma(host->dma); @@ -1612,7 +1555,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host) * Allocate/free IRQ. */ -static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) +static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) { int ret; @@ -1629,17 +1572,23 @@ static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) /* * Set up tasklets. */ - tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); - tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); - tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); - tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); - tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); - tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); + tasklet_init(&host->card_tasklet, wbsd_tasklet_card, + (unsigned long)host); + tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, + (unsigned long)host); + tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, + (unsigned long)host); + tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, + (unsigned long)host); + tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, + (unsigned long)host); + tasklet_init(&host->block_tasklet, wbsd_tasklet_block, + (unsigned long)host); return 0; } -static void __devexit wbsd_release_irq(struct wbsd_host* host) +static void __devexit wbsd_release_irq(struct wbsd_host *host) { if (!host->irq) return; @@ -1660,7 +1609,7 @@ static void __devexit wbsd_release_irq(struct wbsd_host* host) * Allocate all resources for the host. */ -static int __devinit wbsd_request_resources(struct wbsd_host* host, +static int __devinit wbsd_request_resources(struct wbsd_host *host, int base, int irq, int dma) { int ret; @@ -1691,7 +1640,7 @@ static int __devinit wbsd_request_resources(struct wbsd_host* host, * Release all resources for the host. */ -static void __devexit wbsd_release_resources(struct wbsd_host* host) +static void __devexit wbsd_release_resources(struct wbsd_host *host) { wbsd_release_dma(host); wbsd_release_irq(host); @@ -1702,7 +1651,7 @@ static void __devexit wbsd_release_resources(struct wbsd_host* host) * Configure the resources the chip should use. */ -static void wbsd_chip_config(struct wbsd_host* host) +static void wbsd_chip_config(struct wbsd_host *host) { wbsd_unlock_config(host); @@ -1746,7 +1695,7 @@ static void wbsd_chip_config(struct wbsd_host* host) * Check that configured resources are correct. */ -static int wbsd_chip_validate(struct wbsd_host* host) +static int wbsd_chip_validate(struct wbsd_host *host) { int base, irq, dma; @@ -1786,7 +1735,7 @@ static int wbsd_chip_validate(struct wbsd_host* host) * Powers down the SD function */ -static void wbsd_chip_poweroff(struct wbsd_host* host) +static void wbsd_chip_poweroff(struct wbsd_host *host) { wbsd_unlock_config(host); @@ -1802,11 +1751,11 @@ static void wbsd_chip_poweroff(struct wbsd_host* host) * * \*****************************************************************************/ -static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, +static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, int pnp) { - struct wbsd_host* host = NULL; - struct mmc_host* mmc = NULL; + struct wbsd_host *host = NULL; + struct mmc_host *mmc = NULL; int ret; ret = wbsd_alloc_mmc(dev); @@ -1820,16 +1769,12 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, * Scan for hardware. */ ret = wbsd_scan(host); - if (ret) - { - if (pnp && (ret == -ENODEV)) - { + if (ret) { + if (pnp && (ret == -ENODEV)) { printk(KERN_WARNING DRIVER_NAME ": Unable to confirm device presence. You may " "experience lock-ups.\n"); - } - else - { + } else { wbsd_free_mmc(dev); return ret; } @@ -1839,8 +1784,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, * Request resources. */ ret = wbsd_request_resources(host, io, irq, dma); - if (ret) - { + if (ret) { wbsd_release_resources(host); wbsd_free_mmc(dev); return ret; @@ -1849,18 +1793,15 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, /* * See if chip needs to be configured. */ - if (pnp) - { - if ((host->config != 0) && !wbsd_chip_validate(host)) - { + if (pnp) { + if ((host->config != 0) && !wbsd_chip_validate(host)) { printk(KERN_WARNING DRIVER_NAME ": PnP active but chip not configured! " "You probably have a buggy BIOS. " "Configuring chip manually.\n"); wbsd_chip_config(host); } - } - else + } else wbsd_chip_config(host); /* @@ -1868,8 +1809,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, * Not tested. */ #ifdef CONFIG_PM - if (host->config) - { + if (host->config) { wbsd_unlock_config(host); wbsd_write_config(host, WBSD_CONF_PME, 0xA0); wbsd_lock_config(host); @@ -1902,10 +1842,10 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, return 0; } -static void __devexit wbsd_shutdown(struct device* dev, int pnp) +static void __devexit wbsd_shutdown(struct device *dev, int pnp) { - struct mmc_host* mmc = dev_get_drvdata(dev); - struct wbsd_host* host; + struct mmc_host *mmc = dev_get_drvdata(dev); + struct wbsd_host *host; if (!mmc) return; @@ -1929,12 +1869,12 @@ static void __devexit wbsd_shutdown(struct device* dev, int pnp) * Non-PnP */ -static int __devinit wbsd_probe(struct platform_device* dev) +static int __devinit wbsd_probe(struct platform_device *dev) { return wbsd_init(&dev->dev, io, irq, dma, 0); } -static int __devexit wbsd_remove(struct platform_device* dev) +static int __devexit wbsd_remove(struct platform_device *dev) { wbsd_shutdown(&dev->dev, 0); @@ -1948,7 +1888,7 @@ static int __devexit wbsd_remove(struct platform_device* dev) #ifdef CONFIG_PNP static int __devinit -wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) +wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) { int io, irq, dma; @@ -1967,7 +1907,7 @@ wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) return wbsd_init(&pnpdev->dev, io, irq, dma, 1); } -static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) +static void __devexit wbsd_pnp_remove(struct pnp_dev *dev) { wbsd_shutdown(&dev->dev, 1); } @@ -1996,7 +1936,8 @@ static int wbsd_resume(struct wbsd_host *host) return mmc_resume_host(host->mmc); } -static int wbsd_platform_suspend(struct platform_device *dev, pm_message_t state) +static int wbsd_platform_suspend(struct platform_device *dev, + pm_message_t state) { struct mmc_host *mmc = platform_get_drvdata(dev); struct wbsd_host *host; @@ -2072,10 +2013,8 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) /* * See if chip needs to be configured. */ - if (host->config != 0) - { - if (!wbsd_chip_validate(host)) - { + if (host->config != 0) { + if (!wbsd_chip_validate(host)) { printk(KERN_WARNING DRIVER_NAME ": PnP active but chip not configured! " "You probably have a buggy BIOS. " @@ -2146,31 +2085,26 @@ static int __init wbsd_drv_init(void) #ifdef CONFIG_PNP - if (!nopnp) - { + if (!nopnp) { result = pnp_register_driver(&wbsd_pnp_driver); if (result < 0) return result; } - #endif /* CONFIG_PNP */ - if (nopnp) - { + if (nopnp) { result = platform_driver_register(&wbsd_driver); if (result < 0) return result; wbsd_device = platform_device_alloc(DRIVER_NAME, -1); - if (!wbsd_device) - { + if (!wbsd_device) { platform_driver_unregister(&wbsd_driver); return -ENOMEM; } result = platform_device_add(wbsd_device); - if (result) - { + if (result) { platform_device_put(wbsd_device); platform_driver_unregister(&wbsd_driver); return result; @@ -2189,8 +2123,7 @@ static void __exit wbsd_drv_exit(void) #endif /* CONFIG_PNP */ - if (nopnp) - { + if (nopnp) { platform_device_unregister(wbsd_device); platform_driver_unregister(&wbsd_driver); -- cgit v1.2.3 From ad14336de8e9cddae9ed29d45bd2e97abb72eaf9 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 8 Jan 2006 19:58:51 +0100 Subject: kbuild: remove GCC_VERSION This was causing some ordering problems. Remove the up-front evaluation and just revaluate the compiler version each time we need it. (The up-front evaluation was problematic because some architectures modify the value of $(CC)). Signed-off-by: Andrew Morton Signed-off-by: Sam Ravnborg --- Documentation/kbuild/makefiles.txt | 4 ++-- arch/i386/Makefile | 4 ++-- arch/ia64/Makefile | 7 +------ arch/powerpc/Makefile | 6 ++---- arch/ppc/Makefile | 3 +-- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index d802ce88bedc..443230b43e09 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -1033,9 +1033,9 @@ When kbuild executes the following steps are followed (roughly): Example: #arch/i386/Makefile - GCC_VERSION := $(call cc-version) cflags-y += $(shell \ - if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) + if [ $(call cc-version) -ge 0300 ] ; then \ + echo "-mregparm=3"; fi ;) In the above example -mregparm=3 is only used for gcc version greater than or equal to gcc 3.0. diff --git a/arch/i386/Makefile b/arch/i386/Makefile index d121ea18460f..8f6b90e44c9b 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -39,8 +39,8 @@ include $(srctree)/arch/i386/Makefile.cpu # -mregparm=3 works ok on gcc-3.0 and later # -GCC_VERSION := $(call cc-version) -cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) +cflags-$(CONFIG_REGPARM) += $(shell if [ $(call cc-version) -ge 0300 ] ; then \ + echo "-mregparm=3"; fi ;) # Disable unit-at-a-time mode, it makes gcc use a lot more stack # due to the lack of sharing of stacklots. diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 67932ad53082..f722e1a25948 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -25,7 +25,6 @@ cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \ -falign-functions=32 -frename-registers -fno-optimize-sibling-calls CFLAGS_KERNEL := -mconstant-gp -GCC_VERSION := $(call cc-version) GAS_STATUS = $(shell $(srctree)/arch/ia64/scripts/check-gas "$(CC)" "$(OBJDUMP)") CPPFLAGS += $(shell $(srctree)/arch/ia64/scripts/toolchain-flags "$(CC)" "$(OBJDUMP)" "$(READELF)") @@ -37,11 +36,7 @@ $(error Sorry, you need a newer version of the assember, one that is built from ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifneq ($(shell if [ $(GCC_VERSION) -lt 0300 ] ; then echo "bad"; fi ;),) -$(error Sorry, your compiler is too old. GCC v2.96 is known to generate bad code.) -endif - -ifeq ($(GCC_VERSION),0304) +ifeq ($(call cc-version),0304) cflags-$(CONFIG_ITANIUM) += -mtune=merced cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley endif diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a13eb575f834..b98f11b6b25d 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -76,8 +76,7 @@ LINUXINCLUDE += $(LINUXINCLUDE-y) CHECKFLAGS += -m$(SZ) -D__powerpc__ -D__powerpc$(SZ)__ ifeq ($(CONFIG_PPC64),y) -GCC_VERSION := $(call cc-version) -GCC_BROKEN_VEC := $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi) +GCC_BROKEN_VEC := $(shell if [ $(call cc-version) -lt 0400 ] ; then echo "y"; fi) ifeq ($(CONFIG_POWER4_ONLY),y) ifeq ($(CONFIG_ALTIVEC),y) @@ -189,10 +188,9 @@ TOUT := .tmp_gas_check # Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec # instructions. # gcc-3.4 and binutils-2.14 are a fatal combination. -GCC_VERSION := $(call cc-version) checkbin: - @if test "$(GCC_VERSION)" = "0304" ; then \ + @if test "$(call cc-version)" = "0304" ; then \ if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \ echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \ echo 'correctly with gcc-3.4 and your version of binutils.'; \ diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index e719a4933af1..98e940beeb3b 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -128,10 +128,9 @@ TOUT := .tmp_gas_check # Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec # instructions. # gcc-3.4 and binutils-2.14 are a fatal combination. -GCC_VERSION := $(call cc-version) checkbin: - @if test "$(GCC_VERSION)" = "0304" ; then \ + @if test "$(call cc-version)" = "0304" ; then \ if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \ echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \ echo 'correctly with gcc-3.4 and your version of binutils.'; \ -- cgit v1.2.3 From 63b794bfd898899cc8b6d4679d4fdc486606194b Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 8 Jan 2006 20:37:39 +0100 Subject: frv: Use KERNELRELEASE Signed-off-by: Sam Ravnborg --- arch/frv/boot/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/frv/boot/Makefile b/arch/frv/boot/Makefile index d75e0d771366..5dfc93fd945a 100644 --- a/arch/frv/boot/Makefile +++ b/arch/frv/boot/Makefile @@ -57,10 +57,10 @@ initrd: # installation # install: $(CONFIGURE) Image - sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh ./install.sh $(KERNELRELEASE) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" zinstall: $(CONFIGURE) zImage - sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh ./install.sh $(KERNELRELEASE) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" # # miscellany -- cgit v1.2.3 From 0fec53a24a5e5f7ba68d891b68f568b6aeafaca6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2006 22:37:46 +0000 Subject: [ARM] Remove EPXA10DB machine support EPXA10DB seems to be uncared for: - the "PLD" code has never been merged - no one has reported that this platform has been broken since at least 2.6.10 - interest seems to have dried up around March 2003. Therefore, remove EPXA10DB support. Signed-off-by: Russell King --- arch/arm/Kconfig | 9 - arch/arm/Makefile | 1 - arch/arm/boot/compressed/Makefile | 4 - arch/arm/boot/compressed/head-epxa10db.S | 5 - arch/arm/configs/epxa10db_defconfig | 644 ----------------- arch/arm/mach-epxa10db/Kconfig | 23 - arch/arm/mach-epxa10db/Makefile | 11 - arch/arm/mach-epxa10db/Makefile.boot | 2 - arch/arm/mach-epxa10db/arch.c | 74 -- arch/arm/mach-epxa10db/irq.c | 82 --- arch/arm/mach-epxa10db/mm.c | 71 -- arch/arm/mach-epxa10db/time.c | 78 -- arch/arm/mm/Kconfig | 4 +- drivers/mtd/maps/Kconfig | 8 - drivers/mtd/maps/Makefile | 1 - drivers/mtd/maps/epxa10db-flash.c | 179 ----- drivers/net/arm/Kconfig | 13 - drivers/net/arm/Makefile | 1 - drivers/net/arm/ether00.c | 1017 --------------------------- drivers/serial/Kconfig | 23 - drivers/serial/Makefile | 1 - drivers/serial/uart00.c | 782 -------------------- include/asm-arm/arch-epxa10db/debug-macro.S | 41 -- include/asm-arm/arch-epxa10db/dma.h | 19 - include/asm-arm/arch-epxa10db/entry-macro.S | 25 - include/asm-arm/arch-epxa10db/ether00.h | 482 ------------- include/asm-arm/arch-epxa10db/excalibur.h | 91 --- include/asm-arm/arch-epxa10db/hardware.h | 64 -- include/asm-arm/arch-epxa10db/int_ctrl00.h | 288 -------- include/asm-arm/arch-epxa10db/io.h | 41 -- include/asm-arm/arch-epxa10db/irqs.h | 45 -- include/asm-arm/arch-epxa10db/memory.h | 38 - include/asm-arm/arch-epxa10db/mode_ctrl00.h | 80 --- include/asm-arm/arch-epxa10db/param.h | 19 - include/asm-arm/arch-epxa10db/platform.h | 7 - include/asm-arm/arch-epxa10db/pld_conf00.h | 73 -- include/asm-arm/arch-epxa10db/system.h | 41 -- include/asm-arm/arch-epxa10db/tdkphy.h | 209 ------ include/asm-arm/arch-epxa10db/timer00.h | 98 --- include/asm-arm/arch-epxa10db/timex.h | 26 - include/asm-arm/arch-epxa10db/uart00.h | 181 ----- include/asm-arm/arch-epxa10db/uncompress.h | 54 -- include/asm-arm/arch-epxa10db/vmalloc.h | 20 - 43 files changed, 2 insertions(+), 4973 deletions(-) delete mode 100644 arch/arm/boot/compressed/head-epxa10db.S delete mode 100644 arch/arm/configs/epxa10db_defconfig delete mode 100644 arch/arm/mach-epxa10db/Kconfig delete mode 100644 arch/arm/mach-epxa10db/Makefile delete mode 100644 arch/arm/mach-epxa10db/Makefile.boot delete mode 100644 arch/arm/mach-epxa10db/arch.c delete mode 100644 arch/arm/mach-epxa10db/irq.c delete mode 100644 arch/arm/mach-epxa10db/mm.c delete mode 100644 arch/arm/mach-epxa10db/time.c delete mode 100644 drivers/mtd/maps/epxa10db-flash.c delete mode 100644 drivers/net/arm/ether00.c delete mode 100644 drivers/serial/uart00.c delete mode 100644 include/asm-arm/arch-epxa10db/debug-macro.S delete mode 100644 include/asm-arm/arch-epxa10db/dma.h delete mode 100644 include/asm-arm/arch-epxa10db/entry-macro.S delete mode 100644 include/asm-arm/arch-epxa10db/ether00.h delete mode 100644 include/asm-arm/arch-epxa10db/excalibur.h delete mode 100644 include/asm-arm/arch-epxa10db/hardware.h delete mode 100644 include/asm-arm/arch-epxa10db/int_ctrl00.h delete mode 100644 include/asm-arm/arch-epxa10db/io.h delete mode 100644 include/asm-arm/arch-epxa10db/irqs.h delete mode 100644 include/asm-arm/arch-epxa10db/memory.h delete mode 100644 include/asm-arm/arch-epxa10db/mode_ctrl00.h delete mode 100644 include/asm-arm/arch-epxa10db/param.h delete mode 100644 include/asm-arm/arch-epxa10db/platform.h delete mode 100644 include/asm-arm/arch-epxa10db/pld_conf00.h delete mode 100644 include/asm-arm/arch-epxa10db/system.h delete mode 100644 include/asm-arm/arch-epxa10db/tdkphy.h delete mode 100644 include/asm-arm/arch-epxa10db/timer00.h delete mode 100644 include/asm-arm/arch-epxa10db/timex.h delete mode 100644 include/asm-arm/arch-epxa10db/uart00.h delete mode 100644 include/asm-arm/arch-epxa10db/uncompress.h delete mode 100644 include/asm-arm/arch-epxa10db/vmalloc.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 16a5d522b2f2..70f388d168db 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -103,13 +103,6 @@ config ARCH_EBSA110 Ethernet interface, two PCMCIA sockets, two serial ports and a parallel port. -config ARCH_CAMELOT - bool "Epxa10db" - help - This enables support for Altera's Excalibur XA10 development board. - If you would like to build your kernel to run on one of these boards - then you must say 'Y' here. Otherwise say 'N' - config ARCH_FOOTBRIDGE bool "FootBridge" select FOOTBRIDGE @@ -221,8 +214,6 @@ endchoice source "arch/arm/mach-clps711x/Kconfig" -source "arch/arm/mach-epxa10db/Kconfig" - source "arch/arm/mach-footbridge/Kconfig" source "arch/arm/mach-integrator/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index afaf3a1e903c..1c056d631153 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -84,7 +84,6 @@ endif machine-$(CONFIG_ARCH_PXA) := pxa machine-$(CONFIG_ARCH_L7200) := l7200 machine-$(CONFIG_ARCH_INTEGRATOR) := integrator - machine-$(CONFIG_ARCH_CAMELOT) := epxa10db textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 machine-$(CONFIG_ARCH_CLPS711X) := clps711x machine-$(CONFIG_ARCH_IOP3XX) := iop3xx diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 6b505ce41a75..0009a80498cc 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -21,10 +21,6 @@ ifeq ($(CONFIG_ARCH_SHARK),y) OBJS += head-shark.o ofw-shark.o endif -ifeq ($(CONFIG_ARCH_CAMELOT),y) -OBJS += head-epxa10db.o -endif - ifeq ($(CONFIG_ARCH_L7200),y) OBJS += head-l7200.o endif diff --git a/arch/arm/boot/compressed/head-epxa10db.S b/arch/arm/boot/compressed/head-epxa10db.S deleted file mode 100644 index 757681f12a39..000000000000 --- a/arch/arm/boot/compressed/head-epxa10db.S +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include - - .section ".start", "ax" - mov r7, #MACH_TYPE_CAMELOT diff --git a/arch/arm/configs/epxa10db_defconfig b/arch/arm/configs/epxa10db_defconfig deleted file mode 100644 index 9fb8b58c4954..000000000000 --- a/arch/arm/configs/epxa10db_defconfig +++ /dev/null @@ -1,644 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 22:46:51 2005 -# -CONFIG_ARM=y -CONFIG_MMU=y -CONFIG_UID16=y -CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y -CONFIG_BROKEN_ON_SMP=y - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_POSIX_MQUEUE is not set -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -# CONFIG_HOTPLUG is not set -CONFIG_KOBJECT_UEVENT=y -# CONFIG_IKCONFIG is not set -# CONFIG_EMBEDDED is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_EXTRA_PASS is not set -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y -# CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set -# CONFIG_KMOD is not set - -# -# System Type -# -# CONFIG_ARCH_CLPS7500 is not set -# CONFIG_ARCH_CLPS711X is not set -# CONFIG_ARCH_CO285 is not set -# CONFIG_ARCH_EBSA110 is not set -CONFIG_ARCH_CAMELOT=y -# CONFIG_ARCH_FOOTBRIDGE is not set -# CONFIG_ARCH_INTEGRATOR is not set -# CONFIG_ARCH_IOP3XX is not set -# CONFIG_ARCH_IXP4XX is not set -# CONFIG_ARCH_IXP2000 is not set -# CONFIG_ARCH_L7200 is not set -# CONFIG_ARCH_PXA is not set -# CONFIG_ARCH_RPC is not set -# CONFIG_ARCH_SA1100 is not set -# CONFIG_ARCH_S3C2410 is not set -# CONFIG_ARCH_SHARK is not set -# CONFIG_ARCH_LH7A40X is not set -# CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_VERSATILE is not set -# CONFIG_ARCH_IMX is not set -# CONFIG_ARCH_H720X is not set - -# -# Epxa10db -# - -# -# PLD hotswap support -# -CONFIG_PLD=y -# CONFIG_PLD_HOTSWAP is not set - -# -# Processor Type -# -CONFIG_CPU_32=y -CONFIG_CPU_ARM922T=y -CONFIG_CPU_32v4=y -CONFIG_CPU_ABRT_EV4T=y -CONFIG_CPU_CACHE_V4WT=y -CONFIG_CPU_CACHE_VIVT=y -CONFIG_CPU_COPY_V4WB=y -CONFIG_CPU_TLB_V4WBI=y - -# -# Processor Features -# -# CONFIG_ARM_THUMB is not set -# CONFIG_CPU_ICACHE_DISABLE is not set -# CONFIG_CPU_DCACHE_DISABLE is not set -# CONFIG_CPU_DCACHE_WRITETHROUGH is not set - -# -# Bus support -# - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# Kernel Features -# -# CONFIG_PREEMPT is not set -CONFIG_ALIGNMENT_TRAP=y - -# -# Boot options -# -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="mem=32M console=ttyUA0,115200 initrd=0x00200000,8M root=/dev/ram0 rw" -# CONFIG_XIP_KERNEL is not set - -# -# Floating point emulation -# - -# -# At least one emulation must be selected -# -CONFIG_FPE_NWFPE=y -# CONFIG_FPE_NWFPE_XP is not set -# CONFIG_FPE_FASTFPE is not set - -# -# Userspace binary formats -# -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_AOUT is not set -# CONFIG_BINFMT_MISC is not set -# CONFIG_ARTHUR is not set - -# -# Power management options -# -# CONFIG_PM is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set - -# -# SCSI device support -# -# CONFIG_SCSI is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# - -# -# IEEE 1394 (FireWire) support -# - -# -# I2O device support -# - -# -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -# CONFIG_IP_PNP_DHCP is not set -# CONFIG_IP_PNP_BOOTP is not set -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# Ethernet (10 or 100Mbit) -# -# CONFIG_NET_ETHERNET is not set - -# -# Ethernet (1000 Mbit) -# - -# -# Ethernet (10000 Mbit) -# - -# -# Token Ring devices -# - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -CONFIG_PPP=y -CONFIG_PPP_MULTILINK=y -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=y -CONFIG_PPP_DEFLATE=y -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_PPPOE is not set -# CONFIG_SLIP is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -# CONFIG_INPUT_EVDEV is not set -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_RAW is not set -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -# CONFIG_SERIAL_8250 is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_UART00=y -CONFIG_SERIAL_UART00_CONSOLE=y -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -# CONFIG_FB is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -CONFIG_USB_ARCH_HAS_HCD=y -# CONFIG_USB_ARCH_HAS_OHCI is not set -# CONFIG_USB is not set - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set - -# -# XFS support -# -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -CONFIG_AUTOFS_FS=y -CONFIG_AUTOFS4_FS=y - -# -# CD-ROM/DVD Filesystems -# -# CONFIG_ISO9660_FS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set -# CONFIG_TMPFS is not set -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_NFS_FS is not set -# CONFIG_NFSD is not set -CONFIG_SMB_FS=y -# CONFIG_SMB_NLS_DEFAULT is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Profiling support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -# CONFIG_DEBUG_KERNEL is not set -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_DEBUG_BUGVERBOSE=y -CONFIG_FRAME_POINTER=y -# CONFIG_DEBUG_USER is not set - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set - -# -# Hardware crypto devices -# - -# -# Library routines -# -CONFIG_CRC_CCITT=y -CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y diff --git a/arch/arm/mach-epxa10db/Kconfig b/arch/arm/mach-epxa10db/Kconfig deleted file mode 100644 index 55d896dd4950..000000000000 --- a/arch/arm/mach-epxa10db/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -if ARCH_CAMELOT - -menu "Epxa10db" - -comment "PLD hotswap support" - -config PLD - bool - default y - -config PLD_HOTSWAP - bool "Support for PLD device hotplugging (experimental)" - depends on EXPERIMENTAL - help - This enables support for the dynamic loading and configuration of - compatible drivers when the contents of the PLD are changed. This - is still experimental and requires configuration tools which are - not yet generally available. Say N here. You must enable the kernel - module loader for this feature to work. - -endmenu - -endif diff --git a/arch/arm/mach-epxa10db/Makefile b/arch/arm/mach-epxa10db/Makefile deleted file mode 100644 index 24fbd7d3a3c1..000000000000 --- a/arch/arm/mach-epxa10db/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-y := arch.o irq.o mm.o time.o -obj-m := -obj-n := -obj- := - diff --git a/arch/arm/mach-epxa10db/Makefile.boot b/arch/arm/mach-epxa10db/Makefile.boot deleted file mode 100644 index 28bec7d3fc88..000000000000 --- a/arch/arm/mach-epxa10db/Makefile.boot +++ /dev/null @@ -1,2 +0,0 @@ - zreladdr-y := 0x00008000 - diff --git a/arch/arm/mach-epxa10db/arch.c b/arch/arm/mach-epxa10db/arch.c deleted file mode 100644 index 44c56571d183..000000000000 --- a/arch/arm/mach-epxa10db/arch.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * linux/arch/arm/mach-epxa10db/arch.c - * - * Copyright (C) 2000 Deep Blue Solutions Ltd - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include - -#include -#include -#include - -#include - -static struct plat_serial8250_port serial_platform_data[] = { - { - .iobase = 0x3f8, - .irq = IRQ_UARTINT0, -#error FIXME - .uartclk = 0, - .regshift = 0, - .iotype = UPIO_PORT, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, - }, - { - .iobase = 0x2f8, - .irq = IRQ_UARTINT1, -#error FIXME - .uartclk = 0, - .regshift = 0, - .iotype = UPIO_PORT, - .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, - }, - { }, -}; - -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_platform_data, - }, -}; - -extern void epxa10db_map_io(void); -extern void epxa10db_init_irq(void); -extern struct sys_timer epxa10db_timer; - -MACHINE_START(CAMELOT, "Altera Epxa10db") - /* Maintainer: Altera Corporation */ - .phys_ram = 0x00000000, - .phys_io = 0x7fffc000, - .io_pg_offst = ((0xffffc000) >> 18) & 0xfffc, - .map_io = epxa10db_map_io, - .init_irq = epxa10db_init_irq, - .timer = &epxa10db_timer, -MACHINE_END - diff --git a/arch/arm/mach-epxa10db/irq.c b/arch/arm/mach-epxa10db/irq.c deleted file mode 100644 index 9bf927e13309..000000000000 --- a/arch/arm/mach-epxa10db/irq.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * linux/arch/arm/mach-epxa10db/irq.c - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static void epxa_mask_irq(unsigned int irq) -{ - writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); -} - -static void epxa_unmask_irq(unsigned int irq) -{ - writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE))); -} - - -static struct irqchip epxa_irq_chip = { - .ack = epxa_mask_irq, - .mask = epxa_mask_irq, - .unmask = epxa_unmask_irq, -}; - -static struct resource irq_resource = { - .name = "irq_handler", - .start = IO_ADDRESS(EXC_INT_CTRL00_BASE), - .end = IO_ADDRESS(INT_PRIORITY_FC(EXC_INT_CTRL00_BASE))+4, -}; - -void __init epxa10db_init_irq(void) -{ - unsigned int i; - - request_resource(&iomem_resource, &irq_resource); - - /* - * This bit sets up the interrupt controller using - * the 6 PLD interrupts mode (the default) each - * irqs is assigned a priority which is the same - * as its interrupt number. This scheme is used because - * its easy, but you may want to change it depending - * on the contents of your PLD - */ - - writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE))); - for (i = 0; i < NR_IRQS; i++){ - writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i)); - set_irq_chip(i,&epxa_irq_chip); - set_irq_handler(i,do_level_IRQ); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - } - - /* Disable all interrupts */ - writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE))); - -} diff --git a/arch/arm/mach-epxa10db/mm.c b/arch/arm/mach-epxa10db/mm.c deleted file mode 100644 index cfd0d2182d44..000000000000 --- a/arch/arm/mach-epxa10db/mm.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * linux/arch/arm/mach-epxa10db/mm.c - * - * MM routines for Altera'a Epxa10db board - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -#include -#include -#include -#include - -#include - -/* Page table mapping for I/O region */ - -static struct map_desc epxa10db_io_desc[] __initdata = { - { - .virtual = IO_ADDRESS(EXC_REGISTERS_BASE), - .pfn = __phys_to_pfn(EXC_REGISTERS_BASE), - .length = SZ_16K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(EXC_PLD_BLOCK0_BASE), - .pfn = __phys_to_pfn(EXC_PLD_BLOCK0_BASE), - .length = SZ_16K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(EXC_PLD_BLOCK1_BASE), - .pfn =__phys_to_pfn(EXC_PLD_BLOCK1_BASE), - .length = SZ_16K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(EXC_PLD_BLOCK2_BASE), - .physical = __phys_to_pfn(EXC_PLD_BLOCK2_BASE), - .length = SZ_16K, - .type = MT_DEVICE - }, { - .virtual = IO_ADDRESS(EXC_PLD_BLOCK3_BASE), - .pfn = __phys_to_pfn(EXC_PLD_BLOCK3_BASE), - .length = SZ_16K, - .type = MT_DEVICE - }, { - .virtual = FLASH_VADDR(EXC_EBI_BLOCK0_BASE), - .pfn = __phys_to_pfn(EXC_EBI_BLOCK0_BASE), - .length = SZ_16M, - .type = MT_DEVICE - } -}; - -void __init epxa10db_map_io(void) -{ - iotable_init(epxa10db_io_desc, ARRAY_SIZE(epxa10db_io_desc)); -} diff --git a/arch/arm/mach-epxa10db/time.c b/arch/arm/mach-epxa10db/time.c deleted file mode 100644 index 4b1084dde8dd..000000000000 --- a/arch/arm/mach-epxa10db/time.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * linux/arch/arm/mach-epxa10db/time.c - * - * Copyright (C) 2000 Deep Blue Solutions - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define TIMER00_TYPE (volatile unsigned int*) -#include - -static int epxa10db_set_rtc(void) -{ - return 1; -} - -static int epxa10db_rtc_init(void) -{ - set_rtc = epxa10db_set_rtc; - - return 0; -} - -__initcall(epxa10db_rtc_init); - - -/* - * IRQ handler for the timer - */ -static irqreturn_t -epxa10db_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - write_seqlock(&xtime_lock); - - // ...clear the interrupt - *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))|=TIMER0_CR_CI_MSK; - - timer_tick(regs); - write_sequnlock(&xtime_lock); - - return IRQ_HANDLED; -} - -static struct irqaction epxa10db_timer_irq = { - .name = "Excalibur Timer Tick", - .flags = SA_INTERRUPT | SA_TIMER, - .handler = epxa10db_timer_interrupt, -}; - -/* - * Set up timer interrupt, and return the current time in seconds. - */ -static void __init epxa10db_timer_init(void) -{ - /* Start the timer */ - *TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200); - *TIMER0_PRESCALE(IO_ADDRESS(EXC_TIMER00_BASE))=1; - *TIMER0_CR(IO_ADDRESS(EXC_TIMER00_BASE))=TIMER0_CR_IE_MSK | TIMER0_CR_S_MSK; - - setup_irq(IRQ_TIMER0, &epxa10db_timer_irq); -} - -struct sys_timer epxa10db_timer = { - .init = epxa10db_timer_init, -}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index e84fdde6edf8..04cf0557e54b 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -83,8 +83,8 @@ config CPU_ARM920T # ARM922T config CPU_ARM922T bool "Support ARM922T processor" if ARCH_INTEGRATOR - depends on ARCH_CAMELOT || ARCH_LH7A40X || ARCH_INTEGRATOR - default y if ARCH_CAMELOT || ARCH_LH7A40X + depends on ARCH_LH7A40X || ARCH_INTEGRATOR + default y if ARCH_LH7A40X select CPU_32v4 select CPU_ABRT_EV4T select CPU_CACHE_V4WT diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index b9b77cf39a18..7abd7fee0dda 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -473,14 +473,6 @@ config MTD_IXP2000 IXDP425 and Coyote. If you have an IXP2000 based board and would like to use the flash chips on it, say 'Y'. -config MTD_EPXA10DB - tristate "CFI Flash device mapped on Epxa10db" - depends on MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT - help - This enables support for the flash devices on the Altera - Excalibur XA10 Development Board. If you are building a kernel - for on of these boards then you should say 'Y' otherwise say 'N'. - config MTD_FORTUNET tristate "CFI Flash device mapped on the FortuNet board" depends on MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 2f7e254912f0..ab71f172eb77 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o -obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c deleted file mode 100644 index 265b079fe934..000000000000 --- a/drivers/mtd/maps/epxa10db-flash.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Flash memory access on EPXA based devices - * - * (C) 2000 Nicolas Pitre - * Copyright (C) 2001 Altera Corporation - * Copyright (C) 2001 Red Hat, Inc. - * - * $Id: epxa10db-flash.c,v 1.15 2005/11/07 11:14:27 gleixner Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef CONFIG_EPXA10DB -#define BOARD_NAME "EPXA10DB" -#else -#define BOARD_NAME "EPXA1DB" -#endif - -static int nr_parts = 0; -static struct mtd_partition *parts; - -static struct mtd_info *mymtd; - -static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); - - -static struct map_info epxa_map = { - .name = "EPXA flash", - .size = FLASH_SIZE, - .bankwidth = 2, - .phys = FLASH_START, -}; - -static const char *probes[] = { "RedBoot", "afs", NULL }; - -static int __init epxa_mtd_init(void) -{ - int i; - - printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); - - epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE); - if (!epxa_map.virt) { - printk("Failed to ioremap %s flash\n",BOARD_NAME); - return -EIO; - } - simple_map_init(&epxa_map); - - mymtd = do_map_probe("cfi_probe", &epxa_map); - if (!mymtd) { - iounmap((void *)epxa_map.virt); - return -ENXIO; - } - - mymtd->owner = THIS_MODULE; - - /* Unlock the flash device. */ - if(mymtd->unlock){ - for (i=0; inumeraseregions;i++){ - int j; - for(j=0;jeraseregions[i].numblocks;j++){ - mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize); - } - } - } - -#ifdef CONFIG_MTD_PARTITIONS - nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0); - - if (nr_parts > 0) { - add_mtd_partitions(mymtd, parts, nr_parts); - return 0; - } -#endif - /* No recognised partitioning schemes found - use defaults */ - nr_parts = epxa_default_partitions(mymtd, &parts); - if (nr_parts > 0) { - add_mtd_partitions(mymtd, parts, nr_parts); - return 0; - } - - /* If all else fails... */ - add_mtd_device(mymtd); - return 0; -} - -static void __exit epxa_mtd_cleanup(void) -{ - if (mymtd) { - if (nr_parts) - del_mtd_partitions(mymtd); - else - del_mtd_device(mymtd); - map_destroy(mymtd); - } - if (epxa_map.virt) { - iounmap((void *)epxa_map.virt); - epxa_map.virt = 0; - } -} - - -/* - * This will do for now, once we decide which bootldr we're finally - * going to use then we'll remove this function and do it properly - * - * Partions are currently (as offsets from base of flash): - * 0x00000000 - 0x003FFFFF - bootloader (!) - * 0x00400000 - 0x00FFFFFF - Flashdisk - */ - -static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts) -{ - struct mtd_partition *parts; - int ret, i; - int npartitions = 0; - char *names; - const char *name = "jffs"; - - printk("Using default partitions for %s\n",BOARD_NAME); - npartitions=1; - parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); - memzero(parts,npartitions*sizeof(*parts)+strlen(name)); - if (!parts) { - ret = -ENOMEM; - goto out; - } - i=0; - names = (char *)&parts[npartitions]; - parts[i].name = names; - names += strlen(name) + 1; - strcpy(parts[i].name, name); - -#ifdef CONFIG_EPXA10DB - parts[i].size = FLASH_SIZE-0x00400000; - parts[i].offset = 0x00400000; -#else - parts[i].size = FLASH_SIZE-0x00180000; - parts[i].offset = 0x00180000; -#endif - - out: - *pparts = parts; - return npartitions; -} - - -module_init(epxa_mtd_init); -module_exit(epxa_mtd_cleanup); - -MODULE_AUTHOR("Clive Davies"); -MODULE_DESCRIPTION("Altera epxa mtd flash map"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 470364deded0..625184b65e38 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -31,16 +31,3 @@ config ARM_ETHERH help If you have an Acorn system with one of these network cards, you should say Y to this option if you wish to use it with Linux. - -config ARM_ETHER00 - tristate "Altera Ether00 support" - depends on NET_ETHERNET && ARM && ARCH_CAMELOT - help - This is the driver for Altera's ether00 ethernet mac IP core. Say - Y here if you want to build support for this into the kernel. It - is also available as a module (say M here) that can be inserted/ - removed from the kernel at the same time as the PLD is configured. - If this driver is running on an epxa10 development board then it - will generate a suitable hw address based on the board serial - number (MTD support is required for this). Otherwise you will - need to set a suitable hw address using ifconfig. diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile index b0d706834d89..bc263edf06a7 100644 --- a/drivers/net/arm/Makefile +++ b/drivers/net/arm/Makefile @@ -4,7 +4,6 @@ # obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o -obj-$(CONFIG_ARM_ETHER00) += ether00.o obj-$(CONFIG_ARM_ETHERH) += etherh.o obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHER1) += ether1.o diff --git a/drivers/net/arm/ether00.c b/drivers/net/arm/ether00.c deleted file mode 100644 index 4f1f4e31bda5..000000000000 --- a/drivers/net/arm/ether00.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* - * drivers/net/ether00.c - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -MODULE_AUTHOR("Clive Davies"); -MODULE_DESCRIPTION("Altera Ether00 IP core driver"); -MODULE_LICENSE("GPL"); - -#define PKT_BUF_SZ 1540 /* Size of each rx buffer */ -#define ETH_NR 4 /* Number of MACs this driver supports */ - -#define DEBUG(x) - -#define __dma_va(x) (unsigned int)((unsigned int)priv->dma_data+(((unsigned int)(x))&(EXC_SPSRAM_BLOCK0_SIZE-1))) -#define __dma_pa(x) (unsigned int)(EXC_SPSRAM_BLOCK0_BASE+(((unsigned int)(x))-(unsigned int)priv->dma_data)) - -#define ETHER00_BASE 0 -#define ETHER00_TYPE -#define ETHER00_NAME "ether00" -#define MAC_REG_SIZE 0x400 /* size of MAC register area */ - - - -/* typedefs */ - -/* The definition of the driver control structure */ - -#define RX_NUM_BUFF 10 -#define RX_NUM_FDESC 10 -#define TX_NUM_FDESC 10 - -struct tx_fda_ent{ - FDA_DESC fd; - BUF_DESC bd; - BUF_DESC pad; -}; -struct rx_fda_ent{ - FDA_DESC fd; - BUF_DESC bd; - BUF_DESC pad; -}; -struct rx_blist_ent{ - FDA_DESC fd; - BUF_DESC bd; - BUF_DESC pad; -}; -struct net_priv -{ - struct net_device_stats stats; - struct sk_buff* skb; - void* dma_data; - struct rx_blist_ent* rx_blist_vp; - struct rx_fda_ent* rx_fda_ptr; - struct tx_fda_ent* tx_fdalist_vp; - struct tq_struct tq_memupdate; - unsigned char memupdate_scheduled; - unsigned char rx_disabled; - unsigned char queue_stopped; - spinlock_t rx_lock; -}; - -static const char vendor_id[2]={0x07,0xed}; - -#ifdef ETHER00_DEBUG - -/* Dump (most) registers for debugging puposes */ - -static void dump_regs(struct net_device *dev){ - struct net_priv* priv=dev->priv; - unsigned int* i; - - printk("\n RX free descriptor area:\n"); - - for(i=(unsigned int*)priv->rx_fda_ptr; - i<((unsigned int*)(priv->rx_fda_ptr+RX_NUM_FDESC));){ - printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3)); - i+=4; - } - - printk("\n RX buffer list:\n"); - - for(i=(unsigned int*)priv->rx_blist_vp; - i<((unsigned int*)(priv->rx_blist_vp+RX_NUM_BUFF));){ - printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3)); - i+=4; - } - - printk("\n TX frame descriptor list:\n"); - - for(i=(unsigned int*)priv->tx_fdalist_vp; - i<((unsigned int*)(priv->tx_fdalist_vp+TX_NUM_FDESC));){ - printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3)); - i+=4; - } - - printk("\ndma ctl=%#x\n",readw(ETHER_DMA_CTL(dev->base_addr))); - printk("txfrmptr=%#x\n",readw(ETHER_TXFRMPTR(dev->base_addr))); - printk("txthrsh=%#x\n",readw(ETHER_TXTHRSH(dev->base_addr))); - printk("txpollctr=%#x\n",readw(ETHER_TXPOLLCTR(dev->base_addr))); - printk("blfrmptr=%#x\n",readw(ETHER_BLFRMPTR(dev->base_addr))); - printk("rxfragsize=%#x\n",readw(ETHER_RXFRAGSIZE(dev->base_addr))); - printk("tx_int_en=%#x\n",readw(ETHER_INT_EN(dev->base_addr))); - printk("fda_bas=%#x\n",readw(ETHER_FDA_BAS(dev->base_addr))); - printk("fda_lim=%#x\n",readw(ETHER_FDA_LIM(dev->base_addr))); - printk("int_src=%#x\n",readw(ETHER_INT_SRC(dev->base_addr))); - printk("pausecnt=%#x\n",readw(ETHER_PAUSECNT(dev->base_addr))); - printk("rempaucnt=%#x\n",readw(ETHER_REMPAUCNT(dev->base_addr))); - printk("txconfrmstat=%#x\n",readw(ETHER_TXCONFRMSTAT(dev->base_addr))); - printk("mac_ctl=%#x\n",readw(ETHER_MAC_CTL(dev->base_addr))); - printk("arc_ctl=%#x\n",readw(ETHER_ARC_CTL(dev->base_addr))); - printk("tx_ctl=%#x\n",readw(ETHER_TX_CTL(dev->base_addr))); -} -#endif /* ETHER00_DEBUG */ - - -static int ether00_write_phy(struct net_device *dev, short address, short value) -{ - volatile int count = 1024; - writew(value,ETHER_MD_DATA(dev->base_addr)); - writew( ETHER_MD_CA_BUSY_MSK | - ETHER_MD_CA_WR_MSK | - (address & ETHER_MD_CA_ADDR_MSK), - ETHER_MD_CA(dev->base_addr)); - - /* Wait for the command to complete */ - while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){ - count--; - } - if (!count){ - printk("Write to phy failed, addr=%#x, data=%#x\n",address, value); - return -EIO; - } - return 0; -} - -static int ether00_read_phy(struct net_device *dev, short address) -{ - volatile int count = 1024; - writew( ETHER_MD_CA_BUSY_MSK | - (address & ETHER_MD_CA_ADDR_MSK), - ETHER_MD_CA(dev->base_addr)); - - /* Wait for the command to complete */ - while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){ - count--; - } - if (!count){ - printk(KERN_WARNING "Read from phy timed out\n"); - return -EIO; - } - return readw(ETHER_MD_DATA(dev->base_addr)); -} - -static void ether00_phy_int(int irq_num, void* dev_id, struct pt_regs* regs) -{ - struct net_device* dev=dev_id; - int irq_status; - - irq_status=ether00_read_phy(dev, PHY_IRQ_CONTROL); - - if(irq_status & PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK){ - /* - * Autonegotiation complete on epxa10db. The mac doesn't - * twig if we're in full duplex so we need to check the - * phy status register and configure the mac accordingly - */ - if(ether00_read_phy(dev, PHY_STATUS)&(PHY_STATUS_10T_F_MSK|PHY_STATUS_100_X_F_MSK)){ - int tmp; - tmp=readl(ETHER_MAC_CTL(dev->base_addr)); - writel(tmp|ETHER_MAC_CTL_FULLDUP_MSK,ETHER_MAC_CTL(dev->base_addr)); - } - } - - if(irq_status&PHY_IRQ_CONTROL_LS_CHG_INT_MSK){ - - if(ether00_read_phy(dev, PHY_STATUS)& PHY_STATUS_LINK_MSK){ - /* Link is up */ - netif_carrier_on(dev); - //printk("Carrier on\n"); - }else{ - netif_carrier_off(dev); - //printk("Carrier off\n"); - - } - } - -} - -static void setup_blist_entry(struct sk_buff* skb,struct rx_blist_ent* blist_ent_ptr){ - /* Make the buffer consistent with the cache as the mac is going to write - * directly into it*/ - blist_ent_ptr->fd.FDSystem=(unsigned int)skb; - blist_ent_ptr->bd.BuffData=(char*)__pa(skb->data); - consistent_sync(skb->data,PKT_BUF_SZ,PCI_DMA_FROMDEVICE); - /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */ - skb_reserve(skb,2); - blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2; - blist_ent_ptr->fd.FDLength=1; - blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK; - blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK; -} - - -static int ether00_mem_init(struct net_device* dev) -{ - struct net_priv* priv=dev->priv; - struct tx_fda_ent *tx_fd_ptr,*tx_end_ptr; - struct rx_blist_ent* blist_ent_ptr; - int i; - - /* - * Grab a block of on chip SRAM to contain the control stuctures for - * the ethernet MAC. This uncached becuase it needs to be accesses by both - * bus masters (cpu + mac). However, it shouldn't matter too much in terms - * of speed as its on chip memory - */ - priv->dma_data=ioremap_nocache(EXC_SPSRAM_BLOCK0_BASE,EXC_SPSRAM_BLOCK0_SIZE ); - if (!priv->dma_data) - return -ENOMEM; - - priv->rx_fda_ptr=(struct rx_fda_ent*)priv->dma_data; - /* - * Now share it out amongst the Frame descriptors and the buffer list - */ - priv->rx_blist_vp=(struct rx_blist_ent*)((unsigned int)priv->dma_data+RX_NUM_FDESC*sizeof(struct rx_fda_ent)); - - /* - *Initalise the FDA list - */ - /* set ownership to the controller */ - memset(priv->rx_fda_ptr,0x80,RX_NUM_FDESC*sizeof(struct rx_fda_ent)); - - /* - *Initialise the buffer list - */ - blist_ent_ptr=priv->rx_blist_vp; - i=0; - while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){ - struct sk_buff *skb; - blist_ent_ptr->fd.FDLength=1; - skb=dev_alloc_skb(PKT_BUF_SZ); - if(skb){ - setup_blist_entry(skb,blist_ent_ptr); - blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(blist_ent_ptr+1); - blist_ent_ptr->bd.BDStat=i++; - blist_ent_ptr++; - } - else - { - printk("Failed to initalise buffer list\n"); - } - - } - blist_ent_ptr--; - blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->rx_blist_vp); - - priv->tx_fdalist_vp=(struct tx_fda_ent*)(priv->rx_blist_vp+RX_NUM_BUFF); - - /* Initialise the buffers to be a circular list. The mac will then go poll - * the list until it finds a frame ready to transmit */ - tx_end_ptr=priv->tx_fdalist_vp+TX_NUM_FDESC; - for(tx_fd_ptr=priv->tx_fdalist_vp;tx_fd_ptrfd.FDNext=(FDA_DESC*)__dma_pa((tx_fd_ptr+1)); - tx_fd_ptr->fd.FDCtl=1; - tx_fd_ptr->fd.FDStat=0; - tx_fd_ptr->fd.FDLength=1; - - } - /* Change the last FDNext pointer to make a circular list */ - tx_fd_ptr--; - tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->tx_fdalist_vp); - - /* Point the device at the chain of Rx and Tx Buffers */ - writel((unsigned int)__dma_pa(priv->rx_fda_ptr),ETHER_FDA_BAS(dev->base_addr)); - writel((RX_NUM_FDESC-1)*sizeof(struct rx_fda_ent),ETHER_FDA_LIM(dev->base_addr)); - writel((unsigned int)__dma_pa(priv->rx_blist_vp),ETHER_BLFRMPTR(dev->base_addr)); - - writel((unsigned int)__dma_pa(priv->tx_fdalist_vp),ETHER_TXFRMPTR(dev->base_addr)); - - return 0; -} - - -void ether00_mem_update(void* dev_id) -{ - struct net_device* dev=dev_id; - struct net_priv* priv=dev->priv; - struct sk_buff* skb; - struct tx_fda_ent *fda_ptr=priv->tx_fdalist_vp; - struct rx_blist_ent* blist_ent_ptr; - unsigned long flags; - - priv->tq_memupdate.sync=0; - //priv->tq_memupdate.list= - priv->memupdate_scheduled=0; - - /* Transmit interrupt */ - while(fda_ptr<(priv->tx_fdalist_vp+TX_NUM_FDESC)){ - if(!(FDCTL_COWNSFD_MSK&fda_ptr->fd.FDCtl) && (ETHER_TX_STAT_COMP_MSK&fda_ptr->fd.FDStat)){ - priv->stats.tx_packets++; - priv->stats.tx_bytes+=fda_ptr->bd.BuffLength; - skb=(struct sk_buff*)fda_ptr->fd.FDSystem; - //printk("%d:txcln:fda=%#x skb=%#x\n",jiffies,fda_ptr,skb); - dev_kfree_skb(skb); - fda_ptr->fd.FDSystem=0; - fda_ptr->fd.FDStat=0; - fda_ptr->fd.FDCtl=0; - } - fda_ptr++; - } - /* Fill in any missing buffers from the received queue */ - spin_lock_irqsave(&priv->rx_lock,flags); - blist_ent_ptr=priv->rx_blist_vp; - while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){ - /* fd.FDSystem of 0 indicates we failed to allocate the buffer in the ISR */ - if(!blist_ent_ptr->fd.FDSystem){ - struct sk_buff *skb; - skb=dev_alloc_skb(PKT_BUF_SZ); - blist_ent_ptr->fd.FDSystem=(unsigned int)skb; - if(skb){ - setup_blist_entry(skb,blist_ent_ptr); - } - else - { - break; - } - } - blist_ent_ptr++; - } - spin_unlock_irqrestore(&priv->rx_lock,flags); - if(priv->queue_stopped){ - //printk("%d:cln:start q\n",jiffies); - netif_start_queue(dev); - } - if(priv->rx_disabled){ - //printk("%d:enable_irq\n",jiffies); - priv->rx_disabled=0; - writel(ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr)); - - } -} - - -static void ether00_int( int irq_num, void* dev_id, struct pt_regs* regs) -{ - struct net_device* dev=dev_id; - struct net_priv* priv=dev->priv; - - unsigned int interruptValue; - - interruptValue=readl(ETHER_INT_SRC(dev->base_addr)); - - //printk("INT_SRC=%x\n",interruptValue); - - if(!(readl(ETHER_INT_SRC(dev->base_addr)) & ETHER_INT_SRC_IRQ_MSK)) - { - return; /* Interrupt wasn't caused by us!! */ - } - - if(readl(ETHER_INT_SRC(dev->base_addr))& - (ETHER_INT_SRC_INTMACRX_MSK | - ETHER_INT_SRC_FDAEX_MSK | - ETHER_INT_SRC_BLEX_MSK)) { - struct rx_blist_ent* blist_ent_ptr; - struct rx_fda_ent* fda_ent_ptr; - struct sk_buff* skb; - - fda_ent_ptr=priv->rx_fda_ptr; - spin_lock(&priv->rx_lock); - while(fda_ent_ptr<(priv->rx_fda_ptr+RX_NUM_FDESC)){ - int result; - - if(!(fda_ent_ptr->fd.FDCtl&FDCTL_COWNSFD_MSK)) - { - /* This frame is ready for processing */ - /*find the corresponding buffer in the bufferlist */ - blist_ent_ptr=priv->rx_blist_vp+fda_ent_ptr->bd.BDStat; - skb=(struct sk_buff*)blist_ent_ptr->fd.FDSystem; - - /* Pass this skb up the stack */ - skb->dev=dev; - skb_put(skb,fda_ent_ptr->fd.FDLength); - skb->protocol=eth_type_trans(skb,dev); - skb->ip_summed=CHECKSUM_UNNECESSARY; - result=netif_rx(skb); - /* Update statistics */ - priv->stats.rx_packets++; - priv->stats.rx_bytes+=fda_ent_ptr->fd.FDLength; - - /* Free the FDA entry */ - fda_ent_ptr->bd.BDStat=0xff; - fda_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK; - - /* Allocate a new skb and point the bd entry to it */ - blist_ent_ptr->fd.FDSystem=0; - skb=dev_alloc_skb(PKT_BUF_SZ); - //printk("allocskb=%#x\n",skb); - if(skb){ - setup_blist_entry(skb,blist_ent_ptr); - - } - else if(!priv->memupdate_scheduled){ - int tmp; - /* There are no buffers at the moment, so schedule */ - /* the background task to sort this out */ - schedule_task(&priv->tq_memupdate); - priv->memupdate_scheduled=1; - printk(KERN_DEBUG "%s:No buffers",dev->name); - /* If this interrupt was due to a lack of buffers then - * we'd better stop the receiver too */ - if(interruptValueÐER_INT_SRC_BLEX_MSK){ - priv->rx_disabled=1; - tmp=readl(ETHER_INT_SRC(dev->base_addr)); - writel(tmp&~ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr)); - printk(KERN_DEBUG "%s:Halting rx",dev->name); - } - - } - - } - fda_ent_ptr++; - } - spin_unlock(&priv->rx_lock); - - /* Clear the interrupts */ - writel(ETHER_INT_SRC_INTMACRX_MSK | ETHER_INT_SRC_FDAEX_MSK - | ETHER_INT_SRC_BLEX_MSK,ETHER_INT_SRC(dev->base_addr)); - - } - - if(readl(ETHER_INT_SRC(dev->base_addr))ÐER_INT_SRC_INTMACTX_MSK){ - - if(!priv->memupdate_scheduled){ - schedule_task(&priv->tq_memupdate); - priv->memupdate_scheduled=1; - } - /* Clear the interrupt */ - writel(ETHER_INT_SRC_INTMACTX_MSK,ETHER_INT_SRC(dev->base_addr)); - } - - if (readl(ETHER_INT_SRC(dev->base_addr)) & (ETHER_INT_SRC_SWINT_MSK| - ETHER_INT_SRC_INTEARNOT_MSK| - ETHER_INT_SRC_INTLINK_MSK| - ETHER_INT_SRC_INTEXBD_MSK| - ETHER_INT_SRC_INTTXCTLCMP_MSK)) - { - /* - * Not using any of these so they shouldn't happen - * - * In the cased of INTEXBD - if you allocate more - * than 28 decsriptors you may need to think about this - */ - printk("Not using this interrupt\n"); - } - - if (readl(ETHER_INT_SRC(dev->base_addr)) & - (ETHER_INT_SRC_INTSBUS_MSK | - ETHER_INT_SRC_INTNRABT_MSK - |ETHER_INT_SRC_DMPARERR_MSK)) - { - /* - * Hardware errors, we can either ignore them and hope they go away - *or reset the device, I'll try the first for now to see if they happen - */ - printk("Hardware error\n"); - } -} - -static void ether00_setup_ethernet_address(struct net_device* dev) -{ - int tmp; - - dev->addr_len=6; - writew(0,ETHER_ARC_ADR(dev->base_addr)); - writel((dev->dev_addr[0]<<24) | - (dev->dev_addr[1]<<16) | - (dev->dev_addr[2]<<8) | - dev->dev_addr[3], - ETHER_ARC_DATA(dev->base_addr)); - - writew(4,ETHER_ARC_ADR(dev->base_addr)); - tmp=readl(ETHER_ARC_DATA(dev->base_addr)); - tmp&=0xffff; - tmp|=(dev->dev_addr[4]<<24) | (dev->dev_addr[5]<<16); - writel(tmp, ETHER_ARC_DATA(dev->base_addr)); - /* Enable this entry in the ARC */ - - writel(1,ETHER_ARC_ENA(dev->base_addr)); - - return; -} - - -static void ether00_reset(struct net_device *dev) -{ - /* reset the controller */ - writew(ETHER_MAC_CTL_RESET_MSK,ETHER_MAC_CTL(dev->base_addr)); - - /* - * Make sure we're not going to send anything - */ - - writew(ETHER_TX_CTL_TXHALT_MSK,ETHER_TX_CTL(dev->base_addr)); - - /* - * Make sure we're not going to receive anything - */ - writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr)); - - /* - * Disable Interrupts for now, and set the burst size to 8 bytes - */ - - writel(ETHER_DMA_CTL_INTMASK_MSK | - ((8 << ETHER_DMA_CTL_DMBURST_OFST) & ETHER_DMA_CTL_DMBURST_MSK) - |(2<base_addr)); - - - /* - * Set TxThrsh - start transmitting a packet after 1514 - * bytes or when a packet is complete, whichever comes first - */ - writew(1514,ETHER_TXTHRSH(dev->base_addr)); - - /* - * Set TxPollCtr. Each cycle is - * 61.44 microseconds with a 33 MHz bus - */ - writew(1,ETHER_TXPOLLCTR(dev->base_addr)); - - /* - * Set Rx_Ctl - Turn off reception and let RxData turn it - * on later - */ - writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr)); - -} - - -static void ether00_set_multicast(struct net_device* dev) -{ - int count=dev->mc_count; - - /* Set promiscuous mode if it's asked for. */ - - if (dev->flags&IFF_PROMISC){ - - writew( ETHER_ARC_CTL_COMPEN_MSK | - ETHER_ARC_CTL_BROADACC_MSK | - ETHER_ARC_CTL_GROUPACC_MSK | - ETHER_ARC_CTL_STATIONACC_MSK, - ETHER_ARC_CTL(dev->base_addr)); - return; - } - - /* - * Get all multicast packets if required, or if there are too - * many addresses to fit in hardware - */ - if (dev->flags & IFF_ALLMULTI){ - writew( ETHER_ARC_CTL_COMPEN_MSK | - ETHER_ARC_CTL_GROUPACC_MSK | - ETHER_ARC_CTL_BROADACC_MSK, - ETHER_ARC_CTL(dev->base_addr)); - return; - } - if (dev->mc_count > (ETHER_ARC_SIZE - 1)){ - - printk(KERN_WARNING "Too many multicast addresses for hardware to filter - receiving all multicast packets\n"); - writew( ETHER_ARC_CTL_COMPEN_MSK | - ETHER_ARC_CTL_GROUPACC_MSK | - ETHER_ARC_CTL_BROADACC_MSK, - ETHER_ARC_CTL(dev->base_addr)); - return; - } - - if(dev->mc_count){ - struct dev_mc_list *mc_list_ent=dev->mc_list; - unsigned int temp,i; - DEBUG(printk("mc_count=%d mc_list=%#x\n",dev-> mc_count, dev->mc_list)); - DEBUG(printk("mc addr=%02#x%02x%02x%02x%02x%02x\n", - mc_list_ent->dmi_addr[5], - mc_list_ent->dmi_addr[4], - mc_list_ent->dmi_addr[3], - mc_list_ent->dmi_addr[2], - mc_list_ent->dmi_addr[1], - mc_list_ent->dmi_addr[0]);) - - /* - * The first 6 bytes are the MAC address, so - * don't change them! - */ - writew(4,ETHER_ARC_ADR(dev->base_addr)); - temp=readl(ETHER_ARC_DATA(dev->base_addr)); - temp&=0xffff0000; - - /* Disable the current multicast stuff */ - writel(1,ETHER_ARC_ENA(dev->base_addr)); - - for(;;){ - temp|=mc_list_ent->dmi_addr[1] | - mc_list_ent->dmi_addr[0]<<8; - writel(temp,ETHER_ARC_DATA(dev->base_addr)); - - i=readl(ETHER_ARC_ADR(dev->base_addr)); - writew(i+4,ETHER_ARC_ADR(dev->base_addr)); - - temp=mc_list_ent->dmi_addr[5]| - mc_list_ent->dmi_addr[4]<<8 | - mc_list_ent->dmi_addr[3]<<16 | - mc_list_ent->dmi_addr[2]<<24; - writel(temp,ETHER_ARC_DATA(dev->base_addr)); - - count--; - if(!mc_list_ent->next || !count){ - break; - } - DEBUG(printk("mc_list_next=%#x\n",mc_list_ent->next);) - mc_list_ent=mc_list_ent->next; - - - i=readl(ETHER_ARC_ADR(dev->base_addr)); - writel(i+4,ETHER_ARC_ADR(dev->base_addr)); - - temp=mc_list_ent->dmi_addr[3]| - mc_list_ent->dmi_addr[2]<<8 | - mc_list_ent->dmi_addr[1]<<16 | - mc_list_ent->dmi_addr[0]<<24; - writel(temp,ETHER_ARC_DATA(dev->base_addr)); - - i=readl(ETHER_ARC_ADR(dev->base_addr)); - writel(i+4,ETHER_ARC_ADR(dev->base_addr)); - - temp=mc_list_ent->dmi_addr[4]<<16 | - mc_list_ent->dmi_addr[5]<<24; - - writel(temp,ETHER_ARC_DATA(dev->base_addr)); - - count--; - if(!mc_list_ent->next || !count){ - break; - } - mc_list_ent=mc_list_ent->next; - } - - - if(count) - printk(KERN_WARNING "Multicast list size error\n"); - - - writew( ETHER_ARC_CTL_BROADACC_MSK| - ETHER_ARC_CTL_COMPEN_MSK, - ETHER_ARC_CTL(dev->base_addr)); - - } - - /* enable the active ARC enties */ - writew((1<<(count+2))-1,ETHER_ARC_ENA(dev->base_addr)); -} - - -static int ether00_open(struct net_device* dev) -{ - int result,tmp; - struct net_priv* priv; - - if (!is_valid_ether_addr(dev->dev_addr)) - return -EINVAL; - - /* Install interrupt handlers */ - result=request_irq(dev->irq,ether00_int,0,"ether00",dev); - if(result) - goto open_err1; - - result=request_irq(2,ether00_phy_int,0,"ether00_phy",dev); - if(result) - goto open_err2; - - ether00_reset(dev); - result=ether00_mem_init(dev); - if(result) - goto open_err3; - - - ether00_setup_ethernet_address(dev); - - ether00_set_multicast(dev); - - result=ether00_write_phy(dev,PHY_CONTROL, PHY_CONTROL_ANEGEN_MSK | PHY_CONTROL_RANEG_MSK); - if(result) - goto open_err4; - result=ether00_write_phy(dev,PHY_IRQ_CONTROL, PHY_IRQ_CONTROL_LS_CHG_IE_MSK | - PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK); - if(result) - goto open_err4; - - /* Start the device enable interrupts */ - writew(ETHER_RX_CTL_RXEN_MSK -// | ETHER_RX_CTL_STRIPCRC_MSK - | ETHER_RX_CTL_ENGOOD_MSK - | ETHER_RX_CTL_ENRXPAR_MSK| ETHER_RX_CTL_ENLONGERR_MSK - | ETHER_RX_CTL_ENOVER_MSK| ETHER_RX_CTL_ENCRCERR_MSK, - ETHER_RX_CTL(dev->base_addr)); - - writew(ETHER_TX_CTL_TXEN_MSK| - ETHER_TX_CTL_ENEXDEFER_MSK| - ETHER_TX_CTL_ENLCARR_MSK| - ETHER_TX_CTL_ENEXCOLL_MSK| - ETHER_TX_CTL_ENLATECOLL_MSK| - ETHER_TX_CTL_ENTXPAR_MSK| - ETHER_TX_CTL_ENCOMP_MSK, - ETHER_TX_CTL(dev->base_addr)); - - tmp=readl(ETHER_DMA_CTL(dev->base_addr)); - writel(tmp&~ETHER_DMA_CTL_INTMASK_MSK,ETHER_DMA_CTL(dev->base_addr)); - - return 0; - - open_err4: - ether00_reset(dev); - open_err3: - free_irq(2,dev); - open_err2: - free_irq(dev->irq,dev); - open_err1: - return result; - -} - - -static int ether00_tx(struct sk_buff* skb, struct net_device* dev) -{ - struct net_priv *priv=dev->priv; - struct tx_fda_ent *fda_ptr; - int i; - - - /* - * Find an empty slot in which to stick the frame - */ - fda_ptr=(struct tx_fda_ent*)__dma_va(readl(ETHER_TXFRMPTR(dev->base_addr))); - i=0; - while(ifd.FDStat||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){ - fda_ptr =(struct tx_fda_ent*) __dma_va((struct tx_fda_ent*)fda_ptr->fd.FDNext); - } - else { - break; - } - i++; - } - - /* Write the skb data from the cache*/ - consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE); - fda_ptr->bd.BuffData=(char*)__pa(skb->data); - fda_ptr->bd.BuffLength=(unsigned short)skb->len; - /* Save the pointer to the skb for freeing later */ - fda_ptr->fd.FDSystem=(unsigned int)skb; - fda_ptr->fd.FDStat=0; - /* Pass ownership of the buffers to the controller */ - fda_ptr->fd.FDCtl=1; - fda_ptr->fd.FDCtl|=FDCTL_COWNSFD_MSK; - - /* If the next buffer in the list is full, stop the queue */ - fda_ptr=(struct tx_fda_ent*)__dma_va(fda_ptr->fd.FDNext); - if ((fda_ptr->fd.FDStat)||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){ - netif_stop_queue(dev); - priv->queue_stopped=1; - } - - return 0; -} - -static struct net_device_stats *ether00_stats(struct net_device* dev) -{ - struct net_priv *priv=dev->priv; - return &priv->stats; -} - - -static int ether00_stop(struct net_device* dev) -{ - struct net_priv *priv=dev->priv; - int tmp; - - /* Stop/disable the device. */ - tmp=readw(ETHER_RX_CTL(dev->base_addr)); - tmp&=~(ETHER_RX_CTL_RXEN_MSK | ETHER_RX_CTL_ENGOOD_MSK); - tmp|=ETHER_RX_CTL_RXHALT_MSK; - writew(tmp,ETHER_RX_CTL(dev->base_addr)); - - tmp=readl(ETHER_TX_CTL(dev->base_addr)); - tmp&=~ETHER_TX_CTL_TXEN_MSK; - tmp|=ETHER_TX_CTL_TXHALT_MSK; - writel(tmp,ETHER_TX_CTL(dev->base_addr)); - - /* Free up system resources */ - free_irq(dev->irq,dev); - free_irq(2,dev); - iounmap(priv->dma_data); - - return 0; -} - - -static void ether00_get_ethernet_address(struct net_device* dev) -{ - struct mtd_info *mymtd=NULL; - int i; - size_t retlen; - - /* - * For the Epxa10 dev board (camelot), the ethernet MAC - * address is of the form 00:aa:aa:00:xx:xx where - * 00:aa:aa is the Altera vendor ID and xx:xx is the - * last 2 bytes of the board serial number, as programmed - * into the OTP area of the flash device on EBI1. If this - * isn't an expa10 dev board, or there's no mtd support to - * read the serial number from flash then we'll force the - * use to set their own mac address using ifconfig. - */ - -#ifdef CONFIG_ARCH_CAMELOT -#ifdef CONFIG_MTD - /* get the mtd_info structure for the first mtd device*/ - for(i=0;iname,"EPXA10DB flash")) - break; - } - - if(!mymtd || !mymtd->read_user_prot_reg){ - printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name); - }else{ - mymtd->read_user_prot_reg(mymtd,2,1,&retlen,&dev->dev_addr[5]); - mymtd->read_user_prot_reg(mymtd,3,1,&retlen,&dev->dev_addr[4]); - dev->dev_addr[3]=0; - dev->dev_addr[2]=vendor_id[1]; - dev->dev_addr[1]=vendor_id[0]; - dev->dev_addr[0]=0; - } -#else - printk(KERN_WARNING "%s: MTD support required to read MAC address from EPXA10 dev board\n", dev->name); -#endif -#endif - - if (!is_valid_ether_addr(dev->dev_addr)) - printk("%s: Invalid ethernet MAC address. Please set using " - "ifconfig\n", dev->name); - -} - -/* - * Keep a mapping of dev_info addresses -> port lines to use when - * removing ports dev==NULL indicates unused entry - */ - - -static struct net_device* dev_list[ETH_NR]; - -static int ether00_add_device(struct pldhs_dev_info* dev_info,void* dev_ps_data) -{ - struct net_device *dev; - struct net_priv *priv; - void *map_addr; - int result; - int i; - - i=0; - while(dev_list[i] && i < ETH_NR) - i++; - - if(i==ETH_NR){ - printk(KERN_WARNING "ether00: Maximum number of ports reached\n"); - return 0; - } - - - if (!request_mem_region(dev_info->base_addr, MAC_REG_SIZE, "ether00")) - return -EBUSY; - - dev = alloc_etherdev(sizeof(struct net_priv)); - if(!dev) { - result = -ENOMEM; - goto out_release; - } - priv = dev->priv; - - priv->tq_memupdate.routine=ether00_mem_update; - priv->tq_memupdate.data=(void*) dev; - - spin_lock_init(&priv->rx_lock); - - map_addr=ioremap_nocache(dev_info->base_addr,SZ_4K); - if(!map_addr){ - result = -ENOMEM; - out_kfree; - } - - dev->open=ether00_open; - dev->stop=ether00_stop; - dev->set_multicast_list=ether00_set_multicast; - dev->hard_start_xmit=ether00_tx; - dev->get_stats=ether00_stats; - - ether00_get_ethernet_address(dev); - - SET_MODULE_OWNER(dev); - - dev->base_addr=(unsigned int)map_addr; - dev->irq=dev_info->irq; - dev->features=NETIF_F_DYNALLOC | NETIF_F_HW_CSUM; - - result=register_netdev(dev); - if(result){ - printk("Ether00: Error %i registering driver\n",result); - goto out_unmap; - } - printk("registered ether00 device at %#x\n",dev_info->base_addr); - - dev_list[i]=dev; - - return result; - - out_unmap: - iounmap(map_addr); - out_kfree: - free_netdev(dev); - out_release: - release_mem_region(dev_info->base_addr, MAC_REG_SIZE); - return result; -} - - -static int ether00_remove_devices(void) -{ - int i; - - for(i=0;ibase_addr); - release_mem_region(dev_list[i]->base_addr, MAC_REG_SIZE); - free_netdev(dev_list[i]); - dev_list[i]=0; - } - } - return 0; -} - -static struct pld_hotswap_ops ether00_pldhs_ops={ - .name = ETHER00_NAME, - .add_device = ether00_add_device, - .remove_devices = ether00_remove_devices, -}; - - -static void __exit ether00_cleanup_module(void) -{ - int result; - result=ether00_remove_devices(); - if(result) - printk(KERN_WARNING "ether00: failed to remove all devices\n"); - - pldhs_unregister_driver(ETHER00_NAME); -} -module_exit(ether00_cleanup_module); - - -static int __init ether00_mod_init(void) -{ - printk("mod init\n"); - return pldhs_register_driver(ðer00_pldhs_ops); - -} - -module_init(ether00_mod_init); - diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 812bae62c8ec..47ea8338c03c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -359,29 +359,6 @@ config SERIAL_21285_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) -config SERIAL_UART00 - bool "Excalibur serial port (uart00) support" - depends on ARM && ARCH_CAMELOT - select SERIAL_CORE - help - Say Y here if you want to use the hard logic uart on Excalibur. This - driver also supports soft logic implementations of this uart core. - -config SERIAL_UART00_CONSOLE - bool "Support for console on Excalibur serial port" - depends on SERIAL_UART00 - select SERIAL_CORE_CONSOLE - help - Say Y here if you want to support a serial console on an Excalibur - hard logic uart or uart00 IP core. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyS1". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - config SERIAL_MPSC bool "Marvell MPSC serial port support" depends on PPC32 && MV64X60 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d7c7c7180e33..137148bba4fa 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA) += pxa.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o -obj-$(CONFIG_SERIAL_UART00) += uart00.o obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o diff --git a/drivers/serial/uart00.c b/drivers/serial/uart00.c deleted file mode 100644 index 47b504ff38b2..000000000000 --- a/drivers/serial/uart00.c +++ /dev/null @@ -1,782 +0,0 @@ -/* - * linux/drivers/serial/uart00.c - * - * Driver for UART00 serial ports - * - * Based on drivers/char/serial_amba.c, by ARM Limited & - * Deep Blue Solutions Ltd. - * Copyright 2001 Altera Corporation - * - * Update for 2.6.4 by Dirk Behme - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: uart00.c,v 1.35 2002/07/28 10:03:28 rmk Exp $ - * - */ -#include - -#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#define UART00_TYPE (volatile unsigned int*) -#include -#include - -#define UART_NR 2 - -#define SERIAL_UART00_NAME "ttyUA" -#define SERIAL_UART00_MAJOR 204 -#define SERIAL_UART00_MINOR 16 /* Temporary - will change in future */ -#define SERIAL_UART00_NR UART_NR -#define UART_PORT_SIZE 0x50 - -#define UART00_ISR_PASS_LIMIT 256 - -/* - * Access macros for the UART00 UARTs - */ -#define UART_GET_INT_STATUS(p) inl(UART_ISR((p)->membase)) -#define UART_PUT_IES(p, c) outl(c,UART_IES((p)->membase)) -#define UART_GET_IES(p) inl(UART_IES((p)->membase)) -#define UART_PUT_IEC(p, c) outl(c,UART_IEC((p)->membase)) -#define UART_GET_IEC(p) inl(UART_IEC((p)->membase)) -#define UART_PUT_CHAR(p, c) outl(c,UART_TD((p)->membase)) -#define UART_GET_CHAR(p) inl(UART_RD((p)->membase)) -#define UART_GET_RSR(p) inl(UART_RSR((p)->membase)) -#define UART_GET_RDS(p) inl(UART_RDS((p)->membase)) -#define UART_GET_MSR(p) inl(UART_MSR((p)->membase)) -#define UART_GET_MCR(p) inl(UART_MCR((p)->membase)) -#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase)) -#define UART_GET_MC(p) inl(UART_MC((p)->membase)) -#define UART_PUT_MC(p, c) outl(c,UART_MC((p)->membase)) -#define UART_GET_TSR(p) inl(UART_TSR((p)->membase)) -#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase)) -#define UART_PUT_DIV_HI(p,c) outl(c,UART_DIV_HI((p)->membase)) -#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase)) -#define UART_PUT_DIV_LO(p,c) outl(c,UART_DIV_LO((p)->membase)) -#define UART_RX_DATA(s) ((s) & UART_RSR_RX_LEVEL_MSK) -#define UART_TX_READY(s) (((s) & UART_TSR_TX_LEVEL_MSK) < 15) -//#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0) - -static void uart00_stop_tx(struct uart_port *port) -{ - UART_PUT_IEC(port, UART_IEC_TIE_MSK); -} - -static void uart00_stop_rx(struct uart_port *port) -{ - UART_PUT_IEC(port, UART_IEC_RE_MSK); -} - -static void uart00_enable_ms(struct uart_port *port) -{ - UART_PUT_IES(port, UART_IES_ME_MSK); -} - -static void -uart00_rx_chars(struct uart_port *port, struct pt_regs *regs) -{ - struct tty_struct *tty = port->info->tty; - unsigned int status, ch, rds, flg, ignored = 0; - - status = UART_GET_RSR(port); - while (UART_RX_DATA(status)) { - /* - * We need to read rds before reading the - * character from the fifo - */ - rds = UART_GET_RDS(port); - ch = UART_GET_CHAR(port); - port->icount.rx++; - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; - - flg = TTY_NORMAL; - - /* - * Note that the error handling code is - * out of the main execution path - */ - if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK| - UART_RDS_PE_MSK |UART_RDS_PE_MSK)) - goto handle_error; - if (uart_handle_sysrq_char(port, ch, regs)) - goto ignore_char; - - error_return: - tty_insert_flip_char(tty, ch, flg); - - ignore_char: - status = UART_GET_RSR(port); - } - out: - tty_flip_buffer_push(tty); - return; - - handle_error: - if (rds & UART_RDS_BI_MSK) { - status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK); - port->icount.brk++; - if (uart_handle_break(port)) - goto ignore_char; - } else if (rds & UART_RDS_PE_MSK) - port->icount.parity++; - else if (rds & UART_RDS_FE_MSK) - port->icount.frame++; - if (rds & UART_RDS_OE_MSK) - port->icount.overrun++; - - if (rds & port->ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - rds &= port->read_status_mask; - - if (rds & UART_RDS_BI_MSK) - flg = TTY_BREAK; - else if (rds & UART_RDS_PE_MSK) - flg = TTY_PARITY; - else if (rds & UART_RDS_FE_MSK) - flg = TTY_FRAME; - - if (rds & UART_RDS_OE_MSK) { - /* - * CHECK: does overrun affect the current character? - * ASSUMPTION: it does not. - */ - tty_insert_flip_char(tty, ch, flg); - ch = 0; - flg = TTY_OVERRUN; - } -#ifdef SUPPORT_SYSRQ - port->sysrq = 0; -#endif - goto error_return; -} - -static void uart00_tx_chars(struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - int count; - - if (port->x_char) { - while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15) - barrier(); - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - uart00_stop_tx(port); - return; - } - - count = port->fifosize >> 1; - do { - while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15) - barrier(); - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - uart00_stop_tx(port); -} - -static void uart00_start_tx(struct uart_port *port) -{ - UART_PUT_IES(port, UART_IES_TIE_MSK); - uart00_tx_chars(port); -} - -static void uart00_modem_status(struct uart_port *port) -{ - unsigned int status; - - status = UART_GET_MSR(port); - - if (!(status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | - UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK))) - return; - - if (status & UART_MSR_DDCD_MSK) - uart_handle_dcd_change(port, status & UART_MSR_DCD_MSK); - - if (status & UART_MSR_DDSR_MSK) - port->icount.dsr++; - - if (status & UART_MSR_DCTS_MSK) - uart_handle_cts_change(port, status & UART_MSR_CTS_MSK); - - wake_up_interruptible(&port->info->delta_msr_wait); -} - -static irqreturn_t uart00_int(int irq, void *dev_id, struct pt_regs *regs) -{ - struct uart_port *port = dev_id; - unsigned int status, pass_counter = 0; - - status = UART_GET_INT_STATUS(port); - do { - if (status & UART_ISR_RI_MSK) - uart00_rx_chars(port, regs); - if (status & UART_ISR_MI_MSK) - uart00_modem_status(port); - if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK)) - uart00_tx_chars(port); - if (pass_counter++ > UART00_ISR_PASS_LIMIT) - break; - - status = UART_GET_INT_STATUS(port); - } while (status); - - return IRQ_HANDLED; -} - -static unsigned int uart00_tx_empty(struct uart_port *port) -{ - return UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK? 0 : TIOCSER_TEMT; -} - -static unsigned int uart00_get_mctrl(struct uart_port *port) -{ - unsigned int result = 0; - unsigned int status; - - status = UART_GET_MSR(port); - if (status & UART_MSR_DCD_MSK) - result |= TIOCM_CAR; - if (status & UART_MSR_DSR_MSK) - result |= TIOCM_DSR; - if (status & UART_MSR_CTS_MSK) - result |= TIOCM_CTS; - if (status & UART_MSR_RI_MSK) - result |= TIOCM_RI; - - return result; -} - -static void uart00_set_mctrl_null(struct uart_port *port, unsigned int mctrl) -{ -} - -static void uart00_break_ctl(struct uart_port *port, int break_state) -{ - unsigned long flags; - unsigned int mcr; - - spin_lock_irqsave(&port->lock, flags); - mcr = UART_GET_MCR(port); - if (break_state == -1) - mcr |= UART_MCR_BR_MSK; - else - mcr &= ~UART_MCR_BR_MSK; - UART_PUT_MCR(port, mcr); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void -uart00_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) -{ - unsigned int uart_mc, old_ies, baud, quot; - unsigned long flags; - - /* - * We don't support CREAD (yet) - */ - termios->c_cflag |= CREAD; - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - /* byte size and parity */ - switch (termios->c_cflag & CSIZE) { - case CS5: - uart_mc = UART_MC_CLS_CHARLEN_5; - break; - case CS6: - uart_mc = UART_MC_CLS_CHARLEN_6; - break; - case CS7: - uart_mc = UART_MC_CLS_CHARLEN_7; - break; - default: // CS8 - uart_mc = UART_MC_CLS_CHARLEN_8; - break; - } - if (termios->c_cflag & CSTOPB) - uart_mc|= UART_MC_ST_TWO; - if (termios->c_cflag & PARENB) { - uart_mc |= UART_MC_PE_MSK; - if (!(termios->c_cflag & PARODD)) - uart_mc |= UART_MC_EP_MSK; - } - - spin_lock_irqsave(&port->lock, flags); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART_RDS_OE_MSK; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK; - if (termios->c_iflag & (BRKINT | PARMRK)) - port->read_status_mask |= UART_RDS_BI_MSK; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_RDS_BI_MSK; - /* - * If we're ignoring parity and break indicators, - * ignore overruns to (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_RDS_OE_MSK; - } - - /* first, disable everything */ - old_ies = UART_GET_IES(port); - - if (UART_ENABLE_MS(port, termios->c_cflag)) - old_ies |= UART_IES_ME_MSK; - - /* Set baud rate */ - UART_PUT_DIV_LO(port, (quot & 0xff)); - UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8)); - - UART_PUT_MC(port, uart_mc); - UART_PUT_IES(port, old_ies); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static int uart00_startup(struct uart_port *port) -{ - int result; - - /* - * Allocate the IRQ - */ - result = request_irq(port->irq, uart00_int, 0, "uart00", port); - if (result) { - printk(KERN_ERR "Request of irq %d failed\n", port->irq); - return result; - } - - /* - * Finally, enable interrupts. Use the TII interrupt to minimise - * the number of interrupts generated. If higher performance is - * needed, consider using the TI interrupt with a suitable FIFO - * threshold - */ - UART_PUT_IES(port, UART_IES_RE_MSK | UART_IES_TIE_MSK); - - return 0; -} - -static void uart00_shutdown(struct uart_port *port) -{ - /* - * disable all interrupts, disable the port - */ - UART_PUT_IEC(port, 0xff); - - /* disable break condition and fifos */ - UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK); - - /* - * Free the interrupt - */ - free_irq(port->irq, port); -} - -static const char *uart00_type(struct uart_port *port) -{ - return port->type == PORT_UART00 ? "Altera UART00" : NULL; -} - -/* - * Release the memory region(s) being used by 'port' - */ -static void uart00_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, UART_PORT_SIZE); - -#ifdef CONFIG_ARCH_CAMELOT - if (port->membase != (void*)IO_ADDRESS(EXC_UART00_BASE)) { - iounmap(port->membase); - } -#endif -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int uart00_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_uart00") - != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void uart00_config_port(struct uart_port *port, int flags) -{ - - /* - * Map the io memory if this is a soft uart - */ - if (!port->membase) - port->membase = ioremap_nocache(port->mapbase,SZ_4K); - - if (!port->membase) - printk(KERN_ERR "serial00: cannot map io memory\n"); - else - port->type = PORT_UART00; - -} - -/* - * verify the new serial_struct (for TIOCSSERIAL). - */ -static int uart00_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= NR_IRQS) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops uart00_pops = { - .tx_empty = uart00_tx_empty, - .set_mctrl = uart00_set_mctrl_null, - .get_mctrl = uart00_get_mctrl, - .stop_tx = uart00_stop_tx, - .start_tx = uart00_start_tx, - .stop_rx = uart00_stop_rx, - .enable_ms = uart00_enable_ms, - .break_ctl = uart00_break_ctl, - .startup = uart00_startup, - .shutdown = uart00_shutdown, - .set_termios = uart00_set_termios, - .type = uart00_type, - .release_port = uart00_release_port, - .request_port = uart00_request_port, - .config_port = uart00_config_port, - .verify_port = uart00_verify_port, -}; - - -#ifdef CONFIG_ARCH_CAMELOT -static struct uart_port epxa10db_port = { - .membase = (void*)IO_ADDRESS(EXC_UART00_BASE), - .mapbase = EXC_UART00_BASE, - .iotype = SERIAL_IO_MEM, - .irq = IRQ_UART, - .uartclk = EXC_AHB2_CLK_FREQUENCY, - .fifosize = 16, - .ops = &uart00_pops, - .flags = ASYNC_BOOT_AUTOCONF, -}; -#endif - - -#ifdef CONFIG_SERIAL_UART00_CONSOLE -static void uart00_console_write(struct console *co, const char *s, unsigned count) -{ -#ifdef CONFIG_ARCH_CAMELOT - struct uart_port *port = &epxa10db_port; - unsigned int status, old_ies; - int i; - - /* - * First save the CR then disable the interrupts - */ - old_ies = UART_GET_IES(port); - UART_PUT_IEC(port,0xff); - - /* - * Now, do each character - */ - for (i = 0; i < count; i++) { - do { - status = UART_GET_TSR(port); - } while (!UART_TX_READY(status)); - UART_PUT_CHAR(port, s[i]); - if (s[i] == '\n') { - do { - status = UART_GET_TSR(port); - } while (!UART_TX_READY(status)); - UART_PUT_CHAR(port, '\r'); - } - } - - /* - * Finally, wait for transmitter to become empty - * and restore the IES - */ - do { - status = UART_GET_TSR(port); - } while (status & UART_TSR_TX_LEVEL_MSK); - UART_PUT_IES(port, old_ies); -#endif -} - -static void __init -uart00_console_get_options(struct uart_port *port, int *baud, - int *parity, int *bits) -{ - unsigned int uart_mc, quot; - - uart_mc = UART_GET_MC(port); - - *parity = 'n'; - if (uart_mc & UART_MC_PE_MSK) { - if (uart_mc & UART_MC_EP_MSK) - *parity = 'e'; - else - *parity = 'o'; - } - - switch (uart_mc & UART_MC_CLS_MSK) { - case UART_MC_CLS_CHARLEN_5: - *bits = 5; - break; - case UART_MC_CLS_CHARLEN_6: - *bits = 6; - break; - case UART_MC_CLS_CHARLEN_7: - *bits = 7; - break; - case UART_MC_CLS_CHARLEN_8: - *bits = 8; - break; - } - quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8); - *baud = port->uartclk / (16 *quot ); -} - -static int __init uart00_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - -#ifdef CONFIG_ARCH_CAMELOT - port = &epxa10db_port; ; -#else - return -ENODEV; -#endif - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - uart00_console_get_options(port, &baud, &parity, &bits); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -extern struct uart_driver uart00_reg; -static struct console uart00_console = { - .name = SERIAL_UART00_NAME, - .write = uart00_console_write, - .device = uart_console_device, - .setup = uart00_console_setup, - .flags = CON_PRINTBUFFER, - .index = 0, - .data = &uart00_reg, -}; - -static int __init uart00_console_init(void) -{ - register_console(&uart00_console); - return 0; -} -console_initcall(uart00_console_init); - -#define UART00_CONSOLE &uart00_console -#else -#define UART00_CONSOLE NULL -#endif - -static struct uart_driver uart00_reg = { - .owner = NULL, - .driver_name = SERIAL_UART00_NAME, - .dev_name = SERIAL_UART00_NAME, - .major = SERIAL_UART00_MAJOR, - .minor = SERIAL_UART00_MINOR, - .nr = UART_NR, - .cons = UART00_CONSOLE, -}; - -struct dev_port_entry{ - unsigned int base_addr; - struct uart_port *port; -}; - -#ifdef CONFIG_PLD_HOTSWAP - -static struct dev_port_entry dev_port_map[UART_NR]; - -/* - * Keep a mapping of dev_info addresses -> port lines to use when - * removing ports dev==NULL indicates unused entry - */ - -struct uart00_ps_data{ - unsigned int clk; - unsigned int fifosize; -}; - -int uart00_add_device(struct pldhs_dev_info* dev_info, void* dev_ps_data) -{ - struct uart00_ps_data* dev_ps=dev_ps_data; - struct uart_port * port; - int i,result; - - i=0; - while(dev_port_map[i].port) - i++; - - if(i==UART_NR){ - printk(KERN_WARNING "uart00: Maximum number of ports reached\n"); - return 0; - } - - port=kmalloc(sizeof(struct uart_port),GFP_KERNEL); - if(!port) - return -ENOMEM; - - printk("clk=%d fifo=%d\n",dev_ps->clk,dev_ps->fifosize); - port->membase=0; - port->mapbase=dev_info->base_addr; - port->iotype=SERIAL_IO_MEM; - port->irq=dev_info->irq; - port->uartclk=dev_ps->clk; - port->fifosize=dev_ps->fifosize; - port->ops=&uart00_pops; - port->line=i; - port->flags=ASYNC_BOOT_AUTOCONF; - - result=uart_add_one_port(&uart00_reg, port); - if(result){ - printk("uart_add_one_port returned %d\n",result); - return result; - } - dev_port_map[i].base_addr=dev_info->base_addr; - dev_port_map[i].port=port; - printk("uart00: added device at %x as ttyUA%d\n",dev_port_map[i].base_addr,i); - return 0; - -} - -int uart00_remove_devices(void) -{ - int i,result; - - - result=0; - for(i=1;i -#define UART00_TYPE -#include - - .macro addruart,rx - mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @ MMU enabled? - ldr \rx, =EXC_UART00_BASE @ physical base address - orrne \rx, \rx, #0xff000000 @ virtual base - orrne \rx, \rx, #0x00f00000 - .endm - - .macro senduart,rd,rx - str \rd, [\rx, #UART_TD(0)] - .endm - - .macro waituart,rd,rx -1001: ldr \rd, [\rx, #UART_TSR(0)] - and \rd, \rd, #UART_TSR_TX_LEVEL_MSK - cmp \rd, #15 - beq 1001b - .endm - - .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #UART_TSR(0)] - ands \rd, \rd, #UART_TSR_TX_LEVEL_MSK - bne 1001b - .endm diff --git a/include/asm-arm/arch-epxa10db/dma.h b/include/asm-arm/arch-epxa10db/dma.h deleted file mode 100644 index de20ec8e74b1..000000000000 --- a/include/asm-arm/arch-epxa10db/dma.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * linux/include/asm-arm/arch-camelot/dma.h - * - * Copyright (C) 1997,1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ diff --git a/include/asm-arm/arch-epxa10db/entry-macro.S b/include/asm-arm/arch-epxa10db/entry-macro.S deleted file mode 100644 index de6ae08334e2..000000000000 --- a/include/asm-arm/arch-epxa10db/entry-macro.S +++ /dev/null @@ -1,25 +0,0 @@ -/* - * include/asm-arm/arch-epxa10db/entry-macro.S - * - * Low-level IRQ helper macros for epxa10db platform - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include -#undef IRQ_MODE /* same name defined in asm/proc/ptrace.h */ -#include - - .macro disable_fiq - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - - ldr \irqstat, =INT_ID(IO_ADDRESS(EXC_INT_CTRL00_BASE)) - ldr \irqnr,[\irqstat] - cmp \irqnr,#0 - subne \irqnr,\irqnr,#1 - - .endm - diff --git a/include/asm-arm/arch-epxa10db/ether00.h b/include/asm-arm/arch-epxa10db/ether00.h deleted file mode 100644 index b737b8aabe2f..000000000000 --- a/include/asm-arm/arch-epxa10db/ether00.h +++ /dev/null @@ -1,482 +0,0 @@ -#ifndef __ETHER00_H -#define __ETHER00_H - - - -/* - * Register definitions for the Ethernet MAC - */ - -/* - * Copyright (c) Altera Corporation 2000. - * All rights reserved. - */ - -/* -* Structures for the DMA controller -*/ -typedef struct fda_desc - { - struct fda_desc * FDNext; - long FDSystem; - long FDStat; - short FDLength; - short FDCtl; - }FDA_DESC; - -typedef struct buf_desc - { - char * BuffData; - short BuffLength; - char BDStat; - char BDCtl; - }BUF_DESC; - -/* -* Control masks for the DMA controller -*/ -#define FDCTL_BDCOUNT_MSK (0x1F) -#define FDCTL_BDCOUNT_OFST (0) -#define FDCTL_FRMOPT_MSK (0x7C00) -#define FDCTL_FRMOPT_OFST (10) -#define FDCTL_COWNSFD_MSK (0x8000) -#define FDCTL_COWNSFD_OFST (15) - -#define BDCTL_RXBDSEQN_MSK (0x7F) -#define BDCTL_RXBDSEQN_OFST (0) -#define BDCTL_COWNSBD_MSK (0x80) -#define BDCTL_COWNSBD_OFST (7) - -#define FDNEXT_EOL_MSK (0x1) -#define FDNEXT_EOL_OFST (0) -#define FDNEXT_EOL_POINTER_MSK (0xFFFFFFF0) -#define FDNEXT_EOL_POINTER_OFST (4) - -#define ETHER_ARC_SIZE (21) - -/* -* Register definitions and masks -*/ -#define ETHER_DMA_CTL(base) (ETHER00_TYPE (base + 0x100)) -#define ETHER_DMA_CTL_DMBURST_OFST (2) -#define ETHER_DMA_CTL_DMBURST_MSK (0x1FC) -#define ETHER_DMA_CTL_POWRMGMNT_OFST (11) -#define ETHER_DMA_CTL_POWRMGMNT_MSK (0x1000) -#define ETHER_DMA_CTL_TXBIGE_OFST (14) -#define ETHER_DMA_CTL_TXBIGE_MSK (0x4000) -#define ETHER_DMA_CTL_RXBIGE_OFST (15) -#define ETHER_DMA_CTL_RXBIGE_MSK (0x8000) -#define ETHER_DMA_CTL_TXWAKEUP_OFST (16) -#define ETHER_DMA_CTL_TXWAKEUP_MSK (0x10000) -#define ETHER_DMA_CTL_SWINTREQ_OFST (17) -#define ETHER_DMA_CTL_SWINTREQ_MSK (0x20000) -#define ETHER_DMA_CTL_INTMASK_OFST (18) -#define ETHER_DMA_CTL_INTMASK_MSK (0x40000) -#define ETHER_DMA_CTL_M66ENSTAT_OFST (19) -#define ETHER_DMA_CTL_M66ENSTAT_MSK (0x80000) -#define ETHER_DMA_CTL_RMTXINIT_OFST (20) -#define ETHER_DMA_CTL_RMTXINIT_MSK (0x100000) -#define ETHER_DMA_CTL_RMRXINIT_OFST (21) -#define ETHER_DMA_CTL_RMRXINIT_MSK (0x200000) -#define ETHER_DMA_CTL_RXALIGN_OFST (22) -#define ETHER_DMA_CTL_RXALIGN_MSK (0xC00000) -#define ETHER_DMA_CTL_RMSWRQ_OFST (24) -#define ETHER_DMA_CTL_RMSWRQ_MSK (0x1000000) -#define ETHER_DMA_CTL_RMEMBANK_OFST (25) -#define ETHER_DMA_CTL_RMEMBANK_MSK (0x2000000) - -#define ETHER_TXFRMPTR(base) (ETHER00_TYPE (base + 0x104)) - -#define ETHER_TXTHRSH(base) (ETHER00_TYPE (base + 0x308)) - -#define ETHER_TXPOLLCTR(base) (ETHER00_TYPE (base + 0x30c)) - -#define ETHER_BLFRMPTR(base) (ETHER00_TYPE (base + 0x110)) -#define ETHER_BLFFRMPTR_EOL_OFST (0) -#define ETHER_BLFFRMPTR_EOL_MSK (0x1) -#define ETHER_BLFFRMPTR_ADDRESS_OFST (4) -#define ETHER_BLFFRMPTR_ADDRESS_MSK (0xFFFFFFF0) - -#define ETHER_RXFRAGSIZE(base) (ETHER00_TYPE (base + 0x114)) -#define ETHER_RXFRAGSIZE_MINFRAG_OFST (2) -#define ETHER_RXFRAGSIZE_MINFRAG_MSK (0xFFC) -#define ETHER_RXFRAGSIZE_ENPACK_OFST (15) -#define ETHER_RXFRAGSIZE_ENPACK_MSK (0x8000) - -#define ETHER_INT_EN(base) (ETHER00_TYPE (base + 0x118)) -#define ETHER_INT_EN_FDAEXEN_OFST (0) -#define ETHER_INT_EN_FDAEXEN_MSK (0x1) -#define ETHER_INT_EN_BLEXEN_OFST (1) -#define ETHER_INT_EN_BLEXN_MSK (0x2) -#define ETHER_INT_EN_STARGABTEN_OFST (2) -#define ETHER_INT_EN_STARGABTEN_MSK (0x4) -#define ETHER_INT_EN_RTARGABTEN_OFST (3) -#define ETHER_INT_EN_RTARGABTEN_MSK (0x8) -#define ETHER_INT_EN_RMASABTEN_OFST (4) -#define ETHER_INT_EN_RMASABTEN_MSK (0x10) -#define ETHER_INT_EN_SSYSERREN_OFST (5) -#define ETHER_INT_EN_SSYSERREN_MSK (0x20) -#define ETHER_INT_EN_DPARERREN_OFST (6) -#define ETHER_INT_EN_DPARERREN_MSK (0x40) -#define ETHER_INT_EN_EARNOTEN_OFST (7) -#define ETHER_INT_EN_EARNOTEN_MSK (0x80) -#define ETHER_INT_EN_DPARDEN_OFST (8) -#define ETHER_INT_EN_DPARDEN_MSK (0x100) -#define ETHER_INT_EN_DMPARERREN_OFST (9) -#define ETHER_INT_EN_DMPARERREN_MSK (0x200) -#define ETHER_INT_EN_TXCTLCMPEN_OFST (10) -#define ETHER_INT_EN_TXCTLCMPEN_MSK (0x400) -#define ETHER_INT_EN_NRABTEN_OFST (11) -#define ETHER_INT_EN_NRABTEN_MSK (0x800) - -#define ETHER_FDA_BAS(base) (ETHER00_TYPE (base + 0x11C)) -#define ETHER_FDA_BAS_ADDRESS_OFST (4) -#define ETHER_FDA_BAS_ADDRESS_MSK (0xFFFFFFF0) - -#define ETHER_FDA_LIM(base) (ETHER00_TYPE (base + 0x120)) -#define ETHER_FDA_LIM_COUNT_OFST (4) -#define ETHER_FDA_LIM_COUNT_MSK (0xFFF0) - -#define ETHER_INT_SRC(base) (ETHER00_TYPE (base + 0x124)) -#define ETHER_INT_SRC_INTMACTX_OFST (0) -#define ETHER_INT_SRC_INTMACTX_MSK (0x1) -#define ETHER_INT_SRC_INTMACRX_OFST (1) -#define ETHER_INT_SRC_INTMACRX_MSK (0x2) -#define ETHER_INT_SRC_INTSBUS_OFST (2) -#define ETHER_INT_SRC_INTSBUS_MSK (0x4) -#define ETHER_INT_SRC_INTFDAEX_OFST (3) -#define ETHER_INT_SRC_INTFDAEX_MSK (0x8) -#define ETHER_INT_SRC_INTBLEX_OFST (4) -#define ETHER_INT_SRC_INTBLEX_MSK (0x10) -#define ETHER_INT_SRC_SWINT_OFST (5) -#define ETHER_INT_SRC_SWINT_MSK (0x20) -#define ETHER_INT_SRC_INTEARNOT_OFST (6) -#define ETHER_INT_SRC_INTEARNOT_MSK (0x40) -#define ETHER_INT_SRC_DMPARERR_OFST (7) -#define ETHER_INT_SRC_DMPARERR_MSK (0x80) -#define ETHER_INT_SRC_INTEXBD_OFST (8) -#define ETHER_INT_SRC_INTEXBD_MSK (0x100) -#define ETHER_INT_SRC_INTTXCTLCMP_OFST (9) -#define ETHER_INT_SRC_INTTXCTLCMP_MSK (0x200) -#define ETHER_INT_SRC_INTNRABT_OFST (10) -#define ETHER_INT_SRC_INTNRABT_MSK (0x400) -#define ETHER_INT_SRC_FDAEX_OFST (11) -#define ETHER_INT_SRC_FDAEX_MSK (0x800) -#define ETHER_INT_SRC_BLEX_OFST (12) -#define ETHER_INT_SRC_BLEX_MSK (0x1000) -#define ETHER_INT_SRC_DMPARERRSTAT_OFST (13) -#define ETHER_INT_SRC_DMPARERRSTAT_MSK (0x2000) -#define ETHER_INT_SRC_NRABT_OFST (14) -#define ETHER_INT_SRC_NRABT_MSK (0x4000) -#define ETHER_INT_SRC_INTLINK_OFST (15) -#define ETHER_INT_SRC_INTLINK_MSK (0x8000) -#define ETHER_INT_SRC_INTEXDEFER_OFST (16) -#define ETHER_INT_SRC_INTEXDEFER_MSK (0x10000) -#define ETHER_INT_SRC_INTRMON_OFST (17) -#define ETHER_INT_SRC_INTRMON_MSK (0x20000) -#define ETHER_INT_SRC_IRQ_MSK (0x83FF) - -#define ETHER_PAUSECNT(base) (ETHER00_TYPE (base + 0x40)) -#define ETHER_PAUSECNT_COUNT_OFST (0) -#define ETHER_PAUSECNT_COUNT_MSK (0xFFFF) - -#define ETHER_REMPAUCNT(base) (ETHER00_TYPE (base + 0x44)) -#define ETHER_REMPAUCNT_COUNT_OFST (0) -#define ETHER_REMPAUCNT_COUNT_MSK (0xFFFF) - -#define ETHER_TXCONFRMSTAT(base) (ETHER00_TYPE (base + 0x348)) -#define ETHER_TXCONFRMSTAT_TS_STAT_VALUE_OFST (0) -#define ETHER_TXCONFRMSTAT_TS_STAT_VALUE_MSK (0x3FFFFF) - -#define ETHER_MAC_CTL(base) (ETHER00_TYPE (base + 0)) -#define ETHER_MAC_CTL_HALTREQ_OFST (0) -#define ETHER_MAC_CTL_HALTREQ_MSK (0x1) -#define ETHER_MAC_CTL_HALTIMM_OFST (1) -#define ETHER_MAC_CTL_HALTIMM_MSK (0x2) -#define ETHER_MAC_CTL_RESET_OFST (2) -#define ETHER_MAC_CTL_RESET_MSK (0x4) -#define ETHER_MAC_CTL_FULLDUP_OFST (3) -#define ETHER_MAC_CTL_FULLDUP_MSK (0x8) -#define ETHER_MAC_CTL_MACLOOP_OFST (4) -#define ETHER_MAC_CTL_MACLOOP_MSK (0x10) -#define ETHER_MAC_CTL_CONN_OFST (5) -#define ETHER_MAC_CTL_CONN_MSK (0x60) -#define ETHER_MAC_CTL_LOOP10_OFST (7) -#define ETHER_MAC_CTL_LOOP10_MSK (0x80) -#define ETHER_MAC_CTL_LNKCHG_OFST (8) -#define ETHER_MAC_CTL_LNKCHG_MSK (0x100) -#define ETHER_MAC_CTL_MISSROLL_OFST (10) -#define ETHER_MAC_CTL_MISSROLL_MSK (0x400) -#define ETHER_MAC_CTL_ENMISSROLL_OFST (13) -#define ETHER_MAC_CTL_ENMISSROLL_MSK (0x2000) -#define ETHER_MAC_CTL_LINK10_OFST (15) -#define ETHER_MAC_CTL_LINK10_MSK (0x8000) - -#define ETHER_ARC_CTL(base) (ETHER00_TYPE (base + 0x4)) -#define ETHER_ARC_CTL_STATIONACC_OFST (0) -#define ETHER_ARC_CTL_STATIONACC_MSK (0x1) -#define ETHER_ARC_CTL_GROUPACC_OFST (1) -#define ETHER_ARC_CTL_GROUPACC_MSK (0x2) -#define ETHER_ARC_CTL_BROADACC_OFST (2) -#define ETHER_ARC_CTL_BROADACC_MSK (0x4) -#define ETHER_ARC_CTL_NEGARC_OFST (3) -#define ETHER_ARC_CTL_NEGARC_MSK (0x8) -#define ETHER_ARC_CTL_COMPEN_OFST (4) -#define ETHER_ARC_CTL_COMPEN_MSK (0x10) - -#define ETHER_TX_CTL(base) (ETHER00_TYPE (base + 0x8)) -#define ETHER_TX_CTL_TXEN_OFST (0) -#define ETHER_TX_CTL_TXEN_MSK (0x1) -#define ETHER_TX_CTL_TXHALT_OFST (1) -#define ETHER_TX_CTL_TXHALT_MSK (0x2) -#define ETHER_TX_CTL_NOPAD_OFST (2) -#define ETHER_TX_CTL_NOPAD_MSK (0x4) -#define ETHER_TX_CTL_NOCRC_OFST (3) -#define ETHER_TX_CTL_NOCRC_MSK (0x8) -#define ETHER_TX_CTL_FBACK_OFST (4) -#define ETHER_TX_CTL_FBACK_MSK (0x10) -#define ETHER_TX_CTL_NOEXDEF_OFST (5) -#define ETHER_TX_CTL_NOEXDEF_MSK (0x20) -#define ETHER_TX_CTL_SDPAUSE_OFST (6) -#define ETHER_TX_CTL_SDPAUSE_MSK (0x40) -#define ETHER_TX_CTL_MII10_OFST (7) -#define ETHER_TX_CTL_MII10_MSK (0x80) -#define ETHER_TX_CTL_ENUNDER_OFST (8) -#define ETHER_TX_CTL_ENUNDER_MSK (0x100) -#define ETHER_TX_CTL_ENEXDEFER_OFST (9) -#define ETHER_TX_CTL_ENEXDEFER_MSK (0x200) -#define ETHER_TX_CTL_ENLCARR_OFST (10) -#define ETHER_TX_CTL_ENLCARR_MSK (0x400) -#define ETHER_TX_CTL_ENEXCOLL_OFST (11) -#define ETHER_TX_CTL_ENEXCOLL_MSK (0x800) -#define ETHER_TX_CTL_ENLATECOLL_OFST (12) -#define ETHER_TX_CTL_ENLATECOLL_MSK (0x1000) -#define ETHER_TX_CTL_ENTXPAR_OFST (13) -#define ETHER_TX_CTL_ENTXPAR_MSK (0x2000) -#define ETHER_TX_CTL_ENCOMP_OFST (14) -#define ETHER_TX_CTL_ENCOMP_MSK (0x4000) - -#define ETHER_TX_STAT(base) (ETHER00_TYPE (base + 0xc)) -#define ETHER_TX_STAT_TXCOLL_OFST (0) -#define ETHER_TX_STAT_TXCOLL_MSK (0xF) -#define ETHER_TX_STAT_EXCOLL_OFST (4) -#define ETHER_TX_STAT_EXCOLL_MSK (0x10) -#define ETHER_TX_STAT_TXDEFER_OFST (5) -#define ETHER_TX_STAT_TXDEFER_MSK (0x20) -#define ETHER_TX_STAT_PAUSED_OFST (6) -#define ETHER_TX_STAT_PAUSED_MSK (0x40) -#define ETHER_TX_STAT_INTTX_OFST (7) -#define ETHER_TX_STAT_INTTX_MSK (0x80) -#define ETHER_TX_STAT_UNDER_OFST (8) -#define ETHER_TX_STAT_UNDER_MSK (0x100) -#define ETHER_TX_STAT_EXDEFER_OFST (9) -#define ETHER_TX_STAT_EXDEFER_MSK (0x200) -#define ETHER_TX_STAT_LCARR_OFST (10) -#define ETHER_TX_STAT_LCARR_MSK (0x400) -#define ETHER_TX_STAT_TX10STAT_OFST (11) -#define ETHER_TX_STAT_TX10STAT_MSK (0x800) -#define ETHER_TX_STAT_LATECOLL_OFST (12) -#define ETHER_TX_STAT_LATECOLL_MSK (0x1000) -#define ETHER_TX_STAT_TXPAR_OFST (13) -#define ETHER_TX_STAT_TXPAR_MSK (0x2000) -#define ETHER_TX_STAT_COMP_OFST (14) -#define ETHER_TX_STAT_COMP_MSK (0x4000) -#define ETHER_TX_STAT_TXHALTED_OFST (15) -#define ETHER_TX_STAT_TXHALTED_MSK (0x8000) -#define ETHER_TX_STAT_SQERR_OFST (16) -#define ETHER_TX_STAT_SQERR_MSK (0x10000) -#define ETHER_TX_STAT_TXMCAST_OFST (17) -#define ETHER_TX_STAT_TXMCAST_MSK (0x20000) -#define ETHER_TX_STAT_TXBCAST_OFST (18) -#define ETHER_TX_STAT_TXBCAST_MSK (0x40000) -#define ETHER_TX_STAT_VLAN_OFST (19) -#define ETHER_TX_STAT_VLAN_MSK (0x80000) -#define ETHER_TX_STAT_MACC_OFST (20) -#define ETHER_TX_STAT_MACC_MSK (0x100000) -#define ETHER_TX_STAT_TXPAUSE_OFST (21) -#define ETHER_TX_STAT_TXPAUSE_MSK (0x200000) - -#define ETHER_RX_CTL(base) (ETHER00_TYPE (base + 0x10)) -#define ETHER_RX_CTL_RXEN_OFST (0) -#define ETHER_RX_CTL_RXEN_MSK (0x1) -#define ETHER_RX_CTL_RXHALT_OFST (1) -#define ETHER_RX_CTL_RXHALT_MSK (0x2) -#define ETHER_RX_CTL_LONGEN_OFST (2) -#define ETHER_RX_CTL_LONGEN_MSK (0x4) -#define ETHER_RX_CTL_SHORTEN_OFST (3) -#define ETHER_RX_CTL_SHORTEN_MSK (0x8) -#define ETHER_RX_CTL_STRIPCRC_OFST (4) -#define ETHER_RX_CTL_STRIPCRC_MSK (0x10) -#define ETHER_RX_CTL_PASSCTL_OFST (5) -#define ETHER_RX_CTL_PASSCTL_MSK (0x20) -#define ETHER_RX_CTL_IGNORECRC_OFST (6) -#define ETHER_RX_CTL_IGNORECRC_MSK (0x40) -#define ETHER_RX_CTL_ENALIGN_OFST (8) -#define ETHER_RX_CTL_ENALIGN_MSK (0x100) -#define ETHER_RX_CTL_ENCRCERR_OFST (9) -#define ETHER_RX_CTL_ENCRCERR_MSK (0x200) -#define ETHER_RX_CTL_ENOVER_OFST (10) -#define ETHER_RX_CTL_ENOVER_MSK (0x400) -#define ETHER_RX_CTL_ENLONGERR_OFST (11) -#define ETHER_RX_CTL_ENLONGERR_MSK (0x800) -#define ETHER_RX_CTL_ENRXPAR_OFST (13) -#define ETHER_RX_CTL_ENRXPAR_MSK (0x2000) -#define ETHER_RX_CTL_ENGOOD_OFST (14) -#define ETHER_RX_CTL_ENGOOD_MSK (0x4000) - -#define ETHER_RX_STAT(base) (ETHER00_TYPE (base + 0x14)) -#define ETHER_RX_STAT_LENERR_OFST (4) -#define ETHER_RX_STAT_LENERR_MSK (0x10) -#define ETHER_RX_STAT_CTLRECD_OFST (5) -#define ETHER_RX_STAT_CTLRECD_MSK (0x20) -#define ETHER_RX_STAT_INTRX_OFST (6) -#define ETHER_RX_STAT_INTRX_MSK (0x40) -#define ETHER_RX_STAT_RX10STAT_OFST (7) -#define ETHER_RX_STAT_RX10STAT_MSK (0x80) -#define ETHER_RX_STAT_ALIGNERR_OFST (8) -#define ETHER_RX_STAT_ALIGNERR_MSK (0x100) -#define ETHER_RX_STAT_CRCERR_OFST (9) -#define ETHER_RX_STAT_CRCERR_MSK (0x200) -#define ETHER_RX_STAT_OVERFLOW_OFST (10) -#define ETHER_RX_STAT_OVERFLOW_MSK (0x400) -#define ETHER_RX_STAT_LONGERR_OFST (11) -#define ETHER_RX_STAT_LONGERR_MSK (0x800) -#define ETHER_RX_STAT_RXPAR_OFST (13) -#define ETHER_RX_STAT_RXPAR_MSK (0x2000) -#define ETHER_RX_STAT_GOOD_OFST (14) -#define ETHER_RX_STAT_GOOD_MSK (0x4000) -#define ETHER_RX_STAT_RXHALTED_OFST (15) -#define ETHER_RX_STAT_RXHALTED_MSK (0x8000) -#define ETHER_RX_STAT_RXMCAST_OFST (17) -#define ETHER_RX_STAT_RXMCAST_MSK (0x10000) -#define ETHER_RX_STAT_RXBCAST_OFST (18) -#define ETHER_RX_STAT_RXBCAST_MSK (0x20000) -#define ETHER_RX_STAT_RXVLAN_OFST (19) -#define ETHER_RX_STAT_RXVLAN_MSK (0x40000) -#define ETHER_RX_STAT_RXPAUSE_OFST (20) -#define ETHER_RX_STAT_RXPAUSE_MSK (0x80000) -#define ETHER_RX_STAT_ARCSTATUS_OFST (21) -#define ETHER_RX_STAT_ARCSTATUS_MSK (0xF00000) -#define ETHER_RX_STAT_ARCENT_OFST (25) -#define ETHER_RX_STAT_ARCENT_MSK (0x1F000000) - -#define ETHER_MD_DATA(base) (ETHER00_TYPE (base + 0x18)) - -#define ETHER_MD_CA(base) (ETHER00_TYPE (base + 0x1c)) -#define ETHER_MD_CA_ADDR_OFST (0) -#define ETHER_MD_CA_ADDR_MSK (0x1F) -#define ETHER_MD_CA_PHY_OFST (5) -#define ETHER_MD_CA_PHY_MSK (0x3E0) -#define ETHER_MD_CA_WR_OFST (10) -#define ETHER_MD_CA_WR_MSK (0x400) -#define ETHER_MD_CA_BUSY_OFST (11) -#define ETHER_MD_CA_BUSY_MSK (0x800) -#define ETHER_MD_CA_PRESUPP_OFST (12) -#define ETHER_MD_CA_PRESUPP_MSK (0x1000) - -#define ETHER_ARC_ADR(base) (ETHER00_TYPE (base + 0x160)) -#define ETHER_ARC_ADR_ARC_LOC_OFST (2) -#define ETHER_ARC_ADR_ARC_LOC_MSK (0xFFC) - -#define ETHER_ARC_DATA(base) (ETHER00_TYPE (base + 0x364)) - -#define ETHER_ARC_ENA(base) (ETHER00_TYPE (base + 0x28)) -#define ETHER_ARC_ENA_MSK (0x1FFFFF) - -#define ETHER_PROM_CTL(base) (ETHER00_TYPE (base + 0x2c)) -#define ETHER_PROM_CTL_PROM_ADDR_OFST (0) -#define ETHER_PROM_CTL_PROM_ADDR_MSK (0x3F) -#define ETHER_PROM_CTL_OPCODE_OFST (13) -#define ETHER_PROM_CTL_OPCODE_MSK (0x6000) -#define ETHER_PROM_CTL_OPCODE_READ_MSK (0x4000) -#define ETHER_PROM_CTL_OPCODE_WRITE_MSK (0x2000) -#define ETHER_PROM_CTL_OPCODE_ERASE_MSK (0x6000) -#define ETHER_PROM_CTL_ENABLE_MSK (0x0030) -#define ETHER_PROM_CTL_DISABLE_MSK (0x0000) -#define ETHER_PROM_CTL_BUSY_OFST (15) -#define ETHER_PROM_CTL_BUSY_MSK (0x8000) - -#define ETHER_PROM_DATA(base) (ETHER00_TYPE (base + 0x30)) - -#define ETHER_MISS_CNT(base) (ETHER00_TYPE (base + 0x3c)) -#define ETHER_MISS_CNT_COUNT_OFST (0) -#define ETHER_MISS_CNT_COUNT_MSK (0xFFFF) - -#define ETHER_CNTDATA(base) (ETHER00_TYPE (base + 0x80)) - -#define ETHER_CNTACC(base) (ETHER00_TYPE (base + 0x84)) -#define ETHER_CNTACC_ADDR_OFST (0) -#define ETHER_CNTACC_ADDR_MSK (0xFF) -#define ETHER_CNTACC_WRRDN_OFST (8) -#define ETHER_CNTACC_WRRDN_MSK (0x100) -#define ETHER_CNTACC_CLEAR_OFST (9) -#define ETHER_CNTACC_CLEAR_MSK (0x200) - -#define ETHER_TXRMINTEN(base) (ETHER00_TYPE (base + 0x88)) -#define ETHER_TXRMINTEN_MSK (0x3FFFFFFF) - -#define ETHER_RXRMINTEN(base) (ETHER00_TYPE (base + 0x8C)) -#define ETHER_RXRMINTEN_MSK (0xFFFFFF) - -/* -* RMON Registers -*/ -#define RMON_COLLISION0 0x0 -#define RMON_COLLISION1 0x1 -#define RMON_COLLISION2 0x2 -#define RMON_COLLISION3 0x3 -#define RMON_COLLISION4 0x4 -#define RMON_COLLISION5 0x5 -#define RMON_COLLISION6 0x6 -#define RMON_COLLISION7 0x7 -#define RMON_COLLISION8 0x8 -#define RMON_COLLISION9 0x9 -#define RMON_COLLISION10 0xa -#define RMON_COLLISION11 0xb -#define RMON_COLLISION12 0xc -#define RMON_COLLISION13 0xd -#define RMON_COLLISION14 0xe -#define RMON_COLLISION15 0xf -#define RMON_COLLISION16 0x10 -#define RMON_FRAMES_WITH_DEFERRED_XMISSIONS 0x11 -#define RMON_LATE_COLLISIONS 0x12 -#define RMON_FRAMES_LOST_DUE_TO_MAC_XMIT 0x13 -#define RMON_CARRIER_SENSE_ERRORS 0x14 -#define RMON_FRAMES_WITH_EXCESSIVE_DEFERAL 0x15 -#define RMON_UNICAST_FRAMES_TRANSMITTED_OK 0x16 -#define RMON_MULTICAST_FRAMES_XMITTED_OK 0x17 -#define RMON_BROADCAST_FRAMES_XMITTED_OK 0x18 -#define RMON_SQE_TEST_ERRORS 0x19 -#define RMON_PAUSE_MACCTRL_FRAMES_XMITTED 0x1A -#define RMON_MACCTRL_FRAMES_XMITTED 0x1B -#define RMON_VLAN_FRAMES_XMITTED 0x1C -#define RMON_OCTETS_XMITTED_OK 0x1D -#define RMON_OCTETS_XMITTED_OK_HI 0x1E - -#define RMON_RX_PACKET_SIZES0 0x40 -#define RMON_RX_PACKET_SIZES1 0x41 -#define RMON_RX_PACKET_SIZES2 0x42 -#define RMON_RX_PACKET_SIZES3 0x43 -#define RMON_RX_PACKET_SIZES4 0x44 -#define RMON_RX_PACKET_SIZES5 0x45 -#define RMON_RX_PACKET_SIZES6 0x46 -#define RMON_RX_PACKET_SIZES7 0x47 -#define RMON_FRAME_CHECK_SEQUENCE_ERRORS 0x48 -#define RMON_ALIGNMENT_ERRORS 0x49 -#define RMON_FRAGMENTS 0x4A -#define RMON_JABBERS 0x4B -#define RMON_FRAMES_LOST_TO_INTMACRCVERR 0x4C -#define RMON_UNICAST_FRAMES_RCVD_OK 0x4D -#define RMON_MULTICAST_FRAMES_RCVD_OK 0x4E -#define RMON_BROADCAST_FRAMES_RCVD_OK 0x4F -#define RMON_IN_RANGE_LENGTH_ERRORS 0x50 -#define RMON_OUT_OF_RANGE_LENGTH_ERRORS 0x51 -#define RMON_VLAN_FRAMES_RCVD 0x52 -#define RMON_PAUSE_MAC_CTRL_FRAMES_RCVD 0x53 -#define RMON_MAC_CTRL_FRAMES_RCVD 0x54 -#define RMON_OCTETS_RCVD_OK 0x55 -#define RMON_OCTETS_RCVD_OK_HI 0x56 -#define RMON_OCTETS_RCVD_OTHER 0x57 -#define RMON_OCTETS_RCVD_OTHER_HI 0x58 - -#endif /* __ETHER00_H */ diff --git a/include/asm-arm/arch-epxa10db/excalibur.h b/include/asm-arm/arch-epxa10db/excalibur.h deleted file mode 100644 index 5c91dd6d7822..000000000000 --- a/include/asm-arm/arch-epxa10db/excalibur.h +++ /dev/null @@ -1,91 +0,0 @@ -/* megafunction wizard: %ARM-Based Excalibur% - GENERATION: STANDARD - VERSION: WM1.0 - MODULE: ARM-Based Excalibur - PROJECT: excalibur - ============================================================ - File Name: v:\embedded\linux\bootldr\excalibur.h - Megafunction Name(s): ARM-Based Excalibur - ============================================================ - - ************************************************************ - THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! - ************************************************************/ - -#ifndef EXCALIBUR_H_INCLUDED -#define EXCALIBUR_H_INCLUDED - -#define EXC_DEFINE_PROCESSOR_LITTLE_ENDIAN -#define EXC_DEFINE_BOOT_FROM_FLASH - -#define EXC_INPUT_CLK_FREQUENCY (50000000) -#define EXC_AHB1_CLK_FREQUENCY (150000000) -#define EXC_AHB2_CLK_FREQUENCY (75000000) -#define EXC_SDRAM_CLK_FREQUENCY (75000000) - -/* Registers Block */ -#define EXC_REGISTERS_BASE (0x7fffc000) -#define EXC_MODE_CTRL00_BASE (EXC_REGISTERS_BASE + 0x000) -#define EXC_IO_CTRL00_BASE (EXC_REGISTERS_BASE + 0x040) -#define EXC_MMAP00_BASE (EXC_REGISTERS_BASE + 0x080) -#define EXC_PLD_CONFIG00_BASE (EXC_REGISTERS_BASE + 0x140) -#define EXC_TIMER00_BASE (EXC_REGISTERS_BASE + 0x200) -#define EXC_INT_CTRL00_BASE (EXC_REGISTERS_BASE + 0xc00) -#define EXC_CLOCK_CTRL00_BASE (EXC_REGISTERS_BASE + 0x300) -#define EXC_WATCHDOG00_BASE (EXC_REGISTERS_BASE + 0xa00) -#define EXC_UART00_BASE (EXC_REGISTERS_BASE + 0x280) -#define EXC_EBI00_BASE (EXC_REGISTERS_BASE + 0x380) -#define EXC_SDRAM00_BASE (EXC_REGISTERS_BASE + 0x400) -#define EXC_AHB12_BRIDGE_CTRL00_BASE (EXC_REGISTERS_BASE + 0x800) -#define EXC_PLD_STRIPE_BRIDGE_CTRL00_BASE (EXC_REGISTERS_BASE + 0x100) -#define EXC_STRIPE_PLD_BRIDGE_CTRL00_BASE (EXC_REGISTERS_BASE + 0x100) - -#define EXC_REGISTERS_SIZE (0x00004000) - -/* EBI Block(s) */ -#define EXC_EBI_BLOCK0_BASE (0x40000000) -#define EXC_EBI_BLOCK0_SIZE (0x00400000) -#define EXC_EBI_BLOCK0_WIDTH (8) -#define EXC_EBI_BLOCK0_NON_CACHEABLE -#define EXC_EBI_BLOCK1_BASE (0x40400000) -#define EXC_EBI_BLOCK1_SIZE (0x00400000) -#define EXC_EBI_BLOCK1_WIDTH (16) -#define EXC_EBI_BLOCK1_NON_CACHEABLE -#define EXC_EBI_BLOCK2_BASE (0x40800000) -#define EXC_EBI_BLOCK2_SIZE (0x00400000) -#define EXC_EBI_BLOCK2_WIDTH (16) -#define EXC_EBI_BLOCK2_NON_CACHEABLE -#define EXC_EBI_BLOCK3_BASE (0x40c00000) -#define EXC_EBI_BLOCK3_SIZE (0x00400000) -#define EXC_EBI_BLOCK3_WIDTH (16) -#define EXC_EBI_BLOCK3_NON_CACHEABLE - -/* SDRAM Block(s) */ -#define EXC_SDRAM_BLOCK0_BASE (0x00000000) -#define EXC_SDRAM_BLOCK0_SIZE (0x04000000) -#define EXC_SDRAM_BLOCK0_WIDTH (32) -#define EXC_SDRAM_BLOCK1_BASE (0x04000000) -#define EXC_SDRAM_BLOCK1_SIZE (0x04000000) -#define EXC_SDRAM_BLOCK1_WIDTH (32) - -/* Single Port SRAM Block(s) */ -#define EXC_SPSRAM_BLOCK0_BASE (0x08000000) -#define EXC_SPSRAM_BLOCK0_SIZE (0x00020000) -#define EXC_SPSRAM_BLOCK1_BASE (0x08020000) -#define EXC_SPSRAM_BLOCK1_SIZE (0x00020000) - -/* PLD Block(s) */ -#define EXC_PLD_BLOCK0_BASE (0x80000000) -#define EXC_PLD_BLOCK0_SIZE (0x00004000) -#define EXC_PLD_BLOCK0_NON_CACHEABLE -#define EXC_PLD_BLOCK1_BASE (0xf000000) -#define EXC_PLD_BLOCK1_SIZE (0x00004000) -#define EXC_PLD_BLOCK1_NON_CACHEABLE -#define EXC_PLD_BLOCK2_BASE (0x80008000) -#define EXC_PLD_BLOCK2_SIZE (0x00004000) -#define EXC_PLD_BLOCK2_NON_CACHEABLE -#define EXC_PLD_BLOCK3_BASE (0x8000c000) -#define EXC_PLD_BLOCK3_SIZE (0x00004000) -#define EXC_PLD_BLOCK3_NON_CACHEABLE - -#endif diff --git a/include/asm-arm/arch-epxa10db/hardware.h b/include/asm-arm/arch-epxa10db/hardware.h deleted file mode 100644 index b992c2924a77..000000000000 --- a/include/asm-arm/arch-epxa10db/hardware.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10/hardware.h - * - * This file contains the hardware definitions of the Integrator. - * - * Copyright (C) 1999 ARM Limited. - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARCH_HARDWARE_H -#define __ASM_ARCH_HARDWARE_H - -#include - -/* - * Where in virtual memory the IO devices (timers, system controllers - * and so on) - */ -#define IO_BASE 0xf0000000 // VA of IO -#define IO_SIZE 0x10000000 // How much? -#define IO_START EXC_REGISTERS_BASE // PA of IO -/* macro to get at IO space when running virtually */ -#define IO_ADDRESS(x) ((x) | 0xf0000000) - -#define FLASH_VBASE 0xFE000000 -#define FLASH_SIZE 0x01000000 -#define FLASH_START EXC_EBI_BLOCK0_BASE -#define FLASH_VADDR(x) ((x)|0xFE000000) -/* - * Similar to above, but for PCI addresses (memory, IO, Config and the - * V3 chip itself). WARNING: this has to mirror definitions in platform.h - */ -#if 0 -#define PCI_MEMORY_VADDR 0xe8000000 -#define PCI_CONFIG_VADDR 0xec000000 -#define PCI_V3_VADDR 0xed000000 -#define PCI_IO_VADDR 0xee000000 - -#define PCIO_BASE PCI_IO_VADDR -#define PCIMEM_BASE PCI_MEMORY_VADDR - - -#define pcibios_assign_all_busses() 1 - -#define PCIBIOS_MIN_IO 0x6000 -#define PCIBIOS_MIN_MEM 0x00100000 -#endif - - -#endif - diff --git a/include/asm-arm/arch-epxa10db/int_ctrl00.h b/include/asm-arm/arch-epxa10db/int_ctrl00.h deleted file mode 100644 index 23ec864c40bb..000000000000 --- a/include/asm-arm/arch-epxa10db/int_ctrl00.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * - * This file contains the register definitions for the Excalibur - * Timer TIMER00. - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __INT_CTRL00_H -#define __INT_CTRL00_H - -#define INT_MS(base_addr) (INT_CTRL00_TYPE (base_addr + 0x00 )) -#define INT_MS_FC_MSK (0x10000) -#define INT_MS_FC_OFST (16) -#define INT_MS_M1_MSK (0x8000) -#define INT_MS_M1_OFST (15) -#define INT_MS_M0_MSK (0x4000) -#define INT_MS_M0_OFST (14) -#define INT_MS_AE_MSK (0x2000) -#define INT_MS_AE_OFST (13) -#define INT_MS_PE_MSK (0x1000) -#define INT_MS_PE_OFST (12) -#define INT_MS_EE_MSK (0x0800) -#define INT_MS_EE_OFST (11) -#define INT_MS_PS_MSK (0x0400) -#define INT_MS_PS_OFST (10) -#define INT_MS_T1_MSK (0x0200) -#define INT_MS_T1_OFST (9) -#define INT_MS_T0_MSK (0x0100) -#define INT_MS_T0_OFST (8) -#define INT_MS_UA_MSK (0x0080) -#define INT_MS_UA_OFST (7) -#define INT_MS_IP_MSK (0x0040) -#define INT_MS_IP_OFST (6) -#define INT_MS_P5_MSK (0x0020) -#define INT_MS_P5_OFST (5) -#define INT_MS_P4_MSK (0x0010) -#define INT_MS_P4_OFST (4) -#define INT_MS_P3_MSK (0x0008) -#define INT_MS_P3_OFST (3) -#define INT_MS_P2_MSK (0x0004) -#define INT_MS_P2_OFST (2) -#define INT_MS_P1_MSK (0x0002) -#define INT_MS_P1_OFST (1) -#define INT_MS_P0_MSK (0x0001) -#define INT_MS_P0_OFST (0) - -#define INT_MC(base_addr) (INT_CTRL00_TYPE (base_addr + 0x04 )) -#define INT_MC_FC_MSK (0x10000) -#define INT_MC_FC_OFST (16) -#define INT_MC_M1_MSK (0x8000) -#define INT_MC_M1_OFST (15) -#define INT_MC_M0_MSK (0x4000) -#define INT_MC_M0_OFST (14) -#define INT_MC_AE_MSK (0x2000) -#define INT_MC_AE_OFST (13) -#define INT_MC_PE_MSK (0x1000) -#define INT_MC_PE_OFST (12) -#define INT_MC_EE_MSK (0x0800) -#define INT_MC_EE_OFST (11) -#define INT_MC_PS_MSK (0x0400) -#define INT_MC_PS_OFST (10) -#define INT_MC_T1_MSK (0x0200) -#define INT_MC_T1_OFST (9) -#define INT_MC_T0_MSK (0x0100) -#define INT_MC_T0_OFST (8) -#define INT_MC_UA_MSK (0x0080) -#define INT_MC_UA_OFST (7) -#define INT_MC_IP_MSK (0x0040) -#define INT_MC_IP_OFST (6) -#define INT_MC_P5_MSK (0x0020) -#define INT_MC_P5_OFST (5) -#define INT_MC_P4_MSK (0x0010) -#define INT_MC_P4_OFST (4) -#define INT_MC_P3_MSK (0x0008) -#define INT_MC_P3_OFST (3) -#define INT_MC_P2_MSK (0x0004) -#define INT_MC_P2_OFST (2) -#define INT_MC_P1_MSK (0x0002) -#define INT_MC_P1_OFST (1) -#define INT_MC_P0_MSK (0x0001) -#define INT_MC_P0_OFST (0) - -#define INT_SS(base_addr) (INT_CTRL00_TYPE (base_addr + 0x08 )) -#define INT_SS_FC_SSK (0x8000) -#define INT_SS_FC_OFST (15) -#define INT_SS_M1_SSK (0x8000) -#define INT_SS_M1_OFST (15) -#define INT_SS_M0_SSK (0x4000) -#define INT_SS_M0_OFST (14) -#define INT_SS_AE_SSK (0x2000) -#define INT_SS_AE_OFST (13) -#define INT_SS_PE_SSK (0x1000) -#define INT_SS_PE_OFST (12) -#define INT_SS_EE_SSK (0x0800) -#define INT_SS_EE_OFST (11) -#define INT_SS_PS_SSK (0x0400) -#define INT_SS_PS_OFST (10) -#define INT_SS_T1_SSK (0x0200) -#define INT_SS_T1_OFST (9) -#define INT_SS_T0_SSK (0x0100) -#define INT_SS_T0_OFST (8) -#define INT_SS_UA_SSK (0x0080) -#define INT_SS_UA_OFST (7) -#define INT_SS_IP_SSK (0x0040) -#define INT_SS_IP_OFST (6) -#define INT_SS_P5_SSK (0x0020) -#define INT_SS_P5_OFST (5) -#define INT_SS_P4_SSK (0x0010) -#define INT_SS_P4_OFST (4) -#define INT_SS_P3_SSK (0x0008) -#define INT_SS_P3_OFST (3) -#define INT_SS_P2_SSK (0x0004) -#define INT_SS_P2_OFST (2) -#define INT_SS_P1_SSK (0x0002) -#define INT_SS_P1_OFST (1) -#define INT_SS_P0_SSK (0x0001) -#define INT_SS_P0_OFST (0) - -#define INT_RS(base_addr) (INT_CTRL00_TYPE (base_addr + 0x0C )) -#define INT_RS_FC_RSK (0x10000) -#define INT_RS_FC_OFST (16) -#define INT_RS_M1_RSK (0x8000) -#define INT_RS_M1_OFST (15) -#define INT_RS_M0_RSK (0x4000) -#define INT_RS_M0_OFST (14) -#define INT_RS_AE_RSK (0x2000) -#define INT_RS_AE_OFST (13) -#define INT_RS_PE_RSK (0x1000) -#define INT_RS_PE_OFST (12) -#define INT_RS_EE_RSK (0x0800) -#define INT_RS_EE_OFST (11) -#define INT_RS_PS_RSK (0x0400) -#define INT_RS_PS_OFST (10) -#define INT_RS_T1_RSK (0x0200) -#define INT_RS_T1_OFST (9) -#define INT_RS_T0_RSK (0x0100) -#define INT_RS_T0_OFST (8) -#define INT_RS_UA_RSK (0x0080) -#define INT_RS_UA_OFST (7) -#define INT_RS_IP_RSK (0x0040) -#define INT_RS_IP_OFST (6) -#define INT_RS_P5_RSK (0x0020) -#define INT_RS_P5_OFST (5) -#define INT_RS_P4_RSK (0x0010) -#define INT_RS_P4_OFST (4) -#define INT_RS_P3_RSK (0x0008) -#define INT_RS_P3_OFST (3) -#define INT_RS_P2_RSK (0x0004) -#define INT_RS_P2_OFST (2) -#define INT_RS_P1_RSK (0x0002) -#define INT_RS_P1_OFST (1) -#define INT_RS_P0_RSK (0x0001) -#define INT_RS_P0_OFST (0) - -#define INT_ID(base_addr) (INT_CTRL00_TYPE (base_addr + 0x10 )) -#define INT_ID_ID_MSK (0x3F) -#define INT_ID_ID_OFST (0) - -#define INT_PLD_PRIORITY(base_addr) (INT_CTRL00_TYPE (base_addr + 0x14 )) -#define INT_PLD_PRIORITY_PRI_MSK (0x3F) -#define INT_PLD_PRIORITY_PRI_OFST (0) -#define INT_PLD_PRIORITY_GA_MSK (0x40) -#define INT_PLD_PRIORITY_GA_OFST (6) - -#define INT_MODE(base_addr) (INT_CTRL00_TYPE (base_addr + 0x18 )) -#define INT_MODE_MODE_MSK (0x3) -#define INT_MODE_MODE_OFST (0) - -#define INT_PRIORITY_P0(base_addr) (INT_CTRL00_TYPE (base_addr + 0x80 )) -#define INT_PRIORITY_P0_PRI_MSK (0x3F) -#define INT_PRIORITY_P0_PRI_OFST (0) -#define INT_PRIORITY_P0_FQ_MSK (0x40) -#define INT_PRIORITY_P0_FQ_OFST (6) - -#define INT_PRIORITY_P1(base_addr) (INT_CTRL00_TYPE (base_addr + 0x84 )) -#define INT_PRIORITY_P1_PRI_MSK (0x3F) -#define INT_PRIORITY_P1_PRI_OFST (0) -#define INT_PRIORITY_P1_FQ_MSK (0x40) -#define INT_PRIORITY_P1_FQ_OFST (6) - -#define INT_PRIORITY_P2(base_addr) (INT_CTRL00_TYPE (base_addr + 0x88 )) -#define INT_PRIORITY_P2_PRI_MSK (0x3F) -#define INT_PRIORITY_P2_PRI_OFST (0) -#define INT_PRIORITY_P2_FQ_MSK (0x40) -#define INT_PRIORITY_P2_FQ_OFST (6) - -#define INT_PRIORITY_P3(base_addr) (INT_CTRL00_TYPE (base_addr + 0x8C )) -#define INT_PRIORITY_P3_PRI_MSK (0x3F) -#define INT_PRIORITY_P3_PRI_OFST (0) -#define INT_PRIORITY_P3_FQ_MSK (0x40) -#define INT_PRIORITY_P3_FQ_OFST (6) - -#define INT_PRIORITY_P4(base_addr) (INT_CTRL00_TYPE (base_addr + 0x90 )) -#define INT_PRIORITY_P4_PRI_MSK (0x3F) -#define INT_PRIORITY_P4_PRI_OFST (0) -#define INT_PRIORITY_P4_FQ_MSK (0x40) -#define INT_PRIORITY_P4_FQ_OFST (6) - -#define INT_PRIORITY_P5(base_addr) (INT_CTRL00_TYPE (base_addr + 0x94 )) -#define INT_PRIORITY_P5_PRI_MSK (0x3F) -#define INT_PRIORITY_P5_PRI_OFST (0) -#define INT_PRIORITY_P5_FQ_MSK (0x40) -#define INT_PRIORITY_P5_FQ_OFST (6) - -#define INT_PRIORITY_IP(base_addr) (INT_CTRL00_TYPE (base_addr + 0x94 )) -#define INT_PRIORITY_IP_PRI_MSK (0x3F) -#define INT_PRIORITY_IP_PRI_OFST (0) -#define INT_PRIORITY_IP_FQ_MSK (0x40) -#define INT_PRIORITY_IP_FQ_OFST (6) - -#define INT_PRIORITY_UA(base_addr) (INT_CTRL00_TYPE (base_addr + 0x9C )) -#define INT_PRIORITY_UA_PRI_MSK (0x3F) -#define INT_PRIORITY_UA_PRI_OFST (0) -#define INT_PRIORITY_UA_FQ_MSK (0x40) -#define INT_PRIORITY_UA_FQ_OFST (6) - -#define INT_PRIORITY_T0(base_addr) (INT_CTRL00_TYPE (base_addr + 0xA0 )) -#define INT_PRIORITY_T0_PRI_MSK (0x3F) -#define INT_PRIORITY_T0_PRI_OFST (0) -#define INT_PRIORITY_T0_FQ_MSK (0x40) -#define INT_PRIORITY_T0_FQ_OFST (6) - -#define INT_PRIORITY_T1(base_addr) (INT_CTRL00_TYPE (base_addr + 0xA4 )) -#define INT_PRIORITY_T1_PRI_MSK (0x3F) -#define INT_PRIORITY_T1_PRI_OFST (0) -#define INT_PRIORITY_T1_FQ_MSK (0x40) -#define INT_PRIORITY_T1_FQ_OFST (6) - -#define INT_PRIORITY_PS(base_addr) (INT_CTRL00_TYPE (base_addr + 0xA8 )) -#define INT_PRIORITY_PS_PRI_MSK (0x3F) -#define INT_PRIORITY_PS_PRI_OFST (0) -#define INT_PRIORITY_PS_FQ_MSK (0x40) -#define INT_PRIORITY_PS_FQ_OFST (6) - -#define INT_PRIORITY_EE(base_addr) (INT_CTRL00_TYPE (base_addr + 0xAC )) -#define INT_PRIORITY_EE_PRI_MSK (0x3F) -#define INT_PRIORITY_EE_PRI_OFST (0) -#define INT_PRIORITY_EE_FQ_MSK (0x40) -#define INT_PRIORITY_EE_FQ_OFST (6) - -#define INT_PRIORITY_PE(base_addr) (INT_CTRL00_TYPE (base_addr + 0xB0 )) -#define INT_PRIORITY_PE_PRI_MSK (0x3F) -#define INT_PRIORITY_PE_PRI_OFST (0) -#define INT_PRIORITY_PE_FQ_MSK (0x40) -#define INT_PRIORITY_PE_FQ_OFST (6) - -#define INT_PRIORITY_AE(base_addr) (INT_CTRL00_TYPE (base_addr + 0xB4 )) -#define INT_PRIORITY_AE_PRI_MSK (0x3F) -#define INT_PRIORITY_AE_PRI_OFST (0) -#define INT_PRIORITY_AE_FQ_MSK (0x40) -#define INT_PRIORITY_AE_FQ_OFST (6) - -#define INT_PRIORITY_M0(base_addr) (INT_CTRL00_TYPE (base_addr + 0xB8 )) -#define INT_PRIORITY_M0_PRI_MSK (0x3F) -#define INT_PRIORITY_M0_PRI_OFST (0) -#define INT_PRIORITY_M0_FQ_MSK (0x40) -#define INT_PRIORITY_M0_FQ_OFST (6) - -#define INT_PRIORITY_M1(base_addr) (INT_CTRL00_TYPE (base_addr + 0xBC )) -#define INT_PRIORITY_M1_PRI_MSK (0x3F) -#define INT_PRIORITY_M1_PRI_OFST (0) -#define INT_PRIORITY_M1_FQ_MSK (0x40) -#define INT_PRIORITY_M1_FQ_OFST (6) - -#define INT_PRIORITY_FC(base_addr) (INT_CTRL00_TYPE (base_addr + 0xC0 )) -#define INT_PRIORITY_FC_PRI_MSK (0x3F) -#define INT_PRIORITY_FC_PRI_OFST (0) -#define INT_PRIORITY_FC_FQ_MSK (0x40) -#define INT_PRIORITY_FC_FQ_OFST (6) - -#endif /* __INT_CTRL00_H */ - - diff --git a/include/asm-arm/arch-epxa10db/io.h b/include/asm-arm/arch-epxa10db/io.h deleted file mode 100644 index 9fe100c9d6be..000000000000 --- a/include/asm-arm/arch-epxa10db/io.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/io.h - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARM_ARCH_IO_H -#define __ASM_ARM_ARCH_IO_H - -#include - -#define IO_SPACE_LIMIT 0xffff - - -/* - * Generic virtual read/write - */ -/*#define outsw __arch_writesw -#define outsl __arch_writesl -#define outsb __arch_writesb -#define insb __arch_readsb -#define insw __arch_readsw -#define insl __arch_readsl*/ - -#define __io(a) ((void __iomem *)(a)) -#define __mem_pci(a) (a) - -#endif diff --git a/include/asm-arm/arch-epxa10db/irqs.h b/include/asm-arm/arch-epxa10db/irqs.h deleted file mode 100644 index c3758a3b5d9d..000000000000 --- a/include/asm-arm/arch-epxa10db/irqs.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * linux/include/asm-arm/arch-camelot/irqs.h - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Use the Excalibur chip definitions */ -#define INT_CTRL00_TYPE -#include "asm/arch/int_ctrl00.h" - - -#define IRQ_PLD0 INT_MS_P0_OFST -#define IRQ_PLD1 INT_MS_P1_OFST -#define IRQ_PLD2 INT_MS_P2_OFST -#define IRQ_PLD3 INT_MS_P3_OFST -#define IRQ_PLD4 INT_MS_P4_OFST -#define IRQ_PLD5 INT_MS_P5_OFST -#define IRQ_EXT INT_MS_IP_OFST -#define IRQ_UART INT_MS_UA_OFST -#define IRQ_TIMER0 INT_MS_T0_OFST -#define IRQ_TIMER1 INT_MS_T1_OFST -#define IRQ_PLL INT_MS_PLL_OFST -#define IRQ_EBI INT_MS_EBI_OFST -#define IRQ_STRIPE_BRIDGE INT_MS_PLL_OFST -#define IRQ_AHB_BRIDGE INT_MS_PLL_OFST -#define IRQ_COMMRX INT_MS_CR_OFST -#define IRQ_COMMTX INT_MS_CT_OFST -#define IRQ_FAST_COMM INT_MS_FC_OFST - -#define NR_IRQS (INT_MS_FC_OFST + 1) - diff --git a/include/asm-arm/arch-epxa10db/memory.h b/include/asm-arm/arch-epxa10db/memory.h deleted file mode 100644 index 999541b6a9f5..000000000000 --- a/include/asm-arm/arch-epxa10db/memory.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10/memory.h - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARCH_MEMORY_H -#define __ASM_ARCH_MEMORY_H - -/* - * Physical DRAM offset. - */ -#define PHYS_OFFSET UL(0x00000000) - -/* - * Virtual view <-> DMA view memory address translations - * virt_to_bus: Used to translate the virtual address to an - * address suitable to be passed to set_dma_addr - * bus_to_virt: Used to convert an address for DMA operations - * to an address that the kernel can use. - */ -#define __virt_to_bus(x) (x - PAGE_OFFSET + /*SDRAM_BASE*/0) -#define __bus_to_virt(x) (x - /*SDRAM_BASE*/0 + PAGE_OFFSET) - -#endif diff --git a/include/asm-arm/arch-epxa10db/mode_ctrl00.h b/include/asm-arm/arch-epxa10db/mode_ctrl00.h deleted file mode 100644 index d8a7efa12e19..000000000000 --- a/include/asm-arm/arch-epxa10db/mode_ctrl00.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __MODE_CTRL00_H -#define __MODE_CTRL00_H - -/* - * Register definitions for the reset and mode control - */ - -/* - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - - -#define BOOT_CR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR )) -#define BOOT_CR_BF_MSK (0x1) -#define BOOT_CR_BF_OFST (0) -#define BOOT_CR_HM_MSK (0x2) -#define BOOT_CR_HM_OFST (1) -#define BOOT_CR_RE_MSK (0x4) -#define BOOT_CR_RE_OFST (2) - -#define RESET_SR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x4 )) -#define RESET_SR_WR_MSK (0x1) -#define RESET_SR_WR_OFST (0) -#define RESET_SR_CR_MSK (0x2) -#define RESET_SR_CR_OFST (1) -#define RESET_SR_JT_MSK (0x4) -#define RESET_SR_JT_OFST (2) -#define RESET_SR_ER_MSK (0x8) -#define RESET_SR_ER_OFST (3) - -#define ID_CODE(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x08 )) - -#define SRAM0_SR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x20 )) -#define SRAM0_SR_SIZE_MSK (0xFFFFF000) -#define SRAM0_SR_SIZE_OFST (12) - -#define SRAM1_SR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x24 )) -#define SRAM1_SR_SIZE_MSK (0xFFFFF000) -#define SRAM1_SR_SIZE_OFST (12) - -#define DPSRAM0_SR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x30 )) - -#define DPSRAM0_SR_MODE_MSK (0xF) -#define DPSRAM0_SR_MODE_OFST (0) -#define DPSRAM0_SR_GLBL_MSK (0x30) -#define DPSRAM0_SR_SIZE_MSK (0xFFFFF000) -#define DPSRAM0_SR_SIZE_OFST (12) - -#define DPSRAM0_LCR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x34 )) -#define DPSRAM0_LCR_LCKADDR_MSK (0x1FFE0) -#define DPSRAM0_LCR_LCKADDR_OFST (4) - -#define DPSRAM1_SR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x38 )) -#define DPSRAM1_SR_MODE_MSK (0xF) -#define DPSRAM1_SR_MODE_OFST (0) -#define DPSRAM1_SR_GLBL_MSK (0x30) -#define DPSRAM1_SR_GLBL_OFST (4) -#define DPSRAM1_SR_SIZE_MSK (0xFFFFF000) -#define DPSRAM1_SR_SIZE_OFST (12) - -#define DPSRAM1_LCR(BASE_ADDR) (MODE_CTRL00_TYPE (BASE_ADDR + 0x3C )) -#define DPSRAM1_LCR_LCKADDR_MSK (0x1FFE0) -#define DPSRAM1_LCR_LCKADDR_OFST (4) - -#endif /* __MODE_CTRL00_H */ diff --git a/include/asm-arm/arch-epxa10db/param.h b/include/asm-arm/arch-epxa10db/param.h deleted file mode 100644 index 783dedd71c8f..000000000000 --- a/include/asm-arm/arch-epxa10db/param.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/param.h - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ diff --git a/include/asm-arm/arch-epxa10db/platform.h b/include/asm-arm/arch-epxa10db/platform.h deleted file mode 100644 index 129bb0f212a0..000000000000 --- a/include/asm-arm/arch-epxa10db/platform.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef PLATFORM_H -#define PLATFORM_H -#include "excalibur.h" - -#define MAXIRQNUM 15 -#endif - diff --git a/include/asm-arm/arch-epxa10db/pld_conf00.h b/include/asm-arm/arch-epxa10db/pld_conf00.h deleted file mode 100644 index 7af2c38dacc6..000000000000 --- a/include/asm-arm/arch-epxa10db/pld_conf00.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __PLD_CONF00_H -#define __PLD_CONF00_H - -/* - * Register definitions for the PLD Configuration Logic - */ - -/* - * - * This file contains the register definitions for the Excalibur - * Interrupt controller INT_CTRL00. - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define CONFIG_CONTROL(BASE_ADDR) (PLD_CONF00_TYPE (BASE_ADDR)) -#define CONFIG_CONTROL_LK_MSK (0x1) -#define CONFIG_CONTROL_LK_OFST (0) -#define CONFIG_CONTROL_CO_MSK (0x2) -#define CONFIG_CONTROL_CO_OFST (1) -#define CONFIG_CONTROL_B_MSK (0x4) -#define CONFIG_CONTROL_B_OFST (2) -#define CONFIG_CONTROL_PC_MSK (0x8) -#define CONFIG_CONTROL_PC_OFST (3) -#define CONFIG_CONTROL_E_MSK (0x10) -#define CONFIG_CONTROL_E_OFST (4) -#define CONFIG_CONTROL_ES_MSK (0xE0) -#define CONFIG_CONTROL_ES_OFST (5) -#define CONFIG_CONTROL_ES_0_MSK (0x20) -#define CONFIG_CONTROL_ES_1_MSK (0x40) -#define CONFIG_CONTROL_ES_2_MSK (0x80) - -#define CONFIG_CONTROL_CLOCK(BASE_ADDR) (PLD_CONF00_TYPE (BASE_ADDR + 0x4 )) -#define CONFIG_CONTROL_CLOCK_RATIO_MSK (0xFFFF) -#define CONFIG_CONTROL_CLOCK_RATIO_OFST (0) - -#define CONFIG_CONTROL_DATA(BASE_ADDR) (PLD_CONF00_TYPE (BASE_ADDR + 0x8 )) -#define CONFIG_CONTROL_DATA_MSK (0xFFFFFFFF) -#define CONFIG_CONTROL_DATA_OFST (0) - -#define CONFIG_UNLOCK(BASE_ADDR) (PLD_CONF00_TYPE (BASE_ADDR + 0xC )) -#define CONFIG_UNLOCK_MSK (0xFFFFFFFF) -#define CONFIG_UNLOCK_OFST (0) - -#define CONFIG_UNLOCK_MAGIC (0x554E4C4B) - -#endif /* __PLD_CONF00_H */ - - - - - - - - - - - - diff --git a/include/asm-arm/arch-epxa10db/system.h b/include/asm-arm/arch-epxa10db/system.h deleted file mode 100644 index 345b092a1ed5..000000000000 --- a/include/asm-arm/arch-epxa10db/system.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/system.h - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_ARCH_SYSTEM_H -#define __ASM_ARCH_SYSTEM_H - -#include - -static inline void arch_idle(void) -{ - /* - * This should do all the clock switching - * and wait for interrupt tricks - */ - cpu_do_idle(); -} - -extern __inline__ void arch_reset(char mode) -{ - /* Hmm... We can probably do something with the watchdog... */ -} - -#endif diff --git a/include/asm-arm/arch-epxa10db/tdkphy.h b/include/asm-arm/arch-epxa10db/tdkphy.h deleted file mode 100644 index 5e107bd4e109..000000000000 --- a/include/asm-arm/arch-epxa10db/tdkphy.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * linux/drivers/tdkphy.h - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __TDKPHY_H -#define __TDKPHY_H - -/* - * Register definitions for the TDK 78Q2120 PHY - * which is on the Camelot board - */ - -/* - * Copyright (c) Altera Corporation 2000. - * All rights reserved. - */ -#define PHY_CONTROL (0) -#define PHY_CONTROL_COLT_MSK (0x80) -#define PHY_CONTROL_COLT_OFST (7) -#define PHY_CONTROL_DUPLEX_MSK (0x100) -#define PHY_CONTROL_DUPLEX_OFST (8) -#define PHY_CONTROL_RANEG_MSK (0x200) -#define PHY_CONTROL_RANEG_OFST (9) -#define PHY_CONTROL_ISO_MSK (0x400) -#define PHY_CONTROL_ISO_OFST (10) -#define PHY_CONTROL_PWRDN_MSK (0x800) -#define PHY_CONTROL_PWRDN_OFST (11) -#define PHY_CONTROL_ANEGEN_MSK (0x1000) -#define PHY_CONTROL_ANEGEN_OFST (12) -#define PHY_CONTROL_SPEEDSL_MSK (0x2000) -#define PHY_CONTROL_SPEEDSL_OFST (13) -#define PHY_CONTROL_LOOPBK_MSK (0x4000) -#define PHY_CONTROL_LOOPBK_OFST (14) -#define PHY_CONTROL_RESET_MSK (0x8000) -#define PHY_CONTROL_RESET_OFST (15) - -#define PHY_STATUS (1) -#define PHY_STATUS_ETXD_MSK (0x1) -#define PHY_STATUS_EXTD_OFST (0) -#define PHY_STATUS_JAB_MSK (0x2) -#define PHY_STATUS_JAB_OFST (1) -#define PHY_STATUS_LINK_MSK (0x4) -#define PHY_STATUS_LINK_OFST (2) -#define PHY_STATUS_ANEGA_MSK (0x8) -#define PHY_STATUS_ANEGA_OFST (3) -#define PHY_STATUS_RFAULT_MSK (0x10) -#define PHY_STATUS_RFAULT_OFST (4) -#define PHY_STATUS_ANEGC_MSK (0x20) -#define PHY_STATUS_ANEGC_OFST (5) -#define PHY_STATUS_10T_H_MSK (0x800) -#define PHY_STATUS_10T_H_OFST (11) -#define PHY_STATUS_10T_F_MSK (0x1000) -#define PHY_STATUS_10T_F_OFST (12) -#define PHY_STATUS_100_X_H_MSK (0x2000) -#define PHY_STATUS_100_X_H_OFST (13) -#define PHY_STATUS_100_X_F_MSK (0x4000) -#define PHY_STATUS_100_X_F_OFST (14) -#define PHY_STATUS_100T4_MSK (0x8000) -#define PHY_STATUS_100T4_OFST (15) - -#define PHY_ID1 (2) -#define PHY_ID1_OUI_MSK (0xFFFF) -#define PHY_ID1_OUI_OFST (0) - -#define PHY_ID2 (3) -#define PHY_ID2_RN_MSK (0xF) -#define PHY_ID2_RN_OFST (0) -#define PHY_ID2_MN_MSK (0x3F0) -#define PHY_ID2_MN_OFST (4) -#define PHY_ID2_OUI_MSK (0xFC00) -#define PHY_ID2_OUI_OFST (10) - -#define PHY_AUTO_NEG_ADVERTISEMENT (4) -#define PHY_AUTO_NEG_ADVERTISEMENT_SELECTOR_MSK (0x1F) -#define PHY_AUTO_NEG_ADVERTISEMENT_SELECTOR_OFST (0) -#define PHY_AUTO_NEG_ADVERTISEMENT_A0_MSK (0x20) -#define PHY_AUTO_NEG_ADVERTISEMENT_A0_OFST (5) -#define PHY_AUTO_NEG_ADVERTISEMENT_A1_MSK (0x40) -#define PHY_AUTO_NEG_ADVERTISEMENT_A1_OFST (6) -#define PHY_AUTO_NEG_ADVERTISEMENT_A2_MSK (0x80) -#define PHY_AUTO_NEG_ADVERTISEMENT_A2_OFST (7) -#define PHY_AUTO_NEG_ADVERTISEMENT_A3_MSK (0x100) -#define PHY_AUTO_NEG_ADVERTISEMENT_A3_OFST (8) -#define PHY_AUTO_NEG_ADVERTISEMENT_A4_MSK (0x200) -#define PHY_AUTO_NEG_ADVERTISEMENT_A4_OFST (9) -#define PHY_AUTO_NEG_ADVERTISEMENT_TAF_MSK (0x1FE0) -#define PHY_AUTO_NEG_ADVERTISEMENT_TAF_OFST (5) -#define PHY_AUTO_NEG_ADVERTISEMENT_RF_MSK (0x2000) -#define PHY_AUTO_NEG_ADVERTISEMENT_RF_OFST (13) -#define PHY_AUTO_NEG_ADVERTISEMENT_RSVD_MSK (0x4000) -#define PHY_AUTO_NEG_ADVERTISEMENT_RVSD_OFST (14) -#define PHY_AUTO_NEG_ADVERTISEMENT_NP_MSK (0x8000) -#define PHY_AUTO_NEG_ADVERTISEMENT_NP_OFST (15) - -#define PHY_AUTO_NEG_LINK_PARTNER (5) -#define PHY_AUTO_NEG_LINK_PARTNER_S4_MSK (0x1F) -#define PHY_AUTO_NEG_LINK_PARTNER_S4_OFST (0) -#define PHY_AUTO_NEG_LINK_PARTNER_A7_MSK (0x1FE0) -#define PHY_AUTO_NEG_LINK_PARTNER_A7_OFST (5) -#define PHY_AUTO_NEG_LINK_PARTNER_RF_MSK (0x2000) -#define PHY_AUTO_NEG_LINK_PARTNER_RF_OFST (13) -#define PHY_AUTO_NEG_LINK_PARTNER_ACK_MSK (0x4000) -#define PHY_AUTO_NEG_LINK_PARTNER_ACK_OFST (14) -#define PHY_AUTO_NEG_LINK_PARTNER_NP_MSK (0x8000) -#define PHY_AUTO_NEG_LINK_PARTNER_NP_OFST (15) - -#define PHY_AUTO_NEG_EXPANSION (6) -#define PHY_AUTO_NEG_EXPANSION_LPANEGA_MSK (0x1) -#define PHY_AUTO_NEG_EXPANSION_LPANEGA_OFST (0) -#define PHY_AUTO_NEG_EXPANSION_PRX_MSK (0x2) -#define PHY_AUTO_NEG_EXPANSION_PRX_OFST (1) -#define PHY_AUTO_NEG_EXPANSION_NPA_MSK (0x4) -#define PHY_AUTO_NEG_EXPANSION_NPA_OFST (2) -#define PHY_AUTO_NEG_EXPANSION_LPNPA_MSK (0x8) -#define PHY_AUTO_NEG_EXPANSION_LPNPA_OFST (3) -#define PHY_AUTO_NEG_EXPANSION_PDF_MSK (0x10) -#define PHY_AUTO_NEG_EXPANSION_PDF_OFST (4) - -#define PHY_VENDOR_SPECIFIC (16) -#define PHY_VENDOR_SPECIFIC_RXCC_MSK (0x1) -#define PHY_VENDOR_SPECIFIC_RXCC_OFST (0) -#define PHY_VENDOR_SPECIFIC_PCSBP_MSK (0x2) -#define PHY_VENDOR_SPECIFIC_PCSBP_OFST (1) -#define PHY_VENDOR_SPECIFIC_RVSPOL_MSK (0x10) -#define PHY_VENDOR_SPECIFIC_RVSPOL_OFST (4) -#define PHY_VENDOR_SPECIFIC_APOL_MSK (0x20) -#define PHY_VENDOR_SPECIFIC_APOL_OFST (5) -#define PHY_VENDOR_SPECIFIC_GPIO0_DIR_MSK (0x40) -#define PHY_VENDOR_SPECIFIC_GPIO0_DIR_OFST (6) -#define PHY_VENDOR_SPECIFIC_GPIO0_DAT_MSK (0x80) -#define PHY_VENDOR_SPECIFIC_GPIO0_DAT_OFST (7) -#define PHY_VENDOR_SPECIFIC_GPIO1_DIR_MSK (0x100) -#define PHY_VENDOR_SPECIFIC_GPIO1_DIR_OFST (8) -#define PHY_VENDOR_SPECIFIC_GPIO1_DAT_MSK (0x200) -#define PHY_VENDOR_SPECIFIC_GPIO1_DAT_OFST (9) -#define PHY_VENDOR_SPECIFIC_10BT_NATURAL_LOOPBACK_DAT_MSK (0x400) -#define PHY_VENDOR_SPECIFIC_10BT_NATURAL_LOOPBACK_DAT_OFST (10) -#define PHY_VENDOR_SPECIFIC_10BT_SQE_TEST_INHIBIT_MSK (0x800) -#define PHY_VENDOR_SPECIFIC_10BT_SQE_TEST_INHIBIT_OFST (11) -#define PHY_VENDOR_SPECIFIC_TXHIM_MSK (0x1000) -#define PHY_VENDOR_SPECIFIC_TXHIM_OFST (12) -#define PHY_VENDOR_SPECIFIC_INT_LEVEL_MSK (0x4000) -#define PHY_VENDOR_SPECIFIC_INT_LEVEL_OFST (14) -#define PHY_VENDOR_SPECIFIC_RPTR_MSK (0x8000) -#define PHY_VENDOR_SPECIFIC_RPTR_OFST (15) - -#define PHY_IRQ_CONTROL (17) -#define PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK (0x1) -#define PHY_IRQ_CONTROL_ANEG_COMP_INT_OFST (0) -#define PHY_IRQ_CONTROL_RFAULT_INT_MSK (0x2) -#define PHY_IRQ_CONTROL_RFAULT_INT_OFST (1) -#define PHY_IRQ_CONTROL_LS_CHG_INT_MSK (0x4) -#define PHY_IRQ_CONTROL_LS_CHG_INT_OFST (2) -#define PHY_IRQ_CONTROL_LP_ACK_INT_MSK (0x8) -#define PHY_IRQ_CONTROL_LP_ACK_INT_OFST (3) -#define PHY_IRQ_CONTROL_PDF_INT_MSK (0x10) -#define PHY_IRQ_CONTROL_PDF_INT_OFST (4) -#define PHY_IRQ_CONTROL_PRX_INT_MSK (0x20) -#define PHY_IRQ_CONTROL_PRX_INT_OFST (5) -#define PHY_IRQ_CONTROL_RXER_INT_MSK (0x40) -#define PHY_IRQ_CONTROL_RXER_INT_OFST (6) -#define PHY_IRQ_CONTROL_JABBER_INT_MSK (0x80) -#define PHY_IRQ_CONTROL_JABBER_INT_OFST (7) -#define PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK (0x100) -#define PHY_IRQ_CONTROL_ANEG_COMP_IE_OFST (8) -#define PHY_IRQ_CONTROL_RFAULT_IE_MSK (0x200) -#define PHY_IRQ_CONTROL_RFAULT_IE_OFST (9) -#define PHY_IRQ_CONTROL_LS_CHG_IE_MSK (0x400) -#define PHY_IRQ_CONTROL_LS_CHG_IE_OFST (10) -#define PHY_IRQ_CONTROL_LP_ACK_IE_MSK (0x800) -#define PHY_IRQ_CONTROL_LP_ACK_IE_OFST (11) -#define PHY_IRQ_CONTROL_PDF_IE_MSK (0x1000) -#define PHY_IRQ_CONTROL_PDF_IE_OFST (12) -#define PHY_IRQ_CONTROL_PRX_IE_MSK (0x2000) -#define PHY_IRQ_CONTROL_PRX_IE_OFST (13) -#define PHY_IRQ_CONTROL_RXER_IE_MSK (0x4000) -#define PHY_IRQ_CONTROL_RXER_IE_OFST (14) -#define PHY_IRQ_CONTROL_JABBER_IE_MSK (0x8000) -#define PHY_IRQ_CONTROL_JABBER_IE_OFST (15) - -#define PHY_DIAGNOSTIC (18) -#define PHY_DIAGNOSTIC_RX_LOCK_MSK (0x100) -#define PHY_DIAGNOSTIC_RX_LOCK_OFST (8) -#define PHY_DIAGNOSTIC_RX_PASS_MSK (0x200) -#define PHY_DIAGNOSTIC_RX_PASS_OFST (9) -#define PHY_DIAGNOSTIC_RATE_MSK (0x400) -#define PHY_DIAGNOSTIC_RATE_OFST (10) -#define PHY_DIAGNOSTIC_DPLX_MSK (0x800) -#define PHY_DIAGNOSTIC_DPLX_OFST (11) -#define PHY_DIAGNOSTIC_ANEGF_MSK (0x1000) -#define PHY_DIAGNOSTIC_ANEGF_OFST (12) - -#endif /* __TDKPHY_H */ diff --git a/include/asm-arm/arch-epxa10db/timer00.h b/include/asm-arm/arch-epxa10db/timer00.h deleted file mode 100644 index 52a3fb58b59d..000000000000 --- a/include/asm-arm/arch-epxa10db/timer00.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * This file contains the register definitions for the Excalibur - * Timer TIMER00. - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __TIMER00_H -#define __TIMER00_H - -/* - * Register definitions for the timers - */ - - -#define TIMER0_CR(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x00 )) -#define TIMER0_CR_B_MSK (0x20) -#define TIMER0_CR_B_OFST (0x5) -#define TIMER0_CR_S_MSK (0x10) -#define TIMER0_CR_S_OFST (0x4) -#define TIMER0_CR_CI_MSK (0x08) -#define TIMER0_CR_CI_OFST (0x3) -#define TIMER0_CR_IE_MSK (0x04) -#define TIMER0_CR_IE_OFST (0x2) -#define TIMER0_CR_MODE_MSK (0x3) -#define TIMER0_CR_MODE_OFST (0) -#define TIMER0_CR_MODE_FREE (0) -#define TIMER0_CR_MODE_ONE (1) -#define TIMER0_CR_MODE_INTVL (2) - -#define TIMER0_SR(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x00 )) -#define TIMER0_SR_B_MSK (0x20) -#define TIMER0_SR_B_OFST (0x5) -#define TIMER0_SR_S_MSK (0x10) -#define TIMER0_SR_S_OFST (0x4) -#define TIMER0_SR_CI_MSK (0x08) -#define TIMER0_SR_CI_OFST (0x3) -#define TIMER0_SR_IE_MSK (0x04) -#define TIMER0_SR_IE_OFST (0x2) -#define TIMER0_SR_MODE_MSK (0x3) -#define TIMER0_SR_MODE_OFST (0) -#define TIMER0_SR_MODE_FREE (0) -#define TIMER0_SR_MODE_ONE (1) -#define TIMER0_SR_MODE_INTVL (2) - -#define TIMER0_PRESCALE(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x010 )) -#define TIMER0_LIMIT(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x020 )) -#define TIMER0_READ(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x030 )) - -#define TIMER1_CR(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x40 )) -#define TIMER1_CR_B_MSK (0x20) -#define TIMER1_CR_B_OFST (0x5) -#define TIMER1_CR_S_MSK (0x10) -#define TIMER1_CR_S_OFST (0x4) -#define TIMER1_CR_CI_MSK (0x08) -#define TIMER1_CR_CI_OFST (0x3) -#define TIMER1_CR_IE_MSK (0x04) -#define TIMER1_CR_IE_OFST (0x2) -#define TIMER1_CR_MODE_MSK (0x3) -#define TIMER1_CR_MODE_OFST (0) -#define TIMER1_CR_MODE_FREE (0) -#define TIMER1_CR_MODE_ONE (1) -#define TIMER1_CR_MODE_INTVL (2) - -#define TIMER1_SR(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x40 )) -#define TIMER1_SR_B_MSK (0x20) -#define TIMER1_SR_B_OFST (0x5) -#define TIMER1_SR_S_MSK (0x10) -#define TIMER1_SR_S_OFST (0x4) -#define TIMER1_SR_CI_MSK (0x08) -#define TIMER1_SR_CI_OFST (0x3) -#define TIMER1_SR_IE_MSK (0x04) -#define TIMER1_SR_IE_OFST (0x2) -#define TIMER1_SR_MODE_MSK (0x3) -#define TIMER1_SR_MODE_OFST (0) -#define TIMER1_SR_MODE_FREE (0) -#define TIMER1_SR_MODE_ONE (1) -#define TIMER1_SR_MODE_INTVL (2) - -#define TIMER1_PRESCALE(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x050 )) -#define TIMER1_LIMIT(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x060 )) -#define TIMER1_READ(BASE_ADDR) (TIMER00_TYPE (BASE_ADDR + 0x070 )) - -#endif /* __TIMER00_H */ diff --git a/include/asm-arm/arch-epxa10db/timex.h b/include/asm-arm/arch-epxa10db/timex.h deleted file mode 100644 index b87a75fc9589..000000000000 --- a/include/asm-arm/arch-epxa10db/timex.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/timex.h - * - * Excalibur timex specifications - * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * ?? - */ -#define CLOCK_TICK_RATE (50000000 / 16) diff --git a/include/asm-arm/arch-epxa10db/uart00.h b/include/asm-arm/arch-epxa10db/uart00.h deleted file mode 100644 index 5abd8914d68b..000000000000 --- a/include/asm-arm/arch-epxa10db/uart00.h +++ /dev/null @@ -1,181 +0,0 @@ -/* * - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __UART00_H -#define __UART00_H - -/* - * Register definitions for the UART - */ - -#define UART_TX_FIFO_SIZE (15) - -#define UART_RSR(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x00 )) -#define UART_RSR_RX_LEVEL_MSK (0x1f) -#define UART_RSR_RX_LEVEL_OFST (0) -#define UART_RSR_RE_MSK (0x80) -#define UART_RSR_RE_OFST (7) - -#define UART_RDS(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x04 )) -#define UART_RDS_BI_MSK (0x8) -#define UART_RDS_BI_OFST (4) -#define UART_RDS_FE_MSK (0x4) -#define UART_RDS_FE_OFST (2) -#define UART_RDS_PE_MSK (0x2) -#define UART_RDS_PE_OFST (1) -#define UART_RDS_OE_MSK (0x1) -#define UART_RDS_OE_OFST (0) - -#define UART_RD(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x08 )) -#define UART_RD_RX_DATA_MSK (0xff) -#define UART_RD_RX_DATA_OFST (0) - -#define UART_TSR(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x0c )) -#define UART_TSR_TX_LEVEL_MSK (0x1f) -#define UART_TSR_TX_LEVEL_OFST (0) -#define UART_TSR_TXI_MSK (0x80) -#define UART_TSR_TXI_OFST (7) - -#define UART_TD(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x10 )) -#define UART_TD_TX_DATA_MSK (0xff) -#define UART_TD_TX_DATA_OFST (0) - -#define UART_FCR(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x14 )) -#define UART_FCR_RX_THR_MSK (0xd0) -#define UART_FCR_RX_THR_OFST (5) -#define UART_FCR_RX_THR_1 (0x00) -#define UART_FCR_RX_THR_2 (0x20) -#define UART_FCR_RX_THR_4 (0x40) -#define UART_FCR_RX_THR_6 (0x60) -#define UART_FCR_RX_THR_8 (0x80) -#define UART_FCR_RX_THR_10 (0xa0) -#define UART_FCR_RX_THR_12 (0xc0) -#define UART_FCR_RX_THR_14 (0xd0) -#define UART_FCR_TX_THR_MSK (0x1c) -#define UART_FCR_TX_THR_OFST (2) -#define UART_FCR_TX_THR_0 (0x00) -#define UART_FCR_TX_THR_2 (0x04) -#define UART_FCR_TX_THR_4 (0x08) -#define UART_FCR_TX_THR_8 (0x0c) -#define UART_FCR_TX_THR_10 (0x10) -#define UART_FCR_TX_THR_12 (0x14) -#define UART_FCR_TX_THR_14 (0x18) -#define UART_FCR_TX_THR_15 (0x1c) -#define UART_FCR_RC_MSK (0x02) -#define UART_FCR_RC_OFST (1) -#define UART_FCR_TC_MSK (0x01) -#define UART_FCR_TC_OFST (0) - -#define UART_IES(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x18 )) -#define UART_IES_ME_MSK (0x8) -#define UART_IES_ME_OFST (3) -#define UART_IES_TIE_MSK (0x4) -#define UART_IES_TIE_OFST (2) -#define UART_IES_TE_MSK (0x2) -#define UART_IES_TE_OFST (1) -#define UART_IES_RE_MSK (0x1) -#define UART_IES_RE_OFST (0) - -#define UART_IEC(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x1c )) -#define UART_IEC_ME_MSK (0x8) -#define UART_IEC_ME_OFST (3) -#define UART_IEC_TIE_MSK (0x4) -#define UART_IEC_TIE_OFST (2) -#define UART_IEC_TE_MSK (0x2) -#define UART_IEC_TE_OFST (1) -#define UART_IEC_RE_MSK (0x1) -#define UART_IEC_RE_OFST (0) - -#define UART_ISR(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x20 )) -#define UART_ISR_MI_MSK (0x8) -#define UART_ISR_MI_OFST (3) -#define UART_ISR_TII_MSK (0x4) -#define UART_ISR_TII_OFST (2) -#define UART_ISR_TI_MSK (0x2) -#define UART_ISR_TI_OFST (1) -#define UART_ISR_RI_MSK (0x1) -#define UART_ISR_RI_OFST (0) - -#define UART_IID(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x24 )) -#define UART_IID_IID_MSK (0x7) -#define UART_IID_IID_OFST (0) - -#define UART_MC(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x28 )) -#define UART_MC_OE_MSK (0x40) -#define UART_MC_OE_OFST (6) -#define UART_MC_SP_MSK (0x20) -#define UART_MC_SP_OFST (5) -#define UART_MC_EP_MSK (0x10) -#define UART_MC_EP_OFST (4) -#define UART_MC_PE_MSK (0x08) -#define UART_MC_PE_OFST (3) -#define UART_MC_ST_MSK (0x04) -#define UART_MC_ST_ONE (0x0) -#define UART_MC_ST_TWO (0x04) -#define UART_MC_ST_OFST (2) -#define UART_MC_CLS_MSK (0x03) -#define UART_MC_CLS_OFST (0) -#define UART_MC_CLS_CHARLEN_5 (0) -#define UART_MC_CLS_CHARLEN_6 (1) -#define UART_MC_CLS_CHARLEN_7 (2) -#define UART_MC_CLS_CHARLEN_8 (3) - -#define UART_MCR(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x2c )) -#define UART_MCR_AC_MSK (0x80) -#define UART_MCR_AC_OFST (7) -#define UART_MCR_AR_MSK (0x40) -#define UART_MCR_AR_OFST (6) -#define UART_MCR_BR_MSK (0x20) -#define UART_MCR_BR_OFST (5) -#define UART_MCR_LB_MSK (0x10) -#define UART_MCR_LB_OFST (4) -#define UART_MCR_DCD_MSK (0x08) -#define UART_MCR_DCD_OFST (3) -#define UART_MCR_RI_MSK (0x04) -#define UART_MCR_RI_OFST (2) -#define UART_MCR_DTR_MSK (0x02) -#define UART_MCR_DTR_OFST (1) -#define UART_MCR_RTS_MSK (0x01) -#define UART_MCR_RTS_OFST (0) - -#define UART_MSR(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x30 )) -#define UART_MSR_DCD_MSK (0x80) -#define UART_MSR_DCD_OFST (7) -#define UART_MSR_RI_MSK (0x40) -#define UART_MSR_RI_OFST (6) -#define UART_MSR_DSR_MSK (0x20) -#define UART_MSR_DSR_OFST (5) -#define UART_MSR_CTS_MSK (0x10) -#define UART_MSR_CTS_OFST (4) -#define UART_MSR_DDCD_MSK (0x08) -#define UART_MSR_DDCD_OFST (3) -#define UART_MSR_TERI_MSK (0x04) -#define UART_MSR_TERI_OFST (2) -#define UART_MSR_DDSR_MSK (0x02) -#define UART_MSR_DDSR_OFST (1) -#define UART_MSR_DCTS_MSK (0x01) -#define UART_MSR_DCTS_OFST (0) - -#define UART_DIV_LO(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x34 )) -#define UART_DIV_LO_DIV_MSK (0xff) -#define UART_DIV_LO_DIV_OFST (0) - -#define UART_DIV_HI(BASE_ADDR) (UART00_TYPE (BASE_ADDR + 0x38 )) -#define UART_DIV_HI_DIV_MSK (0xff) -#define UART_DIV_HI_DIV_OFST (0) - -#endif /* __UART00_H */ diff --git a/include/asm-arm/arch-epxa10db/uncompress.h b/include/asm-arm/arch-epxa10db/uncompress.h deleted file mode 100644 index fdfe0e6848f8..000000000000 --- a/include/asm-arm/arch-epxa10db/uncompress.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/uncompress.h - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2001 Altera Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "asm/arch/platform.h" -#include "asm/hardware.h" -#define UART00_TYPE (volatile unsigned int*) -#include "asm/arch/uart00.h" - -/* - * This does not append a newline - */ -static void putstr(const char *s) -{ - while (*s) { - while ((*UART_TSR(EXC_UART00_BASE) & - UART_TSR_TX_LEVEL_MSK)==15) - barrier(); - - *UART_TD(EXC_UART00_BASE) = *s; - - if (*s == '\n') { - while ((*UART_TSR(EXC_UART00_BASE) & - UART_TSR_TX_LEVEL_MSK)==15) - barrier(); - - *UART_TD(EXC_UART00_BASE) = '\r'; - } - s++; - } -} - -/* - * nothing to do - */ -#define arch_decomp_setup() - -#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-epxa10db/vmalloc.h b/include/asm-arm/arch-epxa10db/vmalloc.h deleted file mode 100644 index 546fb7d2b6ad..000000000000 --- a/include/asm-arm/arch-epxa10db/vmalloc.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * linux/include/asm-arm/arch-epxa10db/vmalloc.h - * - * Copyright (C) 2000 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#define VMALLOC_END (PAGE_OFFSET + 0x10000000) -- cgit v1.2.3 From afcc2472d80569059b5fe71fcb67e618b9d83fa8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 13 Nov 2005 02:26:09 +0100 Subject: [PATCH] PPC_PREP: remove unneeded exports This patch removes the EXPORT_SYMBOL'ed but completely unused variable ucSystemType and removes the unneeded EXPORT_SYMBOL(_prep_type). Signed-off-by: Adrian Bunk Acked-by: Tom Rini Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ppc_ksyms.c | 5 ----- arch/ppc/kernel/ppc_ksyms.c | 4 ---- arch/ppc/platforms/prep_setup.c | 1 - include/asm-powerpc/processor.h | 1 - 4 files changed, 11 deletions(-) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 94db25708456..b2758148a0de 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -76,11 +76,6 @@ EXPORT_SYMBOL(single_step_exception); EXPORT_SYMBOL(sys_sigreturn); #endif -#if defined(CONFIG_PPC_PREP) -EXPORT_SYMBOL(_prep_type); -EXPORT_SYMBOL(ucSystemType); -#endif - EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index bb6a5c6a64be..28f1082e5040 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -82,10 +82,6 @@ EXPORT_SYMBOL(ppc_n_lost_interrupts); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); -#if defined(CONFIG_PPC_PREP) -EXPORT_SYMBOL(_prep_type); -EXPORT_SYMBOL(ucSystemType); -#endif #if !defined(__INLINE_BITOPS) EXPORT_SYMBOL(set_bit); diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 4415748071dc..a6a188910a1a 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -72,7 +72,6 @@ TODC_ALLOC(); -unsigned char ucSystemType; unsigned char ucBoardRev; unsigned char ucBoardRevMaj, ucBoardRevMin; diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index d12382d292d4..f3db98454c4d 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -68,7 +68,6 @@ extern int _chrp_type; * vendor. Board revision is also made available. This will be moved * elsewhere soon */ -extern unsigned char ucSystemType; extern unsigned char ucBoardRev; extern unsigned char ucBoardRevMaj, ucBoardRevMin; -- cgit v1.2.3 From 3d1229d6ae92ed1994f4411b8493327ef8f4b76f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 14 Nov 2005 23:35:00 +1100 Subject: [PATCH] powerpc: Merge kexec This patch merges, to some extent, the PPC32 and PPC64 kexec implementations. We adopt the PPC32 approach of having ppc_md callbacks for the kexec functions. The current PPC64 implementation becomes the "default" implementation for PPC64 which platforms can select if they need no special treatment. I've added these default callbacks to pseries/maple/cell/powermac, this means iSeries no longer supports kexec - but it never worked anyway. I've renamed PPC32's machine_kexec_simple to default_machine_kexec, inline with PPC64. Judging by the comments it might be better named machine_kexec_non_of, or something, but at the moment it's the only implementation for PPC32 so it's the "default". Kexec requires machine_shutdown(), which is in machine_kexec.c on PPC32, but we already have in setup-common.c on powerpc. All this does is call ppc_md.nvram_sync, which only powermac implements, so instead make machine_shutdown a ppc_md member and have it call core99_nvram_sync directly on powermac. I've also stuck relocate_kernel.S into misc_32.S for powerpc. Built for ARCH=ppc, and 32 & 64 bit ARCH=powerpc, with KEXEC=y/n. Booted on P5 LPAR and successfully kexec'ed. Should apply on top of 493f25ef4087395891c99fcfe2c72e62e293e89f. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 5 +- arch/powerpc/kernel/machine_kexec.c | 67 +++++++++++++++++++ arch/powerpc/kernel/machine_kexec_32.c | 65 ++++++++++++++++++ arch/powerpc/kernel/machine_kexec_64.c | 25 +------ arch/powerpc/kernel/misc_32.S | 113 ++++++++++++++++++++++++++++++++ arch/powerpc/kernel/setup-common.c | 4 +- arch/powerpc/platforms/cell/setup.c | 5 ++ arch/powerpc/platforms/maple/setup.c | 5 ++ arch/powerpc/platforms/powermac/nvram.c | 1 + arch/powerpc/platforms/powermac/setup.c | 5 ++ arch/powerpc/platforms/pseries/setup.c | 3 + arch/ppc/kernel/Makefile | 1 - include/asm-powerpc/kexec.h | 7 +- include/asm-powerpc/machdep.h | 8 ++- 14 files changed, 281 insertions(+), 33 deletions(-) create mode 100644 arch/powerpc/kernel/machine_kexec.c create mode 100644 arch/powerpc/kernel/machine_kexec_32.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 9ed551b6c172..e7776a438a84 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -65,8 +65,9 @@ pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \ pci_direct_iommu.o iomap.o obj-$(CONFIG_PCI) += $(pci64-y) -kexec64-$(CONFIG_PPC64) += machine_kexec_64.o -obj-$(CONFIG_KEXEC) += $(kexec64-y) +kexec-$(CONFIG_PPC64) := machine_kexec_64.o +kexec-$(CONFIG_PPC32) := machine_kexec_32.o +obj-$(CONFIG_KEXEC) += machine_kexec.o $(kexec-y) ifeq ($(CONFIG_PPC_ISERIES),y) $(obj)/head_64.o: $(obj)/lparmap.s diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c new file mode 100644 index 000000000000..d8225c797199 --- /dev/null +++ b/arch/powerpc/kernel/machine_kexec.c @@ -0,0 +1,67 @@ +/* + * Code to handle transition of Linux booting another kernel. + * + * Copyright (C) 2002-2003 Eric Biederman + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz + * Copyright (C) 2005 IBM Corporation. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include + +/* + * Provide a dummy crash_notes definition until crash dump is implemented. + * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. + */ +note_buf_t crash_notes[NR_CPUS]; + +void machine_crash_shutdown(struct pt_regs *regs) +{ + if (ppc_md.machine_crash_shutdown) + ppc_md.machine_crash_shutdown(); +} + +/* + * Do what every setup is needed on image and the + * reboot code buffer to allow us to avoid allocations + * later. + */ +int machine_kexec_prepare(struct kimage *image) +{ + if (ppc_md.machine_kexec_prepare) + return ppc_md.machine_kexec_prepare(image); + /* + * Fail if platform doesn't provide its own machine_kexec_prepare + * implementation. + */ + return -ENOSYS; +} + +void machine_kexec_cleanup(struct kimage *image) +{ + if (ppc_md.machine_kexec_cleanup) + ppc_md.machine_kexec_cleanup(image); +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) +{ + if (ppc_md.machine_kexec) + ppc_md.machine_kexec(image); + else { + /* + * Fall back to normal restart if platform doesn't provide + * its own kexec function, and user insist to kexec... + */ + machine_restart(NULL); + } + for(;;); +} diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c new file mode 100644 index 000000000000..443606134dff --- /dev/null +++ b/arch/powerpc/kernel/machine_kexec_32.c @@ -0,0 +1,65 @@ +/* + * PPC32 code to handle Linux booting another kernel. + * + * Copyright (C) 2002-2003 Eric Biederman + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz + * Copyright (C) 2005 IBM Corporation. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include + +typedef NORET_TYPE void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long reboot_code_buffer, + unsigned long start_address) ATTRIB_NORET; + +/* + * This is a generic machine_kexec function suitable at least for + * non-OpenFirmware embedded platforms. + * It merely copies the image relocation code to the control page and + * jumps to it. + * A platform specific function may just call this one. + */ +void default_machine_kexec(struct kimage *image) +{ + const extern unsigned char relocate_new_kernel[]; + const extern unsigned int relocate_new_kernel_size; + unsigned long page_list; + unsigned long reboot_code_buffer, reboot_code_buffer_phys; + relocate_new_kernel_t rnk; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + page_list = image->head; + + /* we need both effective and real address here */ + reboot_code_buffer = + (unsigned long)page_address(image->control_code_page); + reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); + + /* copy our kernel relocation code to the control code page */ + memcpy((void *)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); + + flush_icache_range(reboot_code_buffer, + reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); + printk(KERN_INFO "Bye!\n"); + + /* now call it */ + rnk = (relocate_new_kernel_t) reboot_code_buffer; + (*rnk)(page_list, reboot_code_buffer_phys, image->start); +} + +int default_machine_kexec_prepare(struct kimage *image) +{ + return 0; +} diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 97c51e452be7..ec0f06bfc24a 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -1,5 +1,5 @@ /* - * machine_kexec.c - handle transition of Linux booting another kernel + * PPC64 code to handle Linux booting another kernel. * * Copyright (C) 2004-2005, IBM Corp. * @@ -28,21 +28,7 @@ #define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ -/* Have this around till we move it into crash specific file */ -note_buf_t crash_notes[NR_CPUS]; - -/* Dummy for now. Not sure if we need to have a crash shutdown in here - * and if what it will achieve. Letting it be now to compile the code - * in generic kexec environment - */ -void machine_crash_shutdown(struct pt_regs *regs) -{ - /* do nothing right now */ - /* smp_relase_cpus() if we want smp on panic kernel */ - /* cpu_irq_down to isolate us until we are ready */ -} - -int machine_kexec_prepare(struct kimage *image) +int default_machine_kexec_prepare(struct kimage *image) { int i; unsigned long begin, end; /* limits of segment */ @@ -111,11 +97,6 @@ int machine_kexec_prepare(struct kimage *image) return 0; } -void machine_kexec_cleanup(struct kimage *image) -{ - /* we do nothing in prepare that needs to be undone */ -} - #define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) static void copy_segments(unsigned long ind) @@ -283,7 +264,7 @@ extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, void (*clear_all)(void)) ATTRIB_NORET; /* too late to fail here */ -void machine_kexec(struct kimage *image) +void default_machine_kexec(struct kimage *image) { /* prepare control code if any */ diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 624a983a9676..01d0d97a16e1 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -5,6 +5,10 @@ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras. * + * kexec bits: + * Copyright (C) 2002-2003 Eric Biederman + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -24,6 +28,8 @@ #include #include #include +#include +#include .text @@ -1006,3 +1012,110 @@ _GLOBAL(execve) */ _GLOBAL(__main) blr + +#ifdef CONFIG_KEXEC + /* + * Must be relocatable PIC code callable as a C function. + */ + .globl relocate_new_kernel +relocate_new_kernel: + /* r3 = page_list */ + /* r4 = reboot_code_buffer */ + /* r5 = start_address */ + + li r0, 0 + + /* + * Set Machine Status Register to a known status, + * switch the MMU off and jump to 1: in a single step. + */ + + mr r8, r0 + ori r8, r8, MSR_RI|MSR_ME + mtspr SPRN_SRR1, r8 + addi r8, r4, 1f - relocate_new_kernel + mtspr SPRN_SRR0, r8 + sync + rfi + +1: + /* from this point address translation is turned off */ + /* and interrupts are disabled */ + + /* set a new stack at the bottom of our page... */ + /* (not really needed now) */ + addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ + stw r0, 0(r1) + + /* Do the copies */ + li r6, 0 /* checksum */ + mr r0, r3 + b 1f + +0: /* top, read another word for the indirection page */ + lwzu r0, 4(r3) + +1: + /* is it a destination page? (r8) */ + rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ + beq 2f + + rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ + b 0b + +2: /* is it an indirection page? (r3) */ + rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ + beq 2f + + rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ + subi r3, r3, 4 + b 0b + +2: /* are we done? */ + rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ + beq 2f + b 3f + +2: /* is it a source page? (r9) */ + rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ + beq 0b + + rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ + + li r7, PAGE_SIZE / 4 + mtctr r7 + subi r9, r9, 4 + subi r8, r8, 4 +9: + lwzu r0, 4(r9) /* do the copy */ + xor r6, r6, r0 + stwu r0, 4(r8) + dcbst 0, r8 + sync + icbi 0, r8 + bdnz 9b + + addi r9, r9, 4 + addi r8, r8, 4 + b 0b + +3: + + /* To be certain of avoiding problems with self-modifying code + * execute a serializing instruction here. + */ + isync + sync + + /* jump to the entry point, usually the setup routine */ + mtlr r5 + blrl + +1: b 1b + +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel +#endif diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index bd3eb4292b53..6088a39edc26 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -93,8 +93,8 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs); /* also used by kexec */ void machine_shutdown(void) { - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); + if (ppc_md.machine_shutdown) + ppc_md.machine_shutdown(); } void machine_restart(char *cmd) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 9a495634d0c2..d45dc18855a5 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -138,4 +139,8 @@ struct machdep_calls __initdata cell_md = { .set_rtc_time = rtas_set_rtc_time, .calibrate_decr = generic_calibrate_decr, .progress = cell_progress, +#ifdef CONFIG_KEXEC + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, +#endif }; diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 7ece8983a105..95b2352655fe 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -292,4 +293,8 @@ struct machdep_calls __initdata maple_md = { .calibrate_decr = generic_calibrate_decr, .progress = maple_progress, .idle_loop = native_idle, +#ifdef CONFIG_KEXEC + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, +#endif }; diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 4042e2f06ee0..59e0e51cf663 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -549,6 +549,7 @@ static int __init core99_nvram_setup(struct device_node *dp) ppc_md.nvram_write = core99_nvram_write; ppc_md.nvram_size = core99_nvram_size; ppc_md.nvram_sync = core99_nvram_sync; + ppc_md.machine_shutdown = core99_nvram_sync; /* * Maybe we could be smarter here though making an exclusive list * of known flash chips is a bit nasty as older OF didn't provide us diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 7acb0546671f..3b7a492d9b68 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -773,7 +774,11 @@ struct machdep_calls __initdata pmac_md = { .pci_probe_mode = pmac_probe_mode, .idle_loop = native_idle, .enable_pmcs = power4_enable_pmcs, +#ifdef CONFIG_KEXEC + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, #endif +#endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC32 .pcibios_enable_device_hook = pmac_pci_enable_device_hook, .pcibios_after_init = pmac_pcibios_after_init, diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 4a465f067ede..8a4238a3757f 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include "xics.h" @@ -638,5 +639,7 @@ struct machdep_calls __initdata pSeries_md = { .machine_check_exception = pSeries_machine_check_exception, #ifdef CONFIG_KEXEC .kexec_cpu_down = pseries_kexec_cpu_down, + .machine_kexec = default_machine_kexec, + .machine_kexec_prepare = default_machine_kexec_prepare, #endif }; diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 0bb23fce4293..e6c1d615bb86 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -49,5 +49,4 @@ obj-$(CONFIG_TAU) += temp.o ifndef CONFIG_E200 obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o endif -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o endif diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h index c72ffc709ea8..934b4981651d 100644 --- a/include/asm-powerpc/kexec.h +++ b/include/asm-powerpc/kexec.h @@ -41,10 +41,11 @@ extern note_buf_t crash_notes[]; extern void kexec_smp_wait(void); /* get and clear naca physid, wait for master to copy new code to 0 */ extern void __init kexec_setup(void); -#else -struct kimage; -extern void machine_kexec_simple(struct kimage *image); #endif +struct kimage; +extern void default_machine_kexec(struct kimage *image); +extern int default_machine_kexec_prepare(struct kimage *image); + #endif /* ! __ASSEMBLY__ */ #endif /* _ASM_POWERPC_KEXEC_H */ diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index c011abb8b600..d6a1a2b5507d 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -27,6 +27,9 @@ struct device_node; struct iommu_table; struct rtc_time; struct file; +#ifdef CONFIG_KEXEC +struct kimage; +#endif #ifdef CONFIG_SMP struct smp_ops_t { @@ -207,14 +210,14 @@ struct machdep_calls { /* this is for modules, since _machine can be a define -- Cort */ int ppc_machine; +#endif /* CONFIG_PPC32 */ -#ifdef CONFIG_KEXEC /* Called to shutdown machine specific hardware not already controlled * by other drivers. - * XXX Should we move this one out of kexec scope? */ void (*machine_shutdown)(void); +#ifdef CONFIG_KEXEC /* Called to do the minimal shutdown needed to run a kexec'd kernel * to run successfully. * XXX Should we move this one out of kexec scope? @@ -237,7 +240,6 @@ struct machdep_calls { */ void (*machine_kexec)(struct kimage *image); #endif /* CONFIG_KEXEC */ -#endif /* CONFIG_PPC32 */ }; extern void default_idle(void); -- cgit v1.2.3 From 1cd8e506209223ed10da805d99be55e268f4023c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 14 Nov 2005 12:54:33 -0600 Subject: [PATCH] powerpc: moved ipic code to arch/powerpc Moved 83xx and QUICC Engine interrupt handling code into arch/powerpc as a precursor of getting 83xx sub-arch building in arch/powerpc. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/ipic.c | 646 +++++++++++++++++++++++++++++++++++++++++++ arch/powerpc/sysdev/ipic.h | 49 ++++ arch/ppc/syslib/Makefile | 2 +- arch/ppc/syslib/ipic.c | 646 ------------------------------------------- arch/ppc/syslib/ipic.h | 49 ---- include/asm-powerpc/ipic.h | 85 ++++++ include/asm-ppc/ipic.h | 85 ------ 8 files changed, 782 insertions(+), 781 deletions(-) create mode 100644 arch/powerpc/sysdev/ipic.c create mode 100644 arch/powerpc/sysdev/ipic.h delete mode 100644 arch/ppc/syslib/ipic.c delete mode 100644 arch/ppc/syslib/ipic.h create mode 100644 include/asm-powerpc/ipic.h delete mode 100644 include/asm-ppc/ipic.h diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 6b7efcfc352a..b3e3636a57b0 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_BOOKE) += dcr.o obj-$(CONFIG_40x) += dcr.o obj-$(CONFIG_U3_DART) += u3_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o +obj-$(CONFIG_83xx) += ipic.o diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c new file mode 100644 index 000000000000..8f01e0f1d847 --- /dev/null +++ b/arch/powerpc/sysdev/ipic.c @@ -0,0 +1,646 @@ +/* + * include/asm-ppc/ipic.c + * + * IPIC routines implementations. + * + * Copyright 2005 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipic.h" + +static struct ipic p_ipic; +static struct ipic * primary_ipic; + +static struct ipic_info ipic_info[] = { + [9] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 24, + .prio_mask = 0, + }, + [10] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 25, + .prio_mask = 1, + }, + [11] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 26, + .prio_mask = 2, + }, + [14] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 29, + .prio_mask = 5, + }, + [15] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 30, + .prio_mask = 6, + }, + [16] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_D, + .force = IPIC_SIFCR_H, + .bit = 31, + .prio_mask = 7, + }, + [17] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 1, + .prio_mask = 5, + }, + [18] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 2, + .prio_mask = 6, + }, + [19] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 3, + .prio_mask = 7, + }, + [20] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 4, + .prio_mask = 4, + }, + [21] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 5, + .prio_mask = 5, + }, + [22] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 6, + .prio_mask = 6, + }, + [23] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_B, + .force = IPIC_SEFCR, + .bit = 7, + .prio_mask = 7, + }, + [32] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 0, + .prio_mask = 0, + }, + [33] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 1, + .prio_mask = 1, + }, + [34] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 2, + .prio_mask = 2, + }, + [35] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 3, + .prio_mask = 3, + }, + [36] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 4, + .prio_mask = 4, + }, + [37] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 5, + .prio_mask = 5, + }, + [38] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 6, + .prio_mask = 6, + }, + [39] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_H, + .prio = IPIC_SIPRR_A, + .force = IPIC_SIFCR_H, + .bit = 7, + .prio_mask = 7, + }, + [48] = { + .pend = IPIC_SEPNR, + .mask = IPIC_SEMSR, + .prio = IPIC_SMPRR_A, + .force = IPIC_SEFCR, + .bit = 0, + .prio_mask = 4, + }, + [64] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 0, + .prio_mask = 0, + }, + [65] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 1, + .prio_mask = 1, + }, + [66] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 2, + .prio_mask = 2, + }, + [67] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_A, + .force = IPIC_SIFCR_L, + .bit = 3, + .prio_mask = 3, + }, + [68] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 4, + .prio_mask = 0, + }, + [69] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 5, + .prio_mask = 1, + }, + [70] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 6, + .prio_mask = 2, + }, + [71] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = IPIC_SMPRR_B, + .force = IPIC_SIFCR_L, + .bit = 7, + .prio_mask = 3, + }, + [72] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 8, + }, + [73] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 9, + }, + [74] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 10, + }, + [75] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 11, + }, + [76] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 12, + }, + [77] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 13, + }, + [78] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 14, + }, + [79] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 15, + }, + [80] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 16, + }, + [84] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 20, + }, + [85] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 21, + }, + [90] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 26, + }, + [91] = { + .pend = IPIC_SIPNR_H, + .mask = IPIC_SIMSR_L, + .prio = 0, + .force = IPIC_SIFCR_L, + .bit = 27, + }, +}; + +static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg) +{ + return in_be32(base + (reg >> 2)); +} + +static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value) +{ + out_be32(base + (reg >> 2), value); +} + +static inline struct ipic * ipic_from_irq(unsigned int irq) +{ + return primary_ipic; +} + +static void ipic_enable_irq(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + temp = ipic_read(ipic->regs, ipic_info[src].mask); + temp |= (1 << (31 - ipic_info[src].bit)); + ipic_write(ipic->regs, ipic_info[src].mask, temp); +} + +static void ipic_disable_irq(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + temp = ipic_read(ipic->regs, ipic_info[src].mask); + temp &= ~(1 << (31 - ipic_info[src].bit)); + ipic_write(ipic->regs, ipic_info[src].mask, temp); +} + +static void ipic_disable_irq_and_ack(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + ipic_disable_irq(irq); + + temp = ipic_read(ipic->regs, ipic_info[src].pend); + temp |= (1 << (31 - ipic_info[src].bit)); + ipic_write(ipic->regs, ipic_info[src].pend, temp); +} + +static void ipic_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + ipic_enable_irq(irq); +} + +struct hw_interrupt_type ipic = { + .typename = " IPIC ", + .enable = ipic_enable_irq, + .disable = ipic_disable_irq, + .ack = ipic_disable_irq_and_ack, + .end = ipic_end_irq, +}; + +void __init ipic_init(phys_addr_t phys_addr, + unsigned int flags, + unsigned int irq_offset, + unsigned char *senses, + unsigned int senses_count) +{ + u32 i, temp = 0; + + primary_ipic = &p_ipic; + primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE); + + primary_ipic->irq_offset = irq_offset; + + ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0); + + /* default priority scheme is grouped. If spread mode is required + * configure SICFR accordingly */ + if (flags & IPIC_SPREADMODE_GRP_A) + temp |= SICFR_IPSA; + if (flags & IPIC_SPREADMODE_GRP_D) + temp |= SICFR_IPSD; + if (flags & IPIC_SPREADMODE_MIX_A) + temp |= SICFR_MPSA; + if (flags & IPIC_SPREADMODE_MIX_B) + temp |= SICFR_MPSB; + + ipic_write(primary_ipic->regs, IPIC_SICNR, temp); + + /* handle MCP route */ + temp = 0; + if (flags & IPIC_DISABLE_MCP_OUT) + temp = SERCR_MCPR; + ipic_write(primary_ipic->regs, IPIC_SERCR, temp); + + /* handle routing of IRQ0 to MCP */ + temp = ipic_read(primary_ipic->regs, IPIC_SEMSR); + + if (flags & IPIC_IRQ0_MCP) + temp |= SEMSR_SIRQ0; + else + temp &= ~SEMSR_SIRQ0; + + ipic_write(primary_ipic->regs, IPIC_SEMSR, temp); + + for (i = 0 ; i < NR_IPIC_INTS ; i++) { + irq_desc[i+irq_offset].handler = &ipic; + irq_desc[i+irq_offset].status = IRQ_LEVEL; + } + + temp = 0; + for (i = 0 ; i < senses_count ; i++) { + if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) { + temp |= 1 << (15 - i); + if (i != 0) + irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0; + else + irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0; + } + } + ipic_write(primary_ipic->regs, IPIC_SECNR, temp); + + printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS, + senses_count, primary_ipic->regs); +} + +int ipic_set_priority(unsigned int irq, unsigned int priority) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + if (priority > 7) + return -EINVAL; + if (src > 127) + return -EINVAL; + if (ipic_info[src].prio == 0) + return -EINVAL; + + temp = ipic_read(ipic->regs, ipic_info[src].prio); + + if (priority < 4) { + temp &= ~(0x7 << (20 + (3 - priority) * 3)); + temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3); + } else { + temp &= ~(0x7 << (4 + (7 - priority) * 3)); + temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3); + } + + ipic_write(ipic->regs, ipic_info[src].prio, temp); + + return 0; +} + +void ipic_set_highest_priority(unsigned int irq) +{ + struct ipic *ipic = ipic_from_irq(irq); + unsigned int src = irq - ipic->irq_offset; + u32 temp; + + temp = ipic_read(ipic->regs, IPIC_SICFR); + + /* clear and set HPI */ + temp &= 0x7f000000; + temp |= (src & 0x7f) << 24; + + ipic_write(ipic->regs, IPIC_SICFR, temp); +} + +void ipic_set_default_priority(void) +{ + ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0); + ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1); + ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2); + ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3); + ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4); + ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5); + ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6); + ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7); + + ipic_set_priority(MPC83xx_IRQ_UART1, 0); + ipic_set_priority(MPC83xx_IRQ_UART2, 1); + ipic_set_priority(MPC83xx_IRQ_SEC2, 2); + ipic_set_priority(MPC83xx_IRQ_IIC1, 5); + ipic_set_priority(MPC83xx_IRQ_IIC2, 6); + ipic_set_priority(MPC83xx_IRQ_SPI, 7); + ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0); + ipic_set_priority(MPC83xx_IRQ_PIT, 1); + ipic_set_priority(MPC83xx_IRQ_PCI1, 2); + ipic_set_priority(MPC83xx_IRQ_PCI2, 3); + ipic_set_priority(MPC83xx_IRQ_EXT0, 4); + ipic_set_priority(MPC83xx_IRQ_EXT1, 5); + ipic_set_priority(MPC83xx_IRQ_EXT2, 6); + ipic_set_priority(MPC83xx_IRQ_EXT3, 7); + ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0); + ipic_set_priority(MPC83xx_IRQ_MU, 1); + ipic_set_priority(MPC83xx_IRQ_SBA, 2); + ipic_set_priority(MPC83xx_IRQ_DMA, 3); + ipic_set_priority(MPC83xx_IRQ_EXT4, 4); + ipic_set_priority(MPC83xx_IRQ_EXT5, 5); + ipic_set_priority(MPC83xx_IRQ_EXT6, 6); + ipic_set_priority(MPC83xx_IRQ_EXT7, 7); +} + +void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq) +{ + struct ipic *ipic = primary_ipic; + u32 temp; + + temp = ipic_read(ipic->regs, IPIC_SERMR); + temp |= (1 << (31 - mcp_irq)); + ipic_write(ipic->regs, IPIC_SERMR, temp); +} + +void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq) +{ + struct ipic *ipic = primary_ipic; + u32 temp; + + temp = ipic_read(ipic->regs, IPIC_SERMR); + temp &= (1 << (31 - mcp_irq)); + ipic_write(ipic->regs, IPIC_SERMR, temp); +} + +u32 ipic_get_mcp_status(void) +{ + return ipic_read(primary_ipic->regs, IPIC_SERMR); +} + +void ipic_clear_mcp_status(u32 mask) +{ + ipic_write(primary_ipic->regs, IPIC_SERMR, mask); +} + +/* Return an interrupt vector or -1 if no interrupt is pending. */ +int ipic_get_irq(struct pt_regs *regs) +{ + int irq; + + irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f; + + if (irq == 0) /* 0 --> no irq is pending */ + irq = -1; + + return irq; +} + +static struct sysdev_class ipic_sysclass = { + set_kset_name("ipic"), +}; + +static struct sys_device device_ipic = { + .id = 0, + .cls = &ipic_sysclass, +}; + +static int __init init_ipic_sysfs(void) +{ + int rc; + + if (!primary_ipic->regs) + return -ENODEV; + printk(KERN_DEBUG "Registering ipic with sysfs...\n"); + + rc = sysdev_class_register(&ipic_sysclass); + if (rc) { + printk(KERN_ERR "Failed registering ipic sys class\n"); + return -ENODEV; + } + rc = sysdev_register(&device_ipic); + if (rc) { + printk(KERN_ERR "Failed registering ipic sys device\n"); + return -ENODEV; + } + return 0; +} + +subsys_initcall(init_ipic_sysfs); diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h new file mode 100644 index 000000000000..a7ce7da8785c --- /dev/null +++ b/arch/powerpc/sysdev/ipic.h @@ -0,0 +1,49 @@ +/* + * arch/ppc/kernel/ipic.h + * + * IPIC private definitions and structure. + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __IPIC_H__ +#define __IPIC_H__ + +#include + +#define MPC83xx_IPIC_SIZE (0x00100) + +/* System Global Interrupt Configuration Register */ +#define SICFR_IPSA 0x00010000 +#define SICFR_IPSD 0x00080000 +#define SICFR_MPSA 0x00200000 +#define SICFR_MPSB 0x00400000 + +/* System External Interrupt Mask Register */ +#define SEMSR_SIRQ0 0x00008000 + +/* System Error Control Register */ +#define SERCR_MCPR 0x00000001 + +struct ipic { + volatile u32 __iomem *regs; + unsigned int irq_offset; +}; + +struct ipic_info { + u8 pend; /* pending register offset from base */ + u8 mask; /* mask register offset from base */ + u8 prio; /* priority register offset from base */ + u8 force; /* force register offset from base */ + u8 bit; /* register bit position (as per doc) + bit mask = 1 << (31 - bit) */ + u8 prio_mask; /* priority mask value */ +}; + +#endif /* __IPIC_H__ */ diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 5b7f2b80e56e..84ef03018d0e 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -96,7 +96,7 @@ ifeq ($(CONFIG_85xx),y) obj-$(CONFIG_PCI) += pci_auto.o endif obj-$(CONFIG_RAPIDIO) += ppc85xx_rio.o -obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \ +obj-$(CONFIG_83xx) += ppc83xx_setup.o ppc_sys.o \ mpc83xx_sys.o mpc83xx_devices.o ifeq ($(CONFIG_83xx),y) obj-$(CONFIG_PCI) += pci_auto.o diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c deleted file mode 100644 index 8f01e0f1d847..000000000000 --- a/arch/ppc/syslib/ipic.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * include/asm-ppc/ipic.c - * - * IPIC routines implementations. - * - * Copyright 2005 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ipic.h" - -static struct ipic p_ipic; -static struct ipic * primary_ipic; - -static struct ipic_info ipic_info[] = { - [9] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_D, - .force = IPIC_SIFCR_H, - .bit = 24, - .prio_mask = 0, - }, - [10] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_D, - .force = IPIC_SIFCR_H, - .bit = 25, - .prio_mask = 1, - }, - [11] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_D, - .force = IPIC_SIFCR_H, - .bit = 26, - .prio_mask = 2, - }, - [14] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_D, - .force = IPIC_SIFCR_H, - .bit = 29, - .prio_mask = 5, - }, - [15] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_D, - .force = IPIC_SIFCR_H, - .bit = 30, - .prio_mask = 6, - }, - [16] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_D, - .force = IPIC_SIFCR_H, - .bit = 31, - .prio_mask = 7, - }, - [17] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_A, - .force = IPIC_SEFCR, - .bit = 1, - .prio_mask = 5, - }, - [18] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_A, - .force = IPIC_SEFCR, - .bit = 2, - .prio_mask = 6, - }, - [19] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_A, - .force = IPIC_SEFCR, - .bit = 3, - .prio_mask = 7, - }, - [20] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_B, - .force = IPIC_SEFCR, - .bit = 4, - .prio_mask = 4, - }, - [21] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_B, - .force = IPIC_SEFCR, - .bit = 5, - .prio_mask = 5, - }, - [22] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_B, - .force = IPIC_SEFCR, - .bit = 6, - .prio_mask = 6, - }, - [23] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_B, - .force = IPIC_SEFCR, - .bit = 7, - .prio_mask = 7, - }, - [32] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 0, - .prio_mask = 0, - }, - [33] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 1, - .prio_mask = 1, - }, - [34] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 2, - .prio_mask = 2, - }, - [35] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 3, - .prio_mask = 3, - }, - [36] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 4, - .prio_mask = 4, - }, - [37] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 5, - .prio_mask = 5, - }, - [38] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 6, - .prio_mask = 6, - }, - [39] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_H, - .prio = IPIC_SIPRR_A, - .force = IPIC_SIFCR_H, - .bit = 7, - .prio_mask = 7, - }, - [48] = { - .pend = IPIC_SEPNR, - .mask = IPIC_SEMSR, - .prio = IPIC_SMPRR_A, - .force = IPIC_SEFCR, - .bit = 0, - .prio_mask = 4, - }, - [64] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_A, - .force = IPIC_SIFCR_L, - .bit = 0, - .prio_mask = 0, - }, - [65] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_A, - .force = IPIC_SIFCR_L, - .bit = 1, - .prio_mask = 1, - }, - [66] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_A, - .force = IPIC_SIFCR_L, - .bit = 2, - .prio_mask = 2, - }, - [67] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_A, - .force = IPIC_SIFCR_L, - .bit = 3, - .prio_mask = 3, - }, - [68] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_B, - .force = IPIC_SIFCR_L, - .bit = 4, - .prio_mask = 0, - }, - [69] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_B, - .force = IPIC_SIFCR_L, - .bit = 5, - .prio_mask = 1, - }, - [70] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_B, - .force = IPIC_SIFCR_L, - .bit = 6, - .prio_mask = 2, - }, - [71] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = IPIC_SMPRR_B, - .force = IPIC_SIFCR_L, - .bit = 7, - .prio_mask = 3, - }, - [72] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 8, - }, - [73] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 9, - }, - [74] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 10, - }, - [75] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 11, - }, - [76] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 12, - }, - [77] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 13, - }, - [78] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 14, - }, - [79] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 15, - }, - [80] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 16, - }, - [84] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 20, - }, - [85] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 21, - }, - [90] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 26, - }, - [91] = { - .pend = IPIC_SIPNR_H, - .mask = IPIC_SIMSR_L, - .prio = 0, - .force = IPIC_SIFCR_L, - .bit = 27, - }, -}; - -static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg) -{ - return in_be32(base + (reg >> 2)); -} - -static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value) -{ - out_be32(base + (reg >> 2), value); -} - -static inline struct ipic * ipic_from_irq(unsigned int irq) -{ - return primary_ipic; -} - -static void ipic_enable_irq(unsigned int irq) -{ - struct ipic *ipic = ipic_from_irq(irq); - unsigned int src = irq - ipic->irq_offset; - u32 temp; - - temp = ipic_read(ipic->regs, ipic_info[src].mask); - temp |= (1 << (31 - ipic_info[src].bit)); - ipic_write(ipic->regs, ipic_info[src].mask, temp); -} - -static void ipic_disable_irq(unsigned int irq) -{ - struct ipic *ipic = ipic_from_irq(irq); - unsigned int src = irq - ipic->irq_offset; - u32 temp; - - temp = ipic_read(ipic->regs, ipic_info[src].mask); - temp &= ~(1 << (31 - ipic_info[src].bit)); - ipic_write(ipic->regs, ipic_info[src].mask, temp); -} - -static void ipic_disable_irq_and_ack(unsigned int irq) -{ - struct ipic *ipic = ipic_from_irq(irq); - unsigned int src = irq - ipic->irq_offset; - u32 temp; - - ipic_disable_irq(irq); - - temp = ipic_read(ipic->regs, ipic_info[src].pend); - temp |= (1 << (31 - ipic_info[src].bit)); - ipic_write(ipic->regs, ipic_info[src].pend, temp); -} - -static void ipic_end_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - ipic_enable_irq(irq); -} - -struct hw_interrupt_type ipic = { - .typename = " IPIC ", - .enable = ipic_enable_irq, - .disable = ipic_disable_irq, - .ack = ipic_disable_irq_and_ack, - .end = ipic_end_irq, -}; - -void __init ipic_init(phys_addr_t phys_addr, - unsigned int flags, - unsigned int irq_offset, - unsigned char *senses, - unsigned int senses_count) -{ - u32 i, temp = 0; - - primary_ipic = &p_ipic; - primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE); - - primary_ipic->irq_offset = irq_offset; - - ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0); - - /* default priority scheme is grouped. If spread mode is required - * configure SICFR accordingly */ - if (flags & IPIC_SPREADMODE_GRP_A) - temp |= SICFR_IPSA; - if (flags & IPIC_SPREADMODE_GRP_D) - temp |= SICFR_IPSD; - if (flags & IPIC_SPREADMODE_MIX_A) - temp |= SICFR_MPSA; - if (flags & IPIC_SPREADMODE_MIX_B) - temp |= SICFR_MPSB; - - ipic_write(primary_ipic->regs, IPIC_SICNR, temp); - - /* handle MCP route */ - temp = 0; - if (flags & IPIC_DISABLE_MCP_OUT) - temp = SERCR_MCPR; - ipic_write(primary_ipic->regs, IPIC_SERCR, temp); - - /* handle routing of IRQ0 to MCP */ - temp = ipic_read(primary_ipic->regs, IPIC_SEMSR); - - if (flags & IPIC_IRQ0_MCP) - temp |= SEMSR_SIRQ0; - else - temp &= ~SEMSR_SIRQ0; - - ipic_write(primary_ipic->regs, IPIC_SEMSR, temp); - - for (i = 0 ; i < NR_IPIC_INTS ; i++) { - irq_desc[i+irq_offset].handler = &ipic; - irq_desc[i+irq_offset].status = IRQ_LEVEL; - } - - temp = 0; - for (i = 0 ; i < senses_count ; i++) { - if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) { - temp |= 1 << (15 - i); - if (i != 0) - irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0; - else - irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0; - } - } - ipic_write(primary_ipic->regs, IPIC_SECNR, temp); - - printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS, - senses_count, primary_ipic->regs); -} - -int ipic_set_priority(unsigned int irq, unsigned int priority) -{ - struct ipic *ipic = ipic_from_irq(irq); - unsigned int src = irq - ipic->irq_offset; - u32 temp; - - if (priority > 7) - return -EINVAL; - if (src > 127) - return -EINVAL; - if (ipic_info[src].prio == 0) - return -EINVAL; - - temp = ipic_read(ipic->regs, ipic_info[src].prio); - - if (priority < 4) { - temp &= ~(0x7 << (20 + (3 - priority) * 3)); - temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3); - } else { - temp &= ~(0x7 << (4 + (7 - priority) * 3)); - temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3); - } - - ipic_write(ipic->regs, ipic_info[src].prio, temp); - - return 0; -} - -void ipic_set_highest_priority(unsigned int irq) -{ - struct ipic *ipic = ipic_from_irq(irq); - unsigned int src = irq - ipic->irq_offset; - u32 temp; - - temp = ipic_read(ipic->regs, IPIC_SICFR); - - /* clear and set HPI */ - temp &= 0x7f000000; - temp |= (src & 0x7f) << 24; - - ipic_write(ipic->regs, IPIC_SICFR, temp); -} - -void ipic_set_default_priority(void) -{ - ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0); - ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1); - ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2); - ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3); - ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4); - ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5); - ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6); - ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7); - - ipic_set_priority(MPC83xx_IRQ_UART1, 0); - ipic_set_priority(MPC83xx_IRQ_UART2, 1); - ipic_set_priority(MPC83xx_IRQ_SEC2, 2); - ipic_set_priority(MPC83xx_IRQ_IIC1, 5); - ipic_set_priority(MPC83xx_IRQ_IIC2, 6); - ipic_set_priority(MPC83xx_IRQ_SPI, 7); - ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0); - ipic_set_priority(MPC83xx_IRQ_PIT, 1); - ipic_set_priority(MPC83xx_IRQ_PCI1, 2); - ipic_set_priority(MPC83xx_IRQ_PCI2, 3); - ipic_set_priority(MPC83xx_IRQ_EXT0, 4); - ipic_set_priority(MPC83xx_IRQ_EXT1, 5); - ipic_set_priority(MPC83xx_IRQ_EXT2, 6); - ipic_set_priority(MPC83xx_IRQ_EXT3, 7); - ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0); - ipic_set_priority(MPC83xx_IRQ_MU, 1); - ipic_set_priority(MPC83xx_IRQ_SBA, 2); - ipic_set_priority(MPC83xx_IRQ_DMA, 3); - ipic_set_priority(MPC83xx_IRQ_EXT4, 4); - ipic_set_priority(MPC83xx_IRQ_EXT5, 5); - ipic_set_priority(MPC83xx_IRQ_EXT6, 6); - ipic_set_priority(MPC83xx_IRQ_EXT7, 7); -} - -void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq) -{ - struct ipic *ipic = primary_ipic; - u32 temp; - - temp = ipic_read(ipic->regs, IPIC_SERMR); - temp |= (1 << (31 - mcp_irq)); - ipic_write(ipic->regs, IPIC_SERMR, temp); -} - -void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq) -{ - struct ipic *ipic = primary_ipic; - u32 temp; - - temp = ipic_read(ipic->regs, IPIC_SERMR); - temp &= (1 << (31 - mcp_irq)); - ipic_write(ipic->regs, IPIC_SERMR, temp); -} - -u32 ipic_get_mcp_status(void) -{ - return ipic_read(primary_ipic->regs, IPIC_SERMR); -} - -void ipic_clear_mcp_status(u32 mask) -{ - ipic_write(primary_ipic->regs, IPIC_SERMR, mask); -} - -/* Return an interrupt vector or -1 if no interrupt is pending. */ -int ipic_get_irq(struct pt_regs *regs) -{ - int irq; - - irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f; - - if (irq == 0) /* 0 --> no irq is pending */ - irq = -1; - - return irq; -} - -static struct sysdev_class ipic_sysclass = { - set_kset_name("ipic"), -}; - -static struct sys_device device_ipic = { - .id = 0, - .cls = &ipic_sysclass, -}; - -static int __init init_ipic_sysfs(void) -{ - int rc; - - if (!primary_ipic->regs) - return -ENODEV; - printk(KERN_DEBUG "Registering ipic with sysfs...\n"); - - rc = sysdev_class_register(&ipic_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering ipic sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&device_ipic); - if (rc) { - printk(KERN_ERR "Failed registering ipic sys device\n"); - return -ENODEV; - } - return 0; -} - -subsys_initcall(init_ipic_sysfs); diff --git a/arch/ppc/syslib/ipic.h b/arch/ppc/syslib/ipic.h deleted file mode 100644 index a7ce7da8785c..000000000000 --- a/arch/ppc/syslib/ipic.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * arch/ppc/kernel/ipic.h - * - * IPIC private definitions and structure. - * - * Maintainer: Kumar Gala - * - * Copyright 2005 Freescale Semiconductor, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#ifndef __IPIC_H__ -#define __IPIC_H__ - -#include - -#define MPC83xx_IPIC_SIZE (0x00100) - -/* System Global Interrupt Configuration Register */ -#define SICFR_IPSA 0x00010000 -#define SICFR_IPSD 0x00080000 -#define SICFR_MPSA 0x00200000 -#define SICFR_MPSB 0x00400000 - -/* System External Interrupt Mask Register */ -#define SEMSR_SIRQ0 0x00008000 - -/* System Error Control Register */ -#define SERCR_MCPR 0x00000001 - -struct ipic { - volatile u32 __iomem *regs; - unsigned int irq_offset; -}; - -struct ipic_info { - u8 pend; /* pending register offset from base */ - u8 mask; /* mask register offset from base */ - u8 prio; /* priority register offset from base */ - u8 force; /* force register offset from base */ - u8 bit; /* register bit position (as per doc) - bit mask = 1 << (31 - bit) */ - u8 prio_mask; /* priority mask value */ -}; - -#endif /* __IPIC_H__ */ diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h new file mode 100644 index 000000000000..0fe396a2b666 --- /dev/null +++ b/include/asm-powerpc/ipic.h @@ -0,0 +1,85 @@ +/* + * include/asm-ppc/ipic.h + * + * IPIC external definitions and structure. + * + * Maintainer: Kumar Gala + * + * Copyright 2005 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifdef __KERNEL__ +#ifndef __ASM_IPIC_H__ +#define __ASM_IPIC_H__ + +#include + +/* Flags when we init the IPIC */ +#define IPIC_SPREADMODE_GRP_A 0x00000001 +#define IPIC_SPREADMODE_GRP_D 0x00000002 +#define IPIC_SPREADMODE_MIX_A 0x00000004 +#define IPIC_SPREADMODE_MIX_B 0x00000008 +#define IPIC_DISABLE_MCP_OUT 0x00000010 +#define IPIC_IRQ0_MCP 0x00000020 + +/* IPIC registers offsets */ +#define IPIC_SICFR 0x00 /* System Global Interrupt Configuration Register */ +#define IPIC_SIVCR 0x04 /* System Global Interrupt Vector Register */ +#define IPIC_SIPNR_H 0x08 /* System Internal Interrupt Pending Register (HIGH) */ +#define IPIC_SIPNR_L 0x0C /* System Internal Interrupt Pending Register (LOW) */ +#define IPIC_SIPRR_A 0x10 /* System Internal Interrupt group A Priority Register */ +#define IPIC_SIPRR_B 0x14 /* System Internal Interrupt group B Priority Register */ +#define IPIC_SIPRR_C 0x18 /* System Internal Interrupt group C Priority Register */ +#define IPIC_SIPRR_D 0x1C /* System Internal Interrupt group D Priority Register */ +#define IPIC_SIMSR_H 0x20 /* System Internal Interrupt Mask Register (HIGH) */ +#define IPIC_SIMSR_L 0x24 /* System Internal Interrupt Mask Register (LOW) */ +#define IPIC_SICNR 0x28 /* System Internal Interrupt Control Register */ +#define IPIC_SEPNR 0x2C /* System External Interrupt Pending Register */ +#define IPIC_SMPRR_A 0x30 /* System Mixed Interrupt group A Priority Register */ +#define IPIC_SMPRR_B 0x34 /* System Mixed Interrupt group B Priority Register */ +#define IPIC_SEMSR 0x38 /* System External Interrupt Mask Register */ +#define IPIC_SECNR 0x3C /* System External Interrupt Control Register */ +#define IPIC_SERSR 0x40 /* System Error Status Register */ +#define IPIC_SERMR 0x44 /* System Error Mask Register */ +#define IPIC_SERCR 0x48 /* System Error Control Register */ +#define IPIC_SIFCR_H 0x50 /* System Internal Interrupt Force Register (HIGH) */ +#define IPIC_SIFCR_L 0x54 /* System Internal Interrupt Force Register (LOW) */ +#define IPIC_SEFCR 0x58 /* System External Interrupt Force Register */ +#define IPIC_SERFR 0x5C /* System Error Force Register */ +#define IPIC_SCVCR 0x60 /* System Critical Interrupt Vector Register */ +#define IPIC_SMVCR 0x64 /* System Management Interrupt Vector Register */ + +enum ipic_prio_grp { + IPIC_INT_GRP_A = IPIC_SIPRR_A, + IPIC_INT_GRP_D = IPIC_SIPRR_D, + IPIC_MIX_GRP_A = IPIC_SMPRR_A, + IPIC_MIX_GRP_B = IPIC_SMPRR_B, +}; + +enum ipic_mcp_irq { + IPIC_MCP_IRQ0 = 0, + IPIC_MCP_WDT = 1, + IPIC_MCP_SBA = 2, + IPIC_MCP_PCI1 = 5, + IPIC_MCP_PCI2 = 6, + IPIC_MCP_MU = 7, +}; + +extern void ipic_init(phys_addr_t phys_addr, unsigned int flags, + unsigned int irq_offset, + unsigned char *senses, unsigned int senses_count); +extern int ipic_set_priority(unsigned int irq, unsigned int priority); +extern void ipic_set_highest_priority(unsigned int irq); +extern void ipic_set_default_priority(void); +extern void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq); +extern void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq); +extern u32 ipic_get_mcp_status(void); +extern void ipic_clear_mcp_status(u32 mask); +extern int ipic_get_irq(struct pt_regs *regs); + +#endif /* __ASM_IPIC_H__ */ +#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/ipic.h b/include/asm-ppc/ipic.h deleted file mode 100644 index 0fe396a2b666..000000000000 --- a/include/asm-ppc/ipic.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * include/asm-ppc/ipic.h - * - * IPIC external definitions and structure. - * - * Maintainer: Kumar Gala - * - * Copyright 2005 Freescale Semiconductor, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#ifdef __KERNEL__ -#ifndef __ASM_IPIC_H__ -#define __ASM_IPIC_H__ - -#include - -/* Flags when we init the IPIC */ -#define IPIC_SPREADMODE_GRP_A 0x00000001 -#define IPIC_SPREADMODE_GRP_D 0x00000002 -#define IPIC_SPREADMODE_MIX_A 0x00000004 -#define IPIC_SPREADMODE_MIX_B 0x00000008 -#define IPIC_DISABLE_MCP_OUT 0x00000010 -#define IPIC_IRQ0_MCP 0x00000020 - -/* IPIC registers offsets */ -#define IPIC_SICFR 0x00 /* System Global Interrupt Configuration Register */ -#define IPIC_SIVCR 0x04 /* System Global Interrupt Vector Register */ -#define IPIC_SIPNR_H 0x08 /* System Internal Interrupt Pending Register (HIGH) */ -#define IPIC_SIPNR_L 0x0C /* System Internal Interrupt Pending Register (LOW) */ -#define IPIC_SIPRR_A 0x10 /* System Internal Interrupt group A Priority Register */ -#define IPIC_SIPRR_B 0x14 /* System Internal Interrupt group B Priority Register */ -#define IPIC_SIPRR_C 0x18 /* System Internal Interrupt group C Priority Register */ -#define IPIC_SIPRR_D 0x1C /* System Internal Interrupt group D Priority Register */ -#define IPIC_SIMSR_H 0x20 /* System Internal Interrupt Mask Register (HIGH) */ -#define IPIC_SIMSR_L 0x24 /* System Internal Interrupt Mask Register (LOW) */ -#define IPIC_SICNR 0x28 /* System Internal Interrupt Control Register */ -#define IPIC_SEPNR 0x2C /* System External Interrupt Pending Register */ -#define IPIC_SMPRR_A 0x30 /* System Mixed Interrupt group A Priority Register */ -#define IPIC_SMPRR_B 0x34 /* System Mixed Interrupt group B Priority Register */ -#define IPIC_SEMSR 0x38 /* System External Interrupt Mask Register */ -#define IPIC_SECNR 0x3C /* System External Interrupt Control Register */ -#define IPIC_SERSR 0x40 /* System Error Status Register */ -#define IPIC_SERMR 0x44 /* System Error Mask Register */ -#define IPIC_SERCR 0x48 /* System Error Control Register */ -#define IPIC_SIFCR_H 0x50 /* System Internal Interrupt Force Register (HIGH) */ -#define IPIC_SIFCR_L 0x54 /* System Internal Interrupt Force Register (LOW) */ -#define IPIC_SEFCR 0x58 /* System External Interrupt Force Register */ -#define IPIC_SERFR 0x5C /* System Error Force Register */ -#define IPIC_SCVCR 0x60 /* System Critical Interrupt Vector Register */ -#define IPIC_SMVCR 0x64 /* System Management Interrupt Vector Register */ - -enum ipic_prio_grp { - IPIC_INT_GRP_A = IPIC_SIPRR_A, - IPIC_INT_GRP_D = IPIC_SIPRR_D, - IPIC_MIX_GRP_A = IPIC_SMPRR_A, - IPIC_MIX_GRP_B = IPIC_SMPRR_B, -}; - -enum ipic_mcp_irq { - IPIC_MCP_IRQ0 = 0, - IPIC_MCP_WDT = 1, - IPIC_MCP_SBA = 2, - IPIC_MCP_PCI1 = 5, - IPIC_MCP_PCI2 = 6, - IPIC_MCP_MU = 7, -}; - -extern void ipic_init(phys_addr_t phys_addr, unsigned int flags, - unsigned int irq_offset, - unsigned char *senses, unsigned int senses_count); -extern int ipic_set_priority(unsigned int irq, unsigned int priority); -extern void ipic_set_highest_priority(unsigned int irq); -extern void ipic_set_default_priority(void); -extern void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq); -extern void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq); -extern u32 ipic_get_mcp_status(void); -extern void ipic_clear_mcp_status(u32 mask); -extern int ipic_get_irq(struct pt_regs *regs); - -#endif /* __ASM_IPIC_H__ */ -#endif /* __KERNEL__ */ -- cgit v1.2.3 From 401d1f029bebb7153ca704997772113dc36d9527 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 15 Nov 2005 18:52:18 +0000 Subject: [PATCH] syscall entry/exit revamp This cleanup patch speeds up the null syscall path on ppc64 by about 3%, and brings the ppc32 and ppc64 code slightly closer together. The ppc64 code was checking current_thread_info()->flags twice in the syscall exit path; once for TIF_SYSCALL_T_OR_A before disabling interrupts, and then again for TIF_SIGPENDING|TIF_NEED_RESCHED etc after disabling interrupts. Now we do the same as ppc32 -- check the flags only once in the fast path, and re-enable interrupts if necessary in the ptrace case. The patch abolishes the 'syscall_noerror' member of struct thread_info and replaces it with a TIF_NOERROR bit in the flags, which is handled in the slow path. This shortens the syscall entry code, which no longer needs to clear syscall_noerror. The patch adds a TIF_SAVE_NVGPRS flag which causes the syscall exit slow path to save the non-volatile GPRs into a signal frame. This removes the need for the assembly wrappers around sys_sigsuspend(), sys_rt_sigsuspend(), et al which existed solely to save those registers in advance. It also means I don't have to add new wrappers for ppoll() and pselect(), which is what I was supposed to be doing when I got distracted into this... Finally, it unifies the ppc64 and ppc32 methods of handling syscall exit directly into a signal handler (as required by sigsuspend et al) by introducing a TIF_RESTOREALL flag which causes _all_ the registers to be reloaded from the pt_regs by taking the ret_from_exception path, instead of the normal syscall exit path which stomps on the callee-saved GPRs. It appears to pass an LTP test run on ppc64, and passes basic testing on ppc32 too. Brief tests of ptrace functionality with strace and gdb also appear OK. I wouldn't send it to Linus for 2.6.15 just yet though :) Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 4 +- arch/powerpc/kernel/entry_32.S | 167 ++++++++++++++++------------- arch/powerpc/kernel/entry_64.S | 214 ++++++++++++++++++++------------------ arch/powerpc/kernel/signal_32.c | 59 ++++------- arch/powerpc/kernel/signal_64.c | 23 +++- arch/powerpc/kernel/systbl.S | 10 +- include/asm-powerpc/ptrace.h | 2 +- include/asm-powerpc/thread_info.h | 12 ++- 8 files changed, 269 insertions(+), 222 deletions(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 91538d2445bf..3bf89d1a2de6 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -92,9 +92,9 @@ int main(void) DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); -#ifdef CONFIG_PPC32 + DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame)); DEFINE(TI_TASK, offsetof(struct thread_info, task)); +#ifdef CONFIG_PPC32 DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); #endif /* CONFIG_PPC32 */ diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 2e99ae41723c..8fed9538f188 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -200,8 +200,6 @@ _GLOBAL(DoSyscall) bl do_show_syscall #endif /* SHOW_SYSCALLS */ rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ - li r11,0 - stb r11,TI_SC_NOERR(r10) lwz r11,TI_FLAGS(r10) andi. r11,r11,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace @@ -222,25 +220,21 @@ ret_from_syscall: bl do_show_syscall_exit #endif mr r6,r3 - li r11,-_LAST_ERRNO - cmplw 0,r3,r11 rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ - blt+ 30f - lbz r11,TI_SC_NOERR(r12) - cmpwi r11,0 - bne 30f - neg r3,r3 - lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) - /* disable interrupts so current_thread_info()->flags can't change */ -30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ + LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ SYNC MTMSRD(r10) lwz r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + li r8,-_LAST_ERRNO + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) bne- syscall_exit_work + cmplw 0,r3,r8 + blt+ syscall_exit_cont + lwz r11,_CCR(r1) /* Load CR */ + neg r3,r3 + oris r11,r11,0x1000 /* Set SO bit in CR */ + stw r11,_CCR(r1) syscall_exit_cont: #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) /* If the process has its own DBCR0 value, load it up. The single @@ -292,46 +286,113 @@ syscall_dotrace: b syscall_dotrace_cont syscall_exit_work: - stw r6,RESULT(r1) /* Save result */ + andi. r0,r9,_TIF_RESTOREALL + bne- 2f + cmplw 0,r3,r8 + blt+ 1f + andi. r0,r9,_TIF_NOERROR + bne- 1f + lwz r11,_CCR(r1) /* Load CR */ + neg r3,r3 + oris r11,r11,0x1000 /* Set SO bit in CR */ + stw r11,_CCR(r1) + +1: stw r6,RESULT(r1) /* Save result */ stw r3,GPR3(r1) /* Update return value */ - andi. r0,r9,_TIF_SYSCALL_T_OR_A - beq 5f - ori r10,r10,MSR_EE - SYNC - MTMSRD(r10) /* re-enable interrupts */ +2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) + beq 4f + + /* Clear per-syscall TIF flags if any are set, but _leave_ + _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that + yet. */ + + li r11,_TIF_PERSYSCALL_MASK + addi r12,r12,TI_FLAGS +3: lwarx r8,0,r12 + andc r8,r8,r11 +#ifdef CONFIG_IBM405_ERR77 + dcbt 0,r12 +#endif + stwcx. r8,0,r12 + bne- 3b + subi r12,r12,TI_FLAGS + +4: /* Anything which requires enabling interrupts? */ + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) + beq 7f + + /* Save NVGPRS if they're not saved already */ lwz r4,_TRAP(r1) andi. r4,r4,1 - beq 4f + beq 5f SAVE_NVGPRS(r1) li r4,0xc00 stw r4,_TRAP(r1) -4: + + /* Re-enable interrupts */ +5: ori r10,r10,MSR_EE + SYNC + MTMSRD(r10) + + andi. r0,r9,_TIF_SAVE_NVGPRS + bne save_user_nvgprs + +save_user_nvgprs_cont: + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + beq 7f + addi r3,r1,STACK_FRAME_OVERHEAD bl do_syscall_trace_leave REST_NVGPRS(r1) -2: - lwz r3,GPR3(r1) + +6: lwz r3,GPR3(r1) LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ SYNC MTMSRD(r10) /* disable interrupts again */ rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ lwz r9,TI_FLAGS(r12) -5: +7: andi. r0,r9,_TIF_NEED_RESCHED - bne 1f + bne 8f lwz r5,_MSR(r1) andi. r5,r5,MSR_PR - beq syscall_exit_cont + beq ret_from_except andi. r0,r9,_TIF_SIGPENDING - beq syscall_exit_cont + beq ret_from_except b do_user_signal -1: +8: ori r10,r10,MSR_EE SYNC MTMSRD(r10) /* re-enable interrupts */ bl schedule - b 2b + b 6b + +save_user_nvgprs: + ld r8,TI_SIGFRAME(r12) + +.macro savewords start, end + 1: stw \start,4*(\start)(r8) + .section __ex_table,"a" + .align 2 + .long 1b,save_user_nvgprs_fault + .previous + .if \end - \start + savewords "(\start+1)",\end + .endif +.endm + savewords 14,31 + b save_user_nvgprs_cont + + +save_user_nvgprs_fault: + li r3,11 /* SIGSEGV */ + ld r4,TI_TASK(r12) + bl force_sigsegv + rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ + ld r9,TI_FLAGS(r12) + b save_user_nvgprs_cont + #ifdef SHOW_SYSCALLS do_show_syscall: #ifdef SHOW_SYSCALLS_TASK @@ -401,28 +462,10 @@ show_syscalls_task: #endif /* SHOW_SYSCALLS */ /* - * The sigsuspend and rt_sigsuspend system calls can call do_signal - * and thus put the process into the stopped state where we might - * want to examine its user state with ptrace. Therefore we need - * to save all the nonvolatile registers (r13 - r31) before calling - * the C code. + * The fork/clone functions need to copy the full register set into + * the child process. Therefore we need to save all the nonvolatile + * registers (r13 - r31) before calling the C code. */ - .globl ppc_sigsuspend -ppc_sigsuspend: - SAVE_NVGPRS(r1) - lwz r0,_TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,_TRAP(r1) /* register set saved */ - b sys_sigsuspend - - .globl ppc_rt_sigsuspend -ppc_rt_sigsuspend: - SAVE_NVGPRS(r1) - lwz r0,_TRAP(r1) - rlwinm r0,r0,0,0,30 - stw r0,_TRAP(r1) - b sys_rt_sigsuspend - .globl ppc_fork ppc_fork: SAVE_NVGPRS(r1) @@ -447,14 +490,6 @@ ppc_clone: stw r0,_TRAP(r1) /* register set saved */ b sys_clone - .globl ppc_swapcontext -ppc_swapcontext: - SAVE_NVGPRS(r1) - lwz r0,_TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,_TRAP(r1) /* register set saved */ - b sys_swapcontext - /* * Top-level page fault handling. * This is in assembler because if do_page_fault tells us that @@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) .long ret_from_except #endif - .globl sigreturn_exit -sigreturn_exit: - subi r1,r3,STACK_FRAME_OVERHEAD - rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ - lwz r9,TI_FLAGS(r12) - andi. r0,r9,_TIF_SYSCALL_T_OR_A - beq+ ret_from_except_full - bl do_syscall_trace_leave - /* fall through */ - .globl ret_from_except_full ret_from_except_full: REST_NVGPRS(r1) @@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ /* Check current_thread_info()->flags */ rlwinm r9,r1,0,0,(31-THREAD_SHIFT) lwz r9,TI_FLAGS(r9) - andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED) + andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) bne do_work restore_user: diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bce33a38399f..0bff31f166dd 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -113,9 +113,7 @@ system_call_common: addi r9,r1,STACK_FRAME_OVERHEAD #endif clrrdi r11,r1,THREAD_SHIFT - li r12,0 ld r10,TI_FLAGS(r11) - stb r12,TI_SC_NOERR(r11) andi. r11,r10,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace syscall_dotrace_cont: @@ -144,24 +142,12 @@ system_call: /* label this so stack traces look sane */ bctrl /* Call handler */ syscall_exit: + std r3,RESULT(r1) #ifdef SHOW_SYSCALLS - std r3,GPR3(r1) bl .do_show_syscall_exit - ld r3,GPR3(r1) + ld r3,RESULT(r1) #endif - std r3,RESULT(r1) - ld r5,_CCR(r1) - li r10,-_LAST_ERRNO - cmpld r3,r10 clrrdi r12,r1,THREAD_SHIFT - bge- syscall_error -syscall_error_cont: - - /* check for syscall tracing or audit */ - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - bne- syscall_exit_trace -syscall_exit_trace_cont: /* disable interrupts so current_thread_info()->flags can't change, and so that we don't get interrupted after loading SRR0/1. */ @@ -173,8 +159,13 @@ syscall_exit_trace_cont: rotldi r10,r10,16 mtmsrd r10,1 ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + li r11,-_LAST_ERRNO + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR) bne- syscall_exit_work + cmpld r3,r11 + ld r5,_CCR(r1) + bge- syscall_error +syscall_error_cont: ld r7,_NIP(r1) stdcx. r0,0,r1 /* to clear the reservation */ andi. r6,r8,MSR_PR @@ -193,21 +184,12 @@ syscall_exit_trace_cont: rfid b . /* prevent speculative execution */ -syscall_enosys: - li r3,-ENOSYS - std r3,RESULT(r1) - clrrdi r12,r1,THREAD_SHIFT - ld r5,_CCR(r1) - -syscall_error: - lbz r11,TI_SC_NOERR(r12) - cmpwi 0,r11,0 - bne- syscall_error_cont - neg r3,r3 +syscall_error: oris r5,r5,0x1000 /* Set SO bit in CR */ + neg r3,r3 std r5,_CCR(r1) b syscall_error_cont - + /* Traced system call support */ syscall_dotrace: bl .save_nvgprs @@ -225,21 +207,69 @@ syscall_dotrace: ld r10,TI_FLAGS(r10) b syscall_dotrace_cont -syscall_exit_trace: - std r3,GPR3(r1) - bl .save_nvgprs +syscall_enosys: + li r3,-ENOSYS + b syscall_exit + +syscall_exit_work: + /* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr. + If TIF_NOERROR is set, just save r3 as it is. */ + + andi. r0,r9,_TIF_RESTOREALL + bne- 2f + cmpld r3,r11 /* r10 is -LAST_ERRNO */ + blt+ 1f + andi. r0,r9,_TIF_NOERROR + bne- 1f + ld r5,_CCR(r1) + neg r3,r3 + oris r5,r5,0x1000 /* Set SO bit in CR */ + std r5,_CCR(r1) +1: std r3,GPR3(r1) +2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) + beq 4f + + /* Clear per-syscall TIF flags if any are set, but _leave_ + _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that + yet. */ + + li r11,_TIF_PERSYSCALL_MASK + addi r12,r12,TI_FLAGS +3: ldarx r10,0,r12 + andc r10,r10,r11 + stdcx. r10,0,r12 + bne- 3b + subi r12,r12,TI_FLAGS + +4: bl save_nvgprs + /* Anything else left to do? */ + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) + beq .ret_from_except_lite + + /* Re-enable interrupts */ + mfmsr r10 + ori r10,r10,MSR_EE + mtmsrd r10,1 + + andi. r0,r9,_TIF_SAVE_NVGPRS + bne save_user_nvgprs + + /* If tracing, re-enable interrupts and do it */ +save_user_nvgprs_cont: + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + beq 5f + addi r3,r1,STACK_FRAME_OVERHEAD bl .do_syscall_trace_leave REST_NVGPRS(r1) - ld r3,GPR3(r1) - ld r5,_CCR(r1) clrrdi r12,r1,THREAD_SHIFT - b syscall_exit_trace_cont -/* Stuff to do on exit from a system call. */ -syscall_exit_work: - std r3,GPR3(r1) - std r5,_CCR(r1) + /* Disable interrupts again and handle other work if any */ +5: mfmsr r10 + rldicl r10,r10,48,1 + rotldi r10,r10,16 + mtmsrd r10,1 + b .ret_from_except_lite /* Save non-volatile GPRs, if not already saved. */ @@ -252,6 +282,52 @@ _GLOBAL(save_nvgprs) std r0,_TRAP(r1) blr + +save_user_nvgprs: + ld r10,TI_SIGFRAME(r12) + andi. r0,r9,_TIF_32BIT + beq- save_user_nvgprs_64 + + /* 32-bit save to userspace */ + +.macro savewords start, end + 1: stw \start,4*(\start)(r10) + .section __ex_table,"a" + .align 3 + .llong 1b,save_user_nvgprs_fault + .previous + .if \end - \start + savewords "(\start+1)",\end + .endif +.endm + savewords 14,31 + b save_user_nvgprs_cont + +save_user_nvgprs_64: + /* 64-bit save to userspace */ + +.macro savelongs start, end + 1: std \start,8*(\start)(r10) + .section __ex_table,"a" + .align 3 + .llong 1b,save_user_nvgprs_fault + .previous + .if \end - \start + savelongs "(\start+1)",\end + .endif +.endm + savelongs 14,31 + b save_user_nvgprs_cont + +save_user_nvgprs_fault: + li r3,11 /* SIGSEGV */ + ld r4,TI_TASK(r12) + bl .force_sigsegv + + clrrdi r12,r1,THREAD_SHIFT + ld r9,TI_FLAGS(r12) + b save_user_nvgprs_cont + /* * The sigsuspend and rt_sigsuspend system calls can call do_signal * and thus put the process into the stopped state where we might @@ -260,35 +336,6 @@ _GLOBAL(save_nvgprs) * the C code. Similarly, fork, vfork and clone need the full * register state on the stack so that it can be copied to the child. */ -_GLOBAL(ppc32_sigsuspend) - bl .save_nvgprs - bl .compat_sys_sigsuspend - b 70f - -_GLOBAL(ppc64_rt_sigsuspend) - bl .save_nvgprs - bl .sys_rt_sigsuspend - b 70f - -_GLOBAL(ppc32_rt_sigsuspend) - bl .save_nvgprs - bl .compat_sys_rt_sigsuspend -70: cmpdi 0,r3,0 - /* If it returned an error, we need to return via syscall_exit to set - the SO bit in cr0 and potentially stop for ptrace. */ - bne syscall_exit - /* If sigsuspend() returns zero, we are going into a signal handler. We - may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ -#ifdef CONFIG_AUDITSYSCALL - ld r3,PACACURRENT(r13) - ld r4,AUDITCONTEXT(r3) - cmpdi 0,r4,0 - beq .ret_from_except /* No audit_context: Leave immediately. */ - li r4, 2 /* AUDITSC_FAILURE */ - li r5,-4 /* It's always -EINTR */ - bl .audit_syscall_exit -#endif - b .ret_from_except _GLOBAL(ppc_fork) bl .save_nvgprs @@ -305,37 +352,6 @@ _GLOBAL(ppc_clone) bl .sys_clone b syscall_exit -_GLOBAL(ppc32_swapcontext) - bl .save_nvgprs - bl .compat_sys_swapcontext - b 80f - -_GLOBAL(ppc64_swapcontext) - bl .save_nvgprs - bl .sys_swapcontext - b 80f - -_GLOBAL(ppc32_sigreturn) - bl .compat_sys_sigreturn - b 80f - -_GLOBAL(ppc32_rt_sigreturn) - bl .compat_sys_rt_sigreturn - b 80f - -_GLOBAL(ppc64_rt_sigreturn) - bl .sys_rt_sigreturn - -80: cmpdi 0,r3,0 - blt syscall_exit - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq+ 81f - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave -81: b .ret_from_except - _GLOBAL(ret_from_fork) bl .schedule_tail REST_NVGPRS(r1) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 5a2eba60dd39..c9d02751127f 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -76,7 +76,6 @@ * registers from *regs. This is what we need * to do when a signal has been delivered. */ -#define sigreturn_exit(regs) return 0 #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) #undef __SIGNAL_FRAMESIZE @@ -156,9 +155,17 @@ static inline int save_general_regs(struct pt_regs *regs, elf_greg_t64 *gregs = (elf_greg_t64 *)regs; int i; - for (i = 0; i <= PT_RESULT; i ++) + if (!FULL_REGS(regs)) { + set_thread_flag(TIF_SAVE_NVGPRS); + current_thread_info()->nvgprs_frame = frame->mc_gregs; + } + + for (i = 0; i <= PT_RESULT; i ++) { + if (i == 14 && !FULL_REGS(regs)) + i = 32; if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) return -EFAULT; + } return 0; } @@ -179,8 +186,6 @@ static inline int restore_general_regs(struct pt_regs *regs, #else /* CONFIG_PPC64 */ -extern void sigreturn_exit(struct pt_regs *); - #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) @@ -256,8 +261,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); + return 0; + } } } @@ -292,8 +299,10 @@ long sys_rt_sigsuspend( while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); + return 0; + } } } @@ -391,9 +400,6 @@ struct rt_sigframe { static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, int sigret) { -#ifdef CONFIG_PPC32 - CHECK_FULL_REGS(regs); -#endif /* Make sure floating point registers are stored in regs */ flush_fp_to_thread(current); @@ -828,12 +834,6 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, regs->gpr[6] = (unsigned long) rt_sf; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; -#ifdef CONFIG_PPC64 - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); -#endif return 1; badframe: @@ -911,8 +911,8 @@ long sys_swapcontext(struct ucontext __user *old_ctx, */ if (do_setcontext(new_ctx, regs, 0)) do_exit(SIGSEGV); - sigreturn_exit(regs); - /* doesn't actually return back to here */ + + set_thread_flag(TIF_RESTOREALL); return 0; } @@ -945,12 +945,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, * nobody does any... */ compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); - return (int)regs->result; #else do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); - sigreturn_exit(regs); /* doesn't return here */ - return 0; #endif + set_thread_flag(TIF_RESTOREALL); + return 0; bad: force_sig(SIGSEGV, current); @@ -1041,9 +1040,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx, */ do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); - sigreturn_exit(regs); - /* doesn't actually return back to here */ - + set_thread_flag(TIF_RESTOREALL); out: return 0; } @@ -1107,12 +1104,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, regs->gpr[4] = (unsigned long) sc; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; -#ifdef CONFIG_PPC64 - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); -#endif return 1; @@ -1160,12 +1151,8 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, || restore_user_regs(regs, sr, 1)) goto badframe; -#ifdef CONFIG_PPC64 - return (int)regs->result; -#else - sigreturn_exit(regs); /* doesn't return */ + set_thread_flag(TIF_RESTOREALL); return 0; -#endif badframe: force_sig(SIGSEGV, current); diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 1decf2785530..5462bef898f6 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -96,8 +96,10 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); return 0; + } } } @@ -152,6 +154,14 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, err |= __put_user(0, &sc->v_regs); #endif /* CONFIG_ALTIVEC */ err |= __put_user(&sc->gp_regs, &sc->regs); + if (!FULL_REGS(regs)) { + /* Zero out the unsaved GPRs to avoid information + leak, and set TIF_SAVE_NVGPRS to ensure that the + registers do actually get saved later. */ + memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); + set_thread_flag(TIF_SAVE_NVGPRS); + current_thread_info()->nvgprs_frame = &sc->gp_regs; + } err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); err |= __put_user(signr, &sc->signal); @@ -340,6 +350,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx, do_exit(SIGSEGV); /* This returns like rt_sigreturn */ + set_thread_flag(TIF_RESTOREALL); return 0; } @@ -372,7 +383,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, */ do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); - return regs->result; + set_thread_flag(TIF_RESTOREALL); + return 0; badframe: #if DEBUG_SIG @@ -454,9 +466,6 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, if (err) goto badframe; - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - return 1; badframe: @@ -502,6 +511,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) * we only get here if there is a handler, we dont restart. */ regs->result = -EINTR; + regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; break; case -ERESTARTSYS: /* ERESTARTSYS means to restart the syscall if there is no @@ -509,6 +520,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) */ if (!(ka->sa.sa_flags & SA_RESTART)) { regs->result = -EINTR; + regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; break; } /* fallthrough */ diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 65eaea91b499..4bb3650420b4 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -113,7 +113,7 @@ SYSCALL(sgetmask) COMPAT_SYS(ssetmask) SYSCALL(setreuid) SYSCALL(setregid) -SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) +SYS32ONLY(sigsuspend) COMPAT_SYS(sigpending) COMPAT_SYS(sethostname) COMPAT_SYS(setrlimit) @@ -160,7 +160,7 @@ SYSCALL(swapoff) COMPAT_SYS(sysinfo) COMPAT_SYS(ipc) SYSCALL(fsync) -SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) +SYS32ONLY(sigreturn) PPC_SYS(clone) COMPAT_SYS(setdomainname) PPC_SYS(newuname) @@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl) SYSCALL(setresgid) SYSCALL(getresgid) COMPAT_SYS(prctl) -SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) +COMPAT_SYS(rt_sigreturn) COMPAT_SYS(rt_sigaction) COMPAT_SYS(rt_sigprocmask) COMPAT_SYS(rt_sigpending) COMPAT_SYS(rt_sigtimedwait) COMPAT_SYS(rt_sigqueueinfo) -SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) +COMPAT_SYS(rt_sigsuspend) COMPAT_SYS(pread64) COMPAT_SYS(pwrite64) SYSCALL(chown) @@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime) COMPAT_SYS(clock_gettime) COMPAT_SYS(clock_getres) COMPAT_SYS(clock_nanosleep) -SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) +COMPAT_SYS(swapcontext) COMPAT_SYS(tgkill) COMPAT_SYS(utimes) COMPAT_SYS(statfs64) diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h index 1f7ecdb0b6ce..9c550b314823 100644 --- a/include/asm-powerpc/ptrace.h +++ b/include/asm-powerpc/ptrace.h @@ -87,7 +87,7 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define force_successful_syscall_return() \ do { \ - current_thread_info()->syscall_noerror = 1; \ + set_thread_flag(TIF_NOERROR); \ } while(0) /* diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h index e525f49bd179..ac1e80e6033e 100644 --- a/include/asm-powerpc/thread_info.h +++ b/include/asm-powerpc/thread_info.h @@ -37,8 +37,7 @@ struct thread_info { int preempt_count; /* 0 => preemptable, <0 => BUG */ struct restart_block restart_block; - /* set by force_successful_syscall_return */ - unsigned char syscall_noerror; + void *nvgprs_frame; /* low level flags - has atomic operations done on it */ unsigned long flags ____cacheline_aligned_in_smp; }; @@ -123,6 +122,9 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SINGLESTEP 9 /* singlestepping active */ #define TIF_MEMDIE 10 #define TIF_SECCOMP 11 /* secure computing */ +#define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */ +#define TIF_SAVE_NVGPRS 13 /* Save r14-r31 in signal frame */ +#define TIF_NOERROR 14 /* Force successful syscall return */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1< Date: Wed, 16 Nov 2005 08:56:43 +0100 Subject: [PATCH] powerpc: IBMEBUS bus support This patch adds the necessary core bus support used by device drivers that sit on the IBM GX bus on modern pSeries machines like the Galaxy infiniband for example. It provide transparent DMA ops (the low level driver works with virtual addresses directly) along with a simple bus layer using the Open Firmware matching routines. Signed-off-by: Heiko J Schick Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 7 + arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/dma_64.c | 9 + arch/powerpc/kernel/ibmebus.c | 396 ++++++++++++++++++++++++++++++++++++++++++ include/asm-powerpc/ibmebus.h | 83 +++++++++ 5 files changed, 496 insertions(+) create mode 100644 arch/powerpc/kernel/ibmebus.c create mode 100644 include/asm-powerpc/ibmebus.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index db93dbc0e21a..4d71aa3ecbb5 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -384,6 +384,13 @@ config IBMVIO bool default y +config IBMEBUS + depends on PPC_PSERIES + bool "Support for GX bus based adapters" + default y + help + Bus device driver for GX bus based adapters. + config PPC_MPC106 bool default n diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index e7776a438a84..78f7b90c98f8 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_RTAS_PROC) += rtas-proc.o obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_IBMVIO) += vio.o +obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o obj-$(CONFIG_PPC_MAPLE) += udbg_16550.o diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 7c3419656ccc..36aaa7663f02 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c @@ -10,6 +10,7 @@ /* Include the busses we support */ #include #include +#include #include #include @@ -22,6 +23,10 @@ static struct dma_mapping_ops *get_dma_ops(struct device *dev) #ifdef CONFIG_IBMVIO if (dev->bus == &vio_bus_type) return &vio_dma_ops; +#endif +#ifdef CONFIG_IBMEBUS + if (dev->bus == &ibmebus_bus_type) + return &ibmebus_dma_ops; #endif return NULL; } @@ -47,6 +52,10 @@ int dma_set_mask(struct device *dev, u64 dma_mask) if (dev->bus == &vio_bus_type) return -EIO; #endif /* CONFIG_IBMVIO */ +#ifdef CONFIG_IBMEBUS + if (dev->bus == &ibmebus_bus_type) + return -EIO; +#endif BUG(); return 0; } diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c new file mode 100644 index 000000000000..e47d40ac6f39 --- /dev/null +++ b/arch/powerpc/kernel/ibmebus.c @@ -0,0 +1,396 @@ +/* + * IBM PowerPC IBM eBus Infrastructure Support. + * + * Copyright (c) 2005 IBM Corporation + * Heiko J Schick + * + * All rights reserved. + * + * This source code is distributed under a dual license of GPL v2.0 and OpenIB + * BSD. + * + * OpenIB BSD License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */ + .name = ibmebus_bus_device.ofdev.dev.bus_id, + .ofdev.dev.bus_id = "ibmebus", + .ofdev.dev.bus = &ibmebus_bus_type, +}; + +static void *ibmebus_alloc_coherent(struct device *dev, + size_t size, + dma_addr_t *dma_handle, + gfp_t flag) +{ + void *mem; + + mem = kmalloc(size, flag); + *dma_handle = (dma_addr_t)mem; + + return mem; +} + +static void ibmebus_free_coherent(struct device *dev, + size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + kfree(vaddr); +} + +static dma_addr_t ibmebus_map_single(struct device *dev, + void *ptr, + size_t size, + enum dma_data_direction direction) +{ + return (dma_addr_t)(ptr); +} + +static void ibmebus_unmap_single(struct device *dev, + dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction) +{ + return; +} + +static int ibmebus_map_sg(struct device *dev, + struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + int i; + + for (i = 0; i < nents; i++) { + sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) + + sg[i].offset; + sg[i].dma_length = sg[i].length; + } + + return nents; +} + +static void ibmebus_unmap_sg(struct device *dev, + struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + return; +} + +static int ibmebus_dma_supported(struct device *dev, u64 mask) +{ + return 1; +} + +struct dma_mapping_ops ibmebus_dma_ops = { + .alloc_coherent = ibmebus_alloc_coherent, + .free_coherent = ibmebus_free_coherent, + .map_single = ibmebus_map_single, + .unmap_single = ibmebus_unmap_single, + .map_sg = ibmebus_map_sg, + .unmap_sg = ibmebus_unmap_sg, + .dma_supported = ibmebus_dma_supported, +}; + +static int ibmebus_bus_probe(struct device *dev) +{ + struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); + struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); + const struct of_device_id *id; + int error = -ENODEV; + + if (!ibmebusdrv->probe) + return error; + + id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev); + if (id) { + error = ibmebusdrv->probe(ibmebusdev, id); + } + + return error; +} + +static int ibmebus_bus_remove(struct device *dev) +{ + struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); + struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); + + if (ibmebusdrv->remove) { + return ibmebusdrv->remove(ibmebusdev); + } + + return 0; +} + +static void __devinit ibmebus_dev_release(struct device *dev) +{ + of_node_put(to_ibmebus_dev(dev)->ofdev.node); + kfree(to_ibmebus_dev(dev)); +} + +static ssize_t ibmebusdev_show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name); +} +static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, + NULL); + +static struct ibmebus_dev* __devinit ibmebus_register_device_common( + struct ibmebus_dev *dev, char *name) +{ + int err = 0; + + dev->name = name; + dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev; + dev->ofdev.dev.bus = &ibmebus_bus_type; + dev->ofdev.dev.release = ibmebus_dev_release; + + /* An ibmebusdev is based on a of_device. We have to change the + * bus type to use our own DMA mapping operations. + */ + if ((err = of_device_register(&dev->ofdev)) != 0) { + printk(KERN_ERR "%s: failed to register device (%d).\n", + __FUNCTION__, err); + return NULL; + } + + device_create_file(&dev->ofdev.dev, &dev_attr_name); + + return dev; +} + +static struct ibmebus_dev* __devinit ibmebus_register_device_node( + struct device_node *dn) +{ + struct ibmebus_dev *dev; + char *loc_code; + int length; + + loc_code = (char *)get_property(dn, "ibm,loc-code", NULL); + if (!loc_code) { + printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n", + __FUNCTION__, dn->name ? dn->name : ""); + return NULL; + } + + if (strlen(loc_code) == 0) { + printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n", + __FUNCTION__); + return NULL; + } + + dev = kmalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); + if (!dev) { + return NULL; + } + memset(dev, 0, sizeof(struct ibmebus_dev)); + + dev->ofdev.node = of_node_get(dn); + + length = strlen(loc_code); + memcpy(dev->ofdev.dev.bus_id, loc_code + + (length - min(length, BUS_ID_SIZE - 1)), + min(length, BUS_ID_SIZE - 1)); + + /* Register with generic device framework. */ + if (ibmebus_register_device_common(dev, dn->name) == NULL) { + kfree(dev); + return NULL; + } + + return dev; +} + +static void ibmebus_probe_of_nodes(char* name) +{ + struct device_node *dn = NULL; + + while ((dn = of_find_node_by_name(dn, name))) { + if (ibmebus_register_device_node(dn) == NULL) { + of_node_put(dn); + + return; + } + } + + of_node_put(dn); + + return; +} + +static void ibmebus_add_devices_by_id(struct of_device_id *idt) +{ + while (strlen(idt->name) > 0) { + ibmebus_probe_of_nodes(idt->name); + idt++; + } + + return; +} + +static int ibmebus_match_helper(struct device *dev, void *data) +{ + if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0) + return 1; + + return 0; +} + +static int ibmebus_unregister_device(struct device *dev) +{ + device_remove_file(dev, &dev_attr_name); + of_device_unregister(to_of_device(dev)); + + return 0; +} + +static void ibmebus_remove_devices_by_id(struct of_device_id *idt) +{ + struct device *dev; + + while (strlen(idt->name) > 0) { + while ((dev = bus_find_device(&ibmebus_bus_type, NULL, + (void*)idt->name, + ibmebus_match_helper))) { + ibmebus_unregister_device(dev); + } + idt++; + + } + + return; +} + +int ibmebus_register_driver(struct ibmebus_driver *drv) +{ + int err = 0; + + drv->driver.name = drv->name; + drv->driver.bus = &ibmebus_bus_type; + drv->driver.probe = ibmebus_bus_probe; + drv->driver.remove = ibmebus_bus_remove; + + if ((err = driver_register(&drv->driver) != 0)) + return err; + + ibmebus_add_devices_by_id(drv->id_table); + + return 0; +} +EXPORT_SYMBOL(ibmebus_register_driver); + +void ibmebus_unregister_driver(struct ibmebus_driver *drv) +{ + driver_unregister(&drv->driver); + ibmebus_remove_devices_by_id(drv->id_table); +} +EXPORT_SYMBOL(ibmebus_unregister_driver); + +int ibmebus_request_irq(struct ibmebus_dev *dev, + u32 ist, + irqreturn_t (*handler)(int, void*, struct pt_regs *), + unsigned long irq_flags, const char * devname, + void *dev_id) +{ + unsigned int irq = virt_irq_create_mapping(ist); + + if (irq == NO_IRQ) + return -EINVAL; + + irq = irq_offset_up(irq); + + return request_irq(irq, handler, + irq_flags, devname, dev_id); +} +EXPORT_SYMBOL(ibmebus_request_irq); + +void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) +{ + unsigned int irq = virt_irq_create_mapping(ist); + + irq = irq_offset_up(irq); + free_irq(irq, dev_id); + + return; +} +EXPORT_SYMBOL(ibmebus_free_irq); + +static int ibmebus_bus_match(struct device *dev, struct device_driver *drv) +{ + const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); + struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv); + const struct of_device_id *ids = ebus_drv->id_table; + const struct of_device_id *found_id; + + if (!ids) + return 0; + + found_id = of_match_device(ids, &ebus_dev->ofdev); + if (found_id) + return 1; + + return 0; +} + +struct bus_type ibmebus_bus_type = { + .name = "ibmebus", + .match = ibmebus_bus_match, +}; +EXPORT_SYMBOL(ibmebus_bus_type); + +static int __init ibmebus_bus_init(void) +{ + int err; + + printk(KERN_INFO "IBM eBus Device Driver\n"); + + err = bus_register(&ibmebus_bus_type); + if (err) { + printk(KERN_ERR ":%s: failed to register IBM eBus.\n", + __FUNCTION__); + return err; + } + + err = device_register(&ibmebus_bus_device.ofdev.dev); + if (err) { + printk(KERN_WARNING "%s: device_register returned %i\n", + __FUNCTION__, err); + bus_unregister(&ibmebus_bus_type); + + return err; + } + + return 0; +} +__initcall(ibmebus_bus_init); diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h new file mode 100644 index 000000000000..55982b8e5b98 --- /dev/null +++ b/include/asm-powerpc/ibmebus.h @@ -0,0 +1,83 @@ +/* + * IBM PowerPC eBus Infrastructure Support. + * + * Copyright (c) 2005 IBM Corporation + * Heiko J Schick + * + * All rights reserved. + * + * This source code is distributed under a dual license of GPL v2.0 and OpenIB + * BSD. + * + * OpenIB BSD License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_EBUS_H +#define _ASM_EBUS_H + +#include +#include +#include +#include + +extern struct dma_mapping_ops ibmebus_dma_ops; +extern struct bus_type ibmebus_bus_type; + +struct ibmebus_dev { + char *name; + struct of_device ofdev; +}; + +struct ibmebus_driver { + char *name; + struct of_device_id *id_table; + int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id); + int (*remove) (struct ibmebus_dev *dev); + struct device_driver driver; +}; + +int ibmebus_register_driver(struct ibmebus_driver *drv); +void ibmebus_unregister_driver(struct ibmebus_driver *drv); + +int ibmebus_request_irq(struct ibmebus_dev *dev, + u32 ist, + irqreturn_t (*handler)(int, void*, struct pt_regs *), + unsigned long irq_flags, const char * devname, + void *dev_id); +void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id); + +static inline struct ibmebus_driver *to_ibmebus_driver(struct device_driver *drv) +{ + return container_of(drv, struct ibmebus_driver, driver); +} + +static inline struct ibmebus_dev *to_ibmebus_dev(struct device *dev) +{ + return container_of(dev, struct ibmebus_dev, ofdev.dev); +} + + +#endif /* _ASM_IBMEBUS_H */ -- cgit v1.2.3 From 67207b9664a8d603138ef1556141e6d0a102bea7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 15 Nov 2005 15:53:48 -0500 Subject: [PATCH] spufs: The SPU file system, base This is the current version of the spu file system, used for driving SPEs on the Cell Broadband Engine. This release is almost identical to the version for the 2.6.14 kernel posted earlier, which is available as part of the Cell BE Linux distribution from http://www.bsc.es/projects/deepcomputing/linuxoncell/. The first patch provides all the interfaces for running spu application, but does not have any support for debugging SPU tasks or for scheduling. Both these functionalities are added in the subsequent patches. See Documentation/filesystems/spufs.txt on how to use spufs. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- Documentation/filesystems/spufs.txt | 521 +++++++++++++++++++ arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/systbl.S | 2 + arch/powerpc/mm/hash_utils_64.c | 1 + arch/powerpc/platforms/cell/Kconfig | 13 + arch/powerpc/platforms/cell/Makefile | 3 + arch/powerpc/platforms/cell/spu_base.c | 740 +++++++++++++++++++++++++++ arch/powerpc/platforms/cell/spu_syscalls.c | 86 ++++ arch/powerpc/platforms/cell/spufs/Makefile | 3 + arch/powerpc/platforms/cell/spufs/context.c | 67 +++ arch/powerpc/platforms/cell/spufs/file.c | 596 +++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/inode.c | 470 +++++++++++++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 71 +++ arch/powerpc/platforms/cell/spufs/syscalls.c | 106 ++++ arch/ppc/kernel/ppc_ksyms.c | 1 - include/asm-powerpc/spu.h | 498 ++++++++++++++++++ include/asm-powerpc/unistd.h | 2 + include/linux/syscalls.h | 5 + kernel/sys_ni.c | 2 + mm/memory.c | 2 + 20 files changed, 3189 insertions(+), 1 deletion(-) create mode 100644 Documentation/filesystems/spufs.txt create mode 100644 arch/powerpc/platforms/cell/Kconfig create mode 100644 arch/powerpc/platforms/cell/spu_base.c create mode 100644 arch/powerpc/platforms/cell/spu_syscalls.c create mode 100644 arch/powerpc/platforms/cell/spufs/Makefile create mode 100644 arch/powerpc/platforms/cell/spufs/context.c create mode 100644 arch/powerpc/platforms/cell/spufs/file.c create mode 100644 arch/powerpc/platforms/cell/spufs/inode.c create mode 100644 arch/powerpc/platforms/cell/spufs/spufs.h create mode 100644 arch/powerpc/platforms/cell/spufs/syscalls.c create mode 100644 include/asm-powerpc/spu.h diff --git a/Documentation/filesystems/spufs.txt b/Documentation/filesystems/spufs.txt new file mode 100644 index 000000000000..8edc3952eff4 --- /dev/null +++ b/Documentation/filesystems/spufs.txt @@ -0,0 +1,521 @@ +SPUFS(2) Linux Programmer's Manual SPUFS(2) + + + +NAME + spufs - the SPU file system + + +DESCRIPTION + The SPU file system is used on PowerPC machines that implement the Cell + Broadband Engine Architecture in order to access Synergistic Processor + Units (SPUs). + + The file system provides a name space similar to posix shared memory or + message queues. Users that have write permissions on the file system + can use spu_create(2) to establish SPU contexts in the spufs root. + + Every SPU context is represented by a directory containing a predefined + set of files. These files can be used for manipulating the state of the + logical SPU. Users can change permissions on those files, but not actu- + ally add or remove files. + + +MOUNT OPTIONS + uid= + set the user owning the mount point, the default is 0 (root). + + gid= + set the group owning the mount point, the default is 0 (root). + + +FILES + The files in spufs mostly follow the standard behavior for regular sys- + tem calls like read(2) or write(2), but often support only a subset of + the operations supported on regular file systems. This list details the + supported operations and the deviations from the behaviour in the + respective man pages. + + All files that support the read(2) operation also support readv(2) and + all files that support the write(2) operation also support writev(2). + All files support the access(2) and stat(2) family of operations, but + only the st_mode, st_nlink, st_uid and st_gid fields of struct stat + contain reliable information. + + All files support the chmod(2)/fchmod(2) and chown(2)/fchown(2) opera- + tions, but will not be able to grant permissions that contradict the + possible operations, e.g. read access on the wbox file. + + The current set of files is: + + + /mem + the contents of the local storage memory of the SPU. This can be + accessed like a regular shared memory file and contains both code and + data in the address space of the SPU. The possible operations on an + open mem file are: + + read(2), pread(2), write(2), pwrite(2), lseek(2) + These operate as documented, with the exception that seek(2), + write(2) and pwrite(2) are not supported beyond the end of the + file. The file size is the size of the local storage of the SPU, + which normally is 256 kilobytes. + + mmap(2) + Mapping mem into the process address space gives access to the + SPU local storage within the process address space. Only + MAP_SHARED mappings are allowed. + + + /mbox + The first SPU to CPU communication mailbox. This file is read-only and + can be read in units of 32 bits. The file can only be used in non- + blocking mode and it even poll() will not block on it. The possible + operations on an open mbox file are: + + read(2) + If a count smaller than four is requested, read returns -1 and + sets errno to EINVAL. If there is no data available in the mail + box, the return value is set to -1 and errno becomes EAGAIN. + When data has been read successfully, four bytes are placed in + the data buffer and the value four is returned. + + + /ibox + The second SPU to CPU communication mailbox. This file is similar to + the first mailbox file, but can be read in blocking I/O mode, and the + poll familiy of system calls can be used to wait for it. The possible + operations on an open ibox file are: + + read(2) + If a count smaller than four is requested, read returns -1 and + sets errno to EINVAL. If there is no data available in the mail + box and the file descriptor has been opened with O_NONBLOCK, the + return value is set to -1 and errno becomes EAGAIN. + + If there is no data available in the mail box and the file + descriptor has been opened without O_NONBLOCK, the call will + block until the SPU writes to its interrupt mailbox channel. + When data has been read successfully, four bytes are placed in + the data buffer and the value four is returned. + + poll(2) + Poll on the ibox file returns (POLLIN | POLLRDNORM) whenever + data is available for reading. + + + /wbox + The CPU to SPU communation mailbox. It is write-only can can be written + in units of 32 bits. If the mailbox is full, write() will block and + poll can be used to wait for it becoming empty again. The possible + operations on an open wbox file are: write(2) If a count smaller than + four is requested, write returns -1 and sets errno to EINVAL. If there + is no space available in the mail box and the file descriptor has been + opened with O_NONBLOCK, the return value is set to -1 and errno becomes + EAGAIN. + + If there is no space available in the mail box and the file descriptor + has been opened without O_NONBLOCK, the call will block until the SPU + reads from its PPE mailbox channel. When data has been read success- + fully, four bytes are placed in the data buffer and the value four is + returned. + + poll(2) + Poll on the ibox file returns (POLLOUT | POLLWRNORM) whenever + space is available for writing. + + + /mbox_stat + /ibox_stat + /wbox_stat + Read-only files that contain the length of the current queue, i.e. how + many words can be read from mbox or ibox or how many words can be + written to wbox without blocking. The files can be read only in 4-byte + units and return a big-endian binary integer number. The possible + operations on an open *box_stat file are: + + read(2) + If a count smaller than four is requested, read returns -1 and + sets errno to EINVAL. Otherwise, a four byte value is placed in + the data buffer, containing the number of elements that can be + read from (for mbox_stat and ibox_stat) or written to (for + wbox_stat) the respective mail box without blocking or resulting + in EAGAIN. + + + /npc + /decr + /decr_status + /spu_tag_mask + /event_mask + /srr0 + Internal registers of the SPU. The representation is an ASCII string + with the numeric value of the next instruction to be executed. These + can be used in read/write mode for debugging, but normal operation of + programs should not rely on them because access to any of them except + npc requires an SPU context save and is therefore very inefficient. + + The contents of these files are: + + npc Next Program Counter + + decr SPU Decrementer + + decr_status Decrementer Status + + spu_tag_mask MFC tag mask for SPU DMA + + event_mask Event mask for SPU interrupts + + srr0 Interrupt Return address register + + + The possible operations on an open npc, decr, decr_status, + spu_tag_mask, event_mask or srr0 file are: + + read(2) + When the count supplied to the read call is shorter than the + required length for the pointer value plus a newline character, + subsequent reads from the same file descriptor will result in + completing the string, regardless of changes to the register by + a running SPU task. When a complete string has been read, all + subsequent read operations will return zero bytes and a new file + descriptor needs to be opened to read the value again. + + write(2) + A write operation on the file results in setting the register to + the value given in the string. The string is parsed from the + beginning to the first non-numeric character or the end of the + buffer. Subsequent writes to the same file descriptor overwrite + the previous setting. + + + /fpcr + This file gives access to the Floating Point Status and Control Regis- + ter as a four byte long file. The operations on the fpcr file are: + + read(2) + If a count smaller than four is requested, read returns -1 and + sets errno to EINVAL. Otherwise, a four byte value is placed in + the data buffer, containing the current value of the fpcr regis- + ter. + + write(2) + If a count smaller than four is requested, write returns -1 and + sets errno to EINVAL. Otherwise, a four byte value is copied + from the data buffer, updating the value of the fpcr register. + + + /signal1 + /signal2 + The two signal notification channels of an SPU. These are read-write + files that operate on a 32 bit word. Writing to one of these files + triggers an interrupt on the SPU. The value writting to the signal + files can be read from the SPU through a channel read or from host user + space through the file. After the value has been read by the SPU, it + is reset to zero. The possible operations on an open signal1 or sig- + nal2 file are: + + read(2) + If a count smaller than four is requested, read returns -1 and + sets errno to EINVAL. Otherwise, a four byte value is placed in + the data buffer, containing the current value of the specified + signal notification register. + + write(2) + If a count smaller than four is requested, write returns -1 and + sets errno to EINVAL. Otherwise, a four byte value is copied + from the data buffer, updating the value of the specified signal + notification register. The signal notification register will + either be replaced with the input data or will be updated to the + bitwise OR or the old value and the input data, depending on the + contents of the signal1_type, or signal2_type respectively, + file. + + + /signal1_type + /signal2_type + These two files change the behavior of the signal1 and signal2 notifi- + cation files. The contain a numerical ASCII string which is read as + either "1" or "0". In mode 0 (overwrite), the hardware replaces the + contents of the signal channel with the data that is written to it. in + mode 1 (logical OR), the hardware accumulates the bits that are subse- + quently written to it. The possible operations on an open signal1_type + or signal2_type file are: + + read(2) + When the count supplied to the read call is shorter than the + required length for the digit plus a newline character, subse- + quent reads from the same file descriptor will result in com- + pleting the string. When a complete string has been read, all + subsequent read operations will return zero bytes and a new file + descriptor needs to be opened to read the value again. + + write(2) + A write operation on the file results in setting the register to + the value given in the string. The string is parsed from the + beginning to the first non-numeric character or the end of the + buffer. Subsequent writes to the same file descriptor overwrite + the previous setting. + + +EXAMPLES + /etc/fstab entry + none /spu spufs gid=spu 0 0 + + +AUTHORS + Arnd Bergmann , Mark Nutter , + Ulrich Weigand + +SEE ALSO + capabilities(7), close(2), spu_create(2), spu_run(2), spufs(7) + + + +Linux 2005-09-28 SPUFS(2) + +------------------------------------------------------------------------------ + +SPU_RUN(2) Linux Programmer's Manual SPU_RUN(2) + + + +NAME + spu_run - execute an spu context + + +SYNOPSIS + #include + + int spu_run(int fd, unsigned int *npc, unsigned int *event); + +DESCRIPTION + The spu_run system call is used on PowerPC machines that implement the + Cell Broadband Engine Architecture in order to access Synergistic Pro- + cessor Units (SPUs). It uses the fd that was returned from spu_cre- + ate(2) to address a specific SPU context. When the context gets sched- + uled to a physical SPU, it starts execution at the instruction pointer + passed in npc. + + Execution of SPU code happens synchronously, meaning that spu_run does + not return while the SPU is still running. If there is a need to exe- + cute SPU code in parallel with other code on either the main CPU or + other SPUs, you need to create a new thread of execution first, e.g. + using the pthread_create(3) call. + + When spu_run returns, the current value of the SPU instruction pointer + is written back to npc, so you can call spu_run again without updating + the pointers. + + event can be a NULL pointer or point to an extended status code that + gets filled when spu_run returns. It can be one of the following con- + stants: + + SPE_EVENT_DMA_ALIGNMENT + A DMA alignment error + + SPE_EVENT_SPE_DATA_SEGMENT + A DMA segmentation error + + SPE_EVENT_SPE_DATA_STORAGE + A DMA storage error + + If NULL is passed as the event argument, these errors will result in a + signal delivered to the calling process. + +RETURN VALUE + spu_run returns the value of the spu_status register or -1 to indicate + an error and set errno to one of the error codes listed below. The + spu_status register value contains a bit mask of status codes and + optionally a 14 bit code returned from the stop-and-signal instruction + on the SPU. The bit masks for the status codes are: + + 0x02 SPU was stopped by stop-and-signal. + + 0x04 SPU was stopped by halt. + + 0x08 SPU is waiting for a channel. + + 0x10 SPU is in single-step mode. + + 0x20 SPU has tried to execute an invalid instruction. + + 0x40 SPU has tried to access an invalid channel. + + 0x3fff0000 + The bits masked with this value contain the code returned from + stop-and-signal. + + There are always one or more of the lower eight bits set or an error + code is returned from spu_run. + +ERRORS + EAGAIN or EWOULDBLOCK + fd is in non-blocking mode and spu_run would block. + + EBADF fd is not a valid file descriptor. + + EFAULT npc is not a valid pointer or status is neither NULL nor a valid + pointer. + + EINTR A signal occured while spu_run was in progress. The npc value + has been updated to the new program counter value if necessary. + + EINVAL fd is not a file descriptor returned from spu_create(2). + + ENOMEM Insufficient memory was available to handle a page fault result- + ing from an MFC direct memory access. + + ENOSYS the functionality is not provided by the current system, because + either the hardware does not provide SPUs or the spufs module is + not loaded. + + +NOTES + spu_run is meant to be used from libraries that implement a more + abstract interface to SPUs, not to be used from regular applications. + See http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec- + ommended libraries. + + +CONFORMING TO + This call is Linux specific and only implemented by the ppc64 architec- + ture. Programs using this system call are not portable. + + +BUGS + The code does not yet fully implement all features lined out here. + + +AUTHOR + Arnd Bergmann + +SEE ALSO + capabilities(7), close(2), spu_create(2), spufs(7) + + + +Linux 2005-09-28 SPU_RUN(2) + +------------------------------------------------------------------------------ + +SPU_CREATE(2) Linux Programmer's Manual SPU_CREATE(2) + + + +NAME + spu_create - create a new spu context + + +SYNOPSIS + #include + #include + + int spu_create(const char *pathname, int flags, mode_t mode); + +DESCRIPTION + The spu_create system call is used on PowerPC machines that implement + the Cell Broadband Engine Architecture in order to access Synergistic + Processor Units (SPUs). It creates a new logical context for an SPU in + pathname and returns a handle to associated with it. pathname must + point to a non-existing directory in the mount point of the SPU file + system (spufs). When spu_create is successful, a directory gets cre- + ated on pathname and it is populated with files. + + The returned file handle can only be passed to spu_run(2) or closed, + other operations are not defined on it. When it is closed, all associ- + ated directory entries in spufs are removed. When the last file handle + pointing either inside of the context directory or to this file + descriptor is closed, the logical SPU context is destroyed. + + The parameter flags can be zero or any bitwise or'd combination of the + following constants: + + SPU_RAWIO + Allow mapping of some of the hardware registers of the SPU into + user space. This flag requires the CAP_SYS_RAWIO capability, see + capabilities(7). + + The mode parameter specifies the permissions used for creating the new + directory in spufs. mode is modified with the user's umask(2) value + and then used for both the directory and the files contained in it. The + file permissions mask out some more bits of mode because they typically + support only read or write access. See stat(2) for a full list of the + possible mode values. + + +RETURN VALUE + spu_create returns a new file descriptor. It may return -1 to indicate + an error condition and set errno to one of the error codes listed + below. + + +ERRORS + EACCESS + The current user does not have write access on the spufs mount + point. + + EEXIST An SPU context already exists at the given path name. + + EFAULT pathname is not a valid string pointer in the current address + space. + + EINVAL pathname is not a directory in the spufs mount point. + + ELOOP Too many symlinks were found while resolving pathname. + + EMFILE The process has reached its maximum open file limit. + + ENAMETOOLONG + pathname was too long. + + ENFILE The system has reached the global open file limit. + + ENOENT Part of pathname could not be resolved. + + ENOMEM The kernel could not allocate all resources required. + + ENOSPC There are not enough SPU resources available to create a new + context or the user specific limit for the number of SPU con- + texts has been reached. + + ENOSYS the functionality is not provided by the current system, because + either the hardware does not provide SPUs or the spufs module is + not loaded. + + ENOTDIR + A part of pathname is not a directory. + + + +NOTES + spu_create is meant to be used from libraries that implement a more + abstract interface to SPUs, not to be used from regular applications. + See http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec- + ommended libraries. + + +FILES + pathname must point to a location beneath the mount point of spufs. By + convention, it gets mounted in /spu. + + +CONFORMING TO + This call is Linux specific and only implemented by the ppc64 architec- + ture. Programs using this system call are not portable. + + +BUGS + The code does not yet fully implement all features lined out here. + + +AUTHOR + Arnd Bergmann + +SEE ALSO + capabilities(7), close(2), spu_run(2), spufs(7) + + + +Linux 2005-09-28 SPU_CREATE(2) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 4d71aa3ecbb5..39ca7b9da369 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -482,6 +482,7 @@ source arch/powerpc/platforms/embedded6xx/Kconfig source arch/powerpc/platforms/4xx/Kconfig source arch/powerpc/platforms/85xx/Kconfig source arch/powerpc/platforms/8xx/Kconfig +source arch/powerpc/platforms/cell/Kconfig menu "Kernel options" diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 4bb3650420b4..989f6286991a 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -319,3 +319,5 @@ COMPAT_SYS(ioprio_get) SYSCALL(inotify_init) SYSCALL(inotify_add_watch) SYSCALL(inotify_rm_watch) +SYSCALL(spu_run) +SYSCALL(spu_create) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index a606504678bd..846a1894cf95 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -644,6 +644,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) DBG_LOW(" -> rc=%d\n", rc); return rc; } +EXPORT_SYMBOL_GPL(hash_page); void hash_preload(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap) diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig new file mode 100644 index 000000000000..3157071e241c --- /dev/null +++ b/arch/powerpc/platforms/cell/Kconfig @@ -0,0 +1,13 @@ +menu "Cell Broadband Engine options" + depends on PPC_CELL + +config SPU_FS + tristate "SPU file system" + default m + depends on PPC_CELL + help + The SPU file system is used to access Synergistic Processing + Units on machines implementing the Broadband Processor + Architecture. + +endmenu diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 55e094b96bc0..74616cf13af9 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,2 +1,5 @@ obj-y += interrupt.o iommu.o setup.o spider-pic.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SPU_FS) += spufs/ spu_base.o +builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o +obj-y += $(builtin-spufs-m) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c new file mode 100644 index 000000000000..9e9096590a07 --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -0,0 +1,740 @@ +/* + * Low-level SPU handling + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define DEBUG 1 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "interrupt.h" + +static int __spu_trap_invalid_dma(struct spu *spu) +{ + pr_debug("%s\n", __FUNCTION__); + force_sig(SIGBUS, /* info, */ current); + return 0; +} + +static int __spu_trap_dma_align(struct spu *spu) +{ + pr_debug("%s\n", __FUNCTION__); + force_sig(SIGBUS, /* info, */ current); + return 0; +} + +static int __spu_trap_error(struct spu *spu) +{ + pr_debug("%s\n", __FUNCTION__); + force_sig(SIGILL, /* info, */ current); + return 0; +} + +static void spu_restart_dma(struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); +} + +static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) +{ + struct spu_priv2 __iomem *priv2; + struct mm_struct *mm; + + pr_debug("%s\n", __FUNCTION__); + + if (REGION_ID(ea) != USER_REGION_ID) { + pr_debug("invalid region access at %016lx\n", ea); + return 1; + } + + priv2 = spu->priv2; + mm = spu->mm; + + if (spu->slb_replace >= 8) + spu->slb_replace = 0; + + out_be64(&priv2->slb_index_W, spu->slb_replace); + out_be64(&priv2->slb_vsid_RW, + (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) + | SLB_VSID_USER); + out_be64(&priv2->slb_esid_RW, (ea & ESID_MASK) | SLB_ESID_V); + + spu_restart_dma(spu); + + pr_debug("set slb %d context %lx, ea %016lx, vsid %016lx, esid %016lx\n", + spu->slb_replace, mm->context.id, ea, + (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT)| SLB_VSID_USER, + (ea & ESID_MASK) | SLB_ESID_V); + return 0; +} + +static int __spu_trap_data_map(struct spu *spu, unsigned long ea) +{ + unsigned long dsisr; + struct spu_priv1 __iomem *priv1; + + pr_debug("%s\n", __FUNCTION__); + priv1 = spu->priv1; + dsisr = in_be64(&priv1->mfc_dsisr_RW); + + wake_up(&spu->stop_wq); + + return 0; +} + +static int __spu_trap_mailbox(struct spu *spu) +{ + wake_up_all(&spu->ibox_wq); + kill_fasync(&spu->ibox_fasync, SIGIO, POLLIN); + + /* atomically disable SPU mailbox interrupts */ + spin_lock(&spu->register_lock); + out_be64(&spu->priv1->int_mask_class2_RW, + in_be64(&spu->priv1->int_mask_class2_RW) & ~0x1); + spin_unlock(&spu->register_lock); + return 0; +} + +static int __spu_trap_stop(struct spu *spu) +{ + pr_debug("%s\n", __FUNCTION__); + spu->stop_code = in_be32(&spu->problem->spu_status_R); + wake_up(&spu->stop_wq); + return 0; +} + +static int __spu_trap_halt(struct spu *spu) +{ + pr_debug("%s\n", __FUNCTION__); + spu->stop_code = in_be32(&spu->problem->spu_status_R); + wake_up(&spu->stop_wq); + return 0; +} + +static int __spu_trap_tag_group(struct spu *spu) +{ + pr_debug("%s\n", __FUNCTION__); + /* wake_up(&spu->dma_wq); */ + return 0; +} + +static int __spu_trap_spubox(struct spu *spu) +{ + wake_up_all(&spu->wbox_wq); + kill_fasync(&spu->wbox_fasync, SIGIO, POLLOUT); + + /* atomically disable SPU mailbox interrupts */ + spin_lock(&spu->register_lock); + out_be64(&spu->priv1->int_mask_class2_RW, + in_be64(&spu->priv1->int_mask_class2_RW) & ~0x10); + spin_unlock(&spu->register_lock); + return 0; +} + +static irqreturn_t +spu_irq_class_0(int irq, void *data, struct pt_regs *regs) +{ + struct spu *spu; + + spu = data; + spu->class_0_pending = 1; + wake_up(&spu->stop_wq); + + return IRQ_HANDLED; +} + +static int +spu_irq_class_0_bottom(struct spu *spu) +{ + unsigned long stat; + + spu->class_0_pending = 0; + + stat = in_be64(&spu->priv1->int_stat_class0_RW); + + if (stat & 1) /* invalid MFC DMA */ + __spu_trap_invalid_dma(spu); + + if (stat & 2) /* invalid DMA alignment */ + __spu_trap_dma_align(spu); + + if (stat & 4) /* error on SPU */ + __spu_trap_error(spu); + + out_be64(&spu->priv1->int_stat_class0_RW, stat); + return 0; +} + +static irqreturn_t +spu_irq_class_1(int irq, void *data, struct pt_regs *regs) +{ + struct spu *spu; + unsigned long stat, dar; + + spu = data; + stat = in_be64(&spu->priv1->int_stat_class1_RW); + dar = in_be64(&spu->priv1->mfc_dar_RW); + + if (stat & 1) /* segment fault */ + __spu_trap_data_seg(spu, dar); + + if (stat & 2) { /* mapping fault */ + __spu_trap_data_map(spu, dar); + } + + if (stat & 4) /* ls compare & suspend on get */ + ; + + if (stat & 8) /* ls compare & suspend on put */ + ; + + out_be64(&spu->priv1->int_stat_class1_RW, stat); + return stat ? IRQ_HANDLED : IRQ_NONE; +} + +static irqreturn_t +spu_irq_class_2(int irq, void *data, struct pt_regs *regs) +{ + struct spu *spu; + unsigned long stat; + + spu = data; + stat = in_be64(&spu->priv1->int_stat_class2_RW); + + pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, + in_be64(&spu->priv1->int_mask_class2_RW)); + + + if (stat & 1) /* PPC core mailbox */ + __spu_trap_mailbox(spu); + + if (stat & 2) /* SPU stop-and-signal */ + __spu_trap_stop(spu); + + if (stat & 4) /* SPU halted */ + __spu_trap_halt(spu); + + if (stat & 8) /* DMA tag group complete */ + __spu_trap_tag_group(spu); + + if (stat & 0x10) /* SPU mailbox threshold */ + __spu_trap_spubox(spu); + + out_be64(&spu->priv1->int_stat_class2_RW, stat); + return stat ? IRQ_HANDLED : IRQ_NONE; +} + +static int +spu_request_irqs(struct spu *spu) +{ + int ret; + int irq_base; + + irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET; + + snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number); + ret = request_irq(irq_base + spu->isrc, + spu_irq_class_0, 0, spu->irq_c0, spu); + if (ret) + goto out; + out_be64(&spu->priv1->int_mask_class0_RW, 0x7); + + snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number); + ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, + spu_irq_class_1, 0, spu->irq_c1, spu); + if (ret) + goto out1; + out_be64(&spu->priv1->int_mask_class1_RW, 0x3); + + snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); + ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, + spu_irq_class_2, 0, spu->irq_c2, spu); + if (ret) + goto out2; + out_be64(&spu->priv1->int_mask_class2_RW, 0xe); + goto out; + +out2: + free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); +out1: + free_irq(irq_base + spu->isrc, spu); +out: + return ret; +} + +static void +spu_free_irqs(struct spu *spu) +{ + int irq_base; + + irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET; + + free_irq(irq_base + spu->isrc, spu); + free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); + free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu); +} + +static LIST_HEAD(spu_list); +static DECLARE_MUTEX(spu_mutex); + +static void spu_init_channels(struct spu *spu) +{ + static const struct { + unsigned channel; + unsigned count; + } zero_list[] = { + { 0x00, 1, }, { 0x01, 1, }, { 0x03, 1, }, { 0x04, 1, }, + { 0x18, 1, }, { 0x19, 1, }, { 0x1b, 1, }, { 0x1d, 1, }, + }, count_list[] = { + { 0x00, 0, }, { 0x03, 0, }, { 0x04, 0, }, { 0x15, 16, }, + { 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, }, + { 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, }, + }; + struct spu_priv2 *priv2; + int i; + + priv2 = spu->priv2; + + /* initialize all channel data to zero */ + for (i = 0; i < ARRAY_SIZE(zero_list); i++) { + int count; + + out_be64(&priv2->spu_chnlcntptr_RW, zero_list[i].channel); + for (count = 0; count < zero_list[i].count; count++) + out_be64(&priv2->spu_chnldata_RW, 0); + } + + /* initialize channel counts to meaningful values */ + for (i = 0; i < ARRAY_SIZE(count_list); i++) { + out_be64(&priv2->spu_chnlcntptr_RW, count_list[i].channel); + out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count); + } +} + +static void spu_init_regs(struct spu *spu) +{ + out_be64(&spu->priv1->int_mask_class0_RW, 0x7); + out_be64(&spu->priv1->int_mask_class1_RW, 0x3); + out_be64(&spu->priv1->int_mask_class2_RW, 0xe); +} + +struct spu *spu_alloc(void) +{ + struct spu *spu; + + down(&spu_mutex); + if (!list_empty(&spu_list)) { + spu = list_entry(spu_list.next, struct spu, list); + list_del_init(&spu->list); + pr_debug("Got SPU %x %d\n", spu->isrc, spu->number); + } else { + pr_debug("No SPU left\n"); + spu = NULL; + } + up(&spu_mutex); + + if (spu) { + spu_init_channels(spu); + spu_init_regs(spu); + } + + return spu; +} +EXPORT_SYMBOL(spu_alloc); + +void spu_free(struct spu *spu) +{ + down(&spu_mutex); + spu->ibox_fasync = NULL; + spu->wbox_fasync = NULL; + list_add_tail(&spu->list, &spu_list); + up(&spu_mutex); +} +EXPORT_SYMBOL(spu_free); + +extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX +static int spu_handle_mm_fault(struct spu *spu) +{ + struct spu_priv1 __iomem *priv1; + struct mm_struct *mm = spu->mm; + struct vm_area_struct *vma; + u64 ea, dsisr, is_write; + int ret; + + priv1 = spu->priv1; + ea = in_be64(&priv1->mfc_dar_RW); + dsisr = in_be64(&priv1->mfc_dsisr_RW); +#if 0 + if (!IS_VALID_EA(ea)) { + return -EFAULT; + } +#endif /* XXX */ + if (mm == NULL) { + return -EFAULT; + } + if (mm->pgd == NULL) { + return -EFAULT; + } + + down_read(&mm->mmap_sem); + vma = find_vma(mm, ea); + if (!vma) + goto bad_area; + if (vma->vm_start <= ea) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +#if 0 + if (expand_stack(vma, ea)) + goto bad_area; +#endif /* XXX */ +good_area: + is_write = dsisr & MFC_DSISR_ACCESS_PUT; + if (is_write) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + if (dsisr & MFC_DSISR_ACCESS_DENIED) + goto bad_area; + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + ret = 0; + switch (handle_mm_fault(mm, vma, ea, is_write)) { + case VM_FAULT_MINOR: + current->min_flt++; + break; + case VM_FAULT_MAJOR: + current->maj_flt++; + break; + case VM_FAULT_SIGBUS: + ret = -EFAULT; + goto bad_area; + case VM_FAULT_OOM: + ret = -ENOMEM; + goto bad_area; + default: + BUG(); + } + up_read(&mm->mmap_sem); + return ret; + +bad_area: + up_read(&mm->mmap_sem); + return -EFAULT; +} + +static int spu_handle_pte_fault(struct spu *spu) +{ + struct spu_priv1 __iomem *priv1; + u64 ea, dsisr, access, error = 0UL; + int ret = 0; + + priv1 = spu->priv1; + ea = in_be64(&priv1->mfc_dar_RW); + dsisr = in_be64(&priv1->mfc_dsisr_RW); + access = (_PAGE_PRESENT | _PAGE_USER); + if (dsisr & MFC_DSISR_PTE_NOT_FOUND) { + if (hash_page(ea, access, 0x300) != 0) + error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; + } + if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) || + (dsisr & MFC_DSISR_ACCESS_DENIED)) { + if ((ret = spu_handle_mm_fault(spu)) != 0) + error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; + else + error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR; + } + if (!error) + spu_restart_dma(spu); + + return ret; +} + +int spu_run(struct spu *spu) +{ + struct spu_problem __iomem *prob; + struct spu_priv1 __iomem *priv1; + struct spu_priv2 __iomem *priv2; + unsigned long status; + int ret; + + prob = spu->problem; + priv1 = spu->priv1; + priv2 = spu->priv2; + + /* Let SPU run. */ + spu->mm = current->mm; + eieio(); + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); + + do { + ret = wait_event_interruptible(spu->stop_wq, + (!((status = in_be32(&prob->spu_status_R)) & 0x1)) + || (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND) + || spu->class_0_pending); + + if (status & SPU_STATUS_STOPPED_BY_STOP) + ret = -EAGAIN; + else if (status & SPU_STATUS_STOPPED_BY_HALT) + ret = -EIO; + else if (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND) + ret = spu_handle_pte_fault(spu); + + if (spu->class_0_pending) + spu_irq_class_0_bottom(spu); + + if (!ret && signal_pending(current)) + ret = -ERESTARTSYS; + + } while (!ret); + + /* Ensure SPU is stopped. */ + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); + eieio(); + while (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) + cpu_relax(); + + out_be64(&priv2->slb_invalidate_all_W, 0); + out_be64(&priv1->tlb_invalidate_entry_W, 0UL); + eieio(); + + spu->mm = NULL; + + /* Check for SPU breakpoint. */ + if (unlikely(current->ptrace & PT_PTRACED)) { + status = in_be32(&prob->spu_status_R); + + if ((status & SPU_STATUS_STOPPED_BY_STOP) + && status >> SPU_STOP_STATUS_SHIFT == 0x3fff) { + force_sig(SIGTRAP, current); + ret = -ERESTARTSYS; + } + } + + return ret; +} +EXPORT_SYMBOL(spu_run); + +static void __iomem * __init map_spe_prop(struct device_node *n, + const char *name) +{ + struct address_prop { + unsigned long address; + unsigned int len; + } __attribute__((packed)) *prop; + + void *p; + int proplen; + + p = get_property(n, name, &proplen); + if (proplen != sizeof (struct address_prop)) + return NULL; + + prop = p; + + return ioremap(prop->address, prop->len); +} + +static void spu_unmap(struct spu *spu) +{ + iounmap(spu->priv2); + iounmap(spu->priv1); + iounmap(spu->problem); + iounmap((u8 __iomem *)spu->local_store); +} + +static int __init spu_map_device(struct spu *spu, struct device_node *spe) +{ + char *prop; + int ret; + + ret = -ENODEV; + prop = get_property(spe, "isrc", NULL); + if (!prop) + goto out; + spu->isrc = *(unsigned int *)prop; + + spu->name = get_property(spe, "name", NULL); + if (!spu->name) + goto out; + + prop = get_property(spe, "local-store", NULL); + if (!prop) + goto out; + spu->local_store_phys = *(unsigned long *)prop; + + /* we use local store as ram, not io memory */ + spu->local_store = (void __force *)map_spe_prop(spe, "local-store"); + if (!spu->local_store) + goto out; + + spu->problem= map_spe_prop(spe, "problem"); + if (!spu->problem) + goto out_unmap; + + spu->priv1= map_spe_prop(spe, "priv1"); + if (!spu->priv1) + goto out_unmap; + + spu->priv2= map_spe_prop(spe, "priv2"); + if (!spu->priv2) + goto out_unmap; + ret = 0; + goto out; + +out_unmap: + spu_unmap(spu); +out: + return ret; +} + +static int __init find_spu_node_id(struct device_node *spe) +{ + unsigned int *id; + struct device_node *cpu; + + cpu = spe->parent->parent; + id = (unsigned int *)get_property(cpu, "node-id", NULL); + + return id ? *id : 0; +} + +static int __init create_spu(struct device_node *spe) +{ + struct spu *spu; + int ret; + static int number; + + ret = -ENOMEM; + spu = kmalloc(sizeof (*spu), GFP_KERNEL); + if (!spu) + goto out; + + ret = spu_map_device(spu, spe); + if (ret) + goto out_free; + + spu->node = find_spu_node_id(spe); + spu->stop_code = 0; + spu->slb_replace = 0; + spu->mm = NULL; + spu->class_0_pending = 0; + spin_lock_init(&spu->register_lock); + + out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); + out_be64(&spu->priv1->mfc_sr1_RW, 0x33); + + init_waitqueue_head(&spu->stop_wq); + init_waitqueue_head(&spu->wbox_wq); + init_waitqueue_head(&spu->ibox_wq); + + spu->ibox_fasync = NULL; + spu->wbox_fasync = NULL; + + down(&spu_mutex); + spu->number = number++; + ret = spu_request_irqs(spu); + if (ret) + goto out_unmap; + + list_add(&spu->list, &spu_list); + up(&spu_mutex); + + pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n", + spu->name, spu->isrc, spu->local_store, + spu->problem, spu->priv1, spu->priv2, spu->number); + goto out; + +out_unmap: + up(&spu_mutex); + spu_unmap(spu); +out_free: + kfree(spu); +out: + return ret; +} + +static void destroy_spu(struct spu *spu) +{ + list_del_init(&spu->list); + + spu_free_irqs(spu); + spu_unmap(spu); + kfree(spu); +} + +static void cleanup_spu_base(void) +{ + struct spu *spu, *tmp; + down(&spu_mutex); + list_for_each_entry_safe(spu, tmp, &spu_list, list) + destroy_spu(spu); + up(&spu_mutex); +} +module_exit(cleanup_spu_base); + +static int __init init_spu_base(void) +{ + struct device_node *node; + int ret; + + ret = -ENODEV; + for (node = of_find_node_by_type(NULL, "spe"); + node; node = of_find_node_by_type(node, "spe")) { + ret = create_spu(node); + if (ret) { + printk(KERN_WARNING "%s: Error initializing %s\n", + __FUNCTION__, node->name); + cleanup_spu_base(); + break; + } + } + /* in some old firmware versions, the spe is called 'spc', so we + look for that as well */ + for (node = of_find_node_by_type(NULL, "spc"); + node; node = of_find_node_by_type(node, "spc")) { + ret = create_spu(node); + if (ret) { + printk(KERN_WARNING "%s: Error initializing %s\n", + __FUNCTION__, node->name); + cleanup_spu_base(); + break; + } + } + return ret; +} +module_init(init_spu_base); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Arnd Bergmann "); diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c new file mode 100644 index 000000000000..43e0b187ffde --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -0,0 +1,86 @@ +/* + * SPU file system -- system call stubs + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include + +#include + +struct spufs_calls spufs_calls = { + .owner = NULL, +}; + +/* These stub syscalls are needed to have the actual implementation + * within a loadable module. When spufs is built into the kernel, + * this file is not used and the syscalls directly enter the fs code */ + +asmlinkage long sys_spu_create(const char __user *name, + unsigned int flags, mode_t mode) +{ + long ret; + + ret = -ENOSYS; + if (try_module_get(spufs_calls.owner)) { + ret = spufs_calls.create_thread(name, flags, mode); + module_put(spufs_calls.owner); + } + return ret; +} + +asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) +{ + long ret; + struct file *filp; + int fput_needed; + + ret = -ENOSYS; + if (try_module_get(spufs_calls.owner)) { + ret = -EBADF; + filp = fget_light(fd, &fput_needed); + if (filp) { + ret = spufs_calls.spu_run(filp, unpc, ustatus); + fput_light(filp, fput_needed); + } + module_put(spufs_calls.owner); + } + return ret; +} + +int register_spu_syscalls(struct spufs_calls *calls) +{ + if (spufs_calls.owner) + return -EBUSY; + + spufs_calls.create_thread = calls->create_thread; + spufs_calls.spu_run = calls->spu_run; + smp_mb(); + spufs_calls.owner = calls->owner; + return 0; +} +EXPORT_SYMBOL_GPL(register_spu_syscalls); + +void unregister_spu_syscalls(struct spufs_calls *calls) +{ + BUG_ON(spufs_calls.owner != calls->owner); + spufs_calls.owner = NULL; +} +EXPORT_SYMBOL_GPL(unregister_spu_syscalls); diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile new file mode 100644 index 000000000000..6f496e37bcb7 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SPU_FS) += spufs.o + +spufs-y += inode.o file.o context.o syscalls.o diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c new file mode 100644 index 000000000000..a69b85e2778a --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -0,0 +1,67 @@ +/* + * SPU file system -- SPU context management + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "spufs.h" + +struct spu_context *alloc_spu_context(void) +{ + struct spu_context *ctx; + ctx = kmalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + goto out; + ctx->spu = spu_alloc(); + if (!ctx->spu) + goto out_free; + init_rwsem(&ctx->backing_sema); + spin_lock_init(&ctx->mmio_lock); + kref_init(&ctx->kref); + goto out; +out_free: + kfree(ctx); + ctx = NULL; +out: + return ctx; +} + +void destroy_spu_context(struct kref *kref) +{ + struct spu_context *ctx; + ctx = container_of(kref, struct spu_context, kref); + if (ctx->spu) + spu_free(ctx->spu); + kfree(ctx); +} + +struct spu_context * get_spu_context(struct spu_context *ctx) +{ + kref_get(&ctx->kref); + return ctx; +} + +int put_spu_context(struct spu_context *ctx) +{ + return kref_put(&ctx->kref, &destroy_spu_context); +} + + diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c new file mode 100644 index 000000000000..c1e643310494 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -0,0 +1,596 @@ +/* + * SPU file system -- file contents + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "spufs.h" + +static int +spufs_mem_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + file->private_data = i->i_ctx; + return 0; +} + +static ssize_t +spufs_mem_read(struct file *file, char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu *spu; + struct spu_context *ctx; + int ret; + + ctx = file->private_data; + spu = ctx->spu; + + down_read(&ctx->backing_sema); + if (spu->number & 0/*1*/) { + ret = generic_file_read(file, buffer, size, pos); + goto out; + } + + ret = simple_read_from_buffer(buffer, size, pos, + spu->local_store, LS_SIZE); +out: + up_read(&ctx->backing_sema); + return ret; +} + +static ssize_t +spufs_mem_write(struct file *file, const char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + struct spu *spu = ctx->spu; + + if (spu->number & 0) //1) + return generic_file_write(file, buffer, size, pos); + + size = min_t(ssize_t, LS_SIZE - *pos, size); + if (size <= 0) + return -EFBIG; + *pos += size; + return copy_from_user(spu->local_store + *pos - size, + buffer, size) ? -EFAULT : size; +} + +static int +spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct spu_context *ctx = file->private_data; + struct spu *spu = ctx->spu; + unsigned long pfn; + + if (spu->number & 0) //1) + return generic_file_mmap(file, vma); + + vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = __pgprot(pgprot_val (vma->vm_page_prot) + | _PAGE_NO_CACHE); + pfn = spu->local_store_phys >> PAGE_SHIFT; + /* + * This will work for actual SPUs, but not for vmalloc memory: + */ + if (remap_pfn_range(vma, vma->vm_start, pfn, + vma->vm_end-vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +static struct file_operations spufs_mem_fops = { + .open = spufs_mem_open, + .read = spufs_mem_read, + .write = spufs_mem_write, + .mmap = spufs_mem_mmap, + .llseek = generic_file_llseek, +}; + +/* generic open function for all pipe-like files */ +static int spufs_pipe_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + file->private_data = i->i_ctx; + + return nonseekable_open(inode, file); +} + +static ssize_t spufs_mbox_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + struct spu_problem __iomem *prob; + u32 mbox_stat; + u32 mbox_data; + + if (len < 4) + return -EINVAL; + + ctx = file->private_data; + prob = ctx->spu->problem; + mbox_stat = in_be32(&prob->mb_stat_R); + if (!(mbox_stat & 0x0000ff)) + return -EAGAIN; + + mbox_data = in_be32(&prob->pu_mb_R); + + if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) + return -EFAULT; + + return 4; +} + +static struct file_operations spufs_mbox_fops = { + .open = spufs_pipe_open, + .read = spufs_mbox_read, +}; + +static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + u32 mbox_stat; + + if (len < 4) + return -EINVAL; + + ctx = file->private_data; + mbox_stat = in_be32(&ctx->spu->problem->mb_stat_R) & 0xff; + + if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) + return -EFAULT; + + return 4; +} + +static struct file_operations spufs_mbox_stat_fops = { + .open = spufs_pipe_open, + .read = spufs_mbox_stat_read, +}; + +/* low-level ibox access function */ +size_t spu_ibox_read(struct spu *spu, u32 *data) +{ + int ret; + + spin_lock_irq(&spu->register_lock); + + if (in_be32(&spu->problem->mb_stat_R) & 0xff0000) { + /* read the first available word */ + *data = in_be64(&spu->priv2->puint_mb_R); + ret = 4; + } else { + /* make sure we get woken up by the interrupt */ + out_be64(&spu->priv1->int_mask_class2_RW, + in_be64(&spu->priv1->int_mask_class2_RW) | 0x1); + ret = 0; + } + + spin_unlock_irq(&spu->register_lock); + return ret; +} +EXPORT_SYMBOL(spu_ibox_read); + +static int spufs_ibox_fasync(int fd, struct file *file, int on) +{ + struct spu_context *ctx; + ctx = file->private_data; + return fasync_helper(fd, file, on, &ctx->spu->ibox_fasync); +} + +static ssize_t spufs_ibox_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + u32 ibox_data; + ssize_t ret; + + if (len < 4) + return -EINVAL; + + ctx = file->private_data; + + ret = 0; + if (file->f_flags & O_NONBLOCK) { + if (!spu_ibox_read(ctx->spu, &ibox_data)) + ret = -EAGAIN; + } else { + ret = wait_event_interruptible(ctx->spu->ibox_wq, + spu_ibox_read(ctx->spu, &ibox_data)); + } + + if (ret) + return ret; + + ret = 4; + if (copy_to_user(buf, &ibox_data, sizeof ibox_data)) + ret = -EFAULT; + + return ret; +} + +static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) +{ + struct spu_context *ctx; + struct spu_problem __iomem *prob; + u32 mbox_stat; + unsigned int mask; + + ctx = file->private_data; + prob = ctx->spu->problem; + mbox_stat = in_be32(&prob->mb_stat_R); + + poll_wait(file, &ctx->spu->ibox_wq, wait); + + mask = 0; + if (mbox_stat & 0xff0000) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static struct file_operations spufs_ibox_fops = { + .open = spufs_pipe_open, + .read = spufs_ibox_read, + .poll = spufs_ibox_poll, + .fasync = spufs_ibox_fasync, +}; + +static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + u32 ibox_stat; + + if (len < 4) + return -EINVAL; + + ctx = file->private_data; + ibox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 16) & 0xff; + + if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) + return -EFAULT; + + return 4; +} + +static struct file_operations spufs_ibox_stat_fops = { + .open = spufs_pipe_open, + .read = spufs_ibox_stat_read, +}; + +/* low-level mailbox write */ +size_t spu_wbox_write(struct spu *spu, u32 data) +{ + int ret; + + spin_lock_irq(&spu->register_lock); + + if (in_be32(&spu->problem->mb_stat_R) & 0x00ff00) { + /* we have space to write wbox_data to */ + out_be32(&spu->problem->spu_mb_W, data); + ret = 4; + } else { + /* make sure we get woken up by the interrupt when space + becomes available */ + out_be64(&spu->priv1->int_mask_class2_RW, + in_be64(&spu->priv1->int_mask_class2_RW) | 0x10); + ret = 0; + } + + spin_unlock_irq(&spu->register_lock); + return ret; +} +EXPORT_SYMBOL(spu_wbox_write); + +static int spufs_wbox_fasync(int fd, struct file *file, int on) +{ + struct spu_context *ctx; + ctx = file->private_data; + return fasync_helper(fd, file, on, &ctx->spu->wbox_fasync); +} + +static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + u32 wbox_data; + int ret; + + if (len < 4) + return -EINVAL; + + ctx = file->private_data; + + if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) + return -EFAULT; + + ret = 0; + if (file->f_flags & O_NONBLOCK) { + if (!spu_wbox_write(ctx->spu, wbox_data)) + ret = -EAGAIN; + } else { + ret = wait_event_interruptible(ctx->spu->wbox_wq, + spu_wbox_write(ctx->spu, wbox_data)); + } + + return ret ? ret : sizeof wbox_data; +} + +static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) +{ + struct spu_context *ctx; + struct spu_problem __iomem *prob; + u32 mbox_stat; + unsigned int mask; + + ctx = file->private_data; + prob = ctx->spu->problem; + mbox_stat = in_be32(&prob->mb_stat_R); + + poll_wait(file, &ctx->spu->wbox_wq, wait); + + mask = 0; + if (mbox_stat & 0x00ff00) + mask = POLLOUT | POLLWRNORM; + + return mask; +} + +static struct file_operations spufs_wbox_fops = { + .open = spufs_pipe_open, + .write = spufs_wbox_write, + .poll = spufs_wbox_poll, + .fasync = spufs_wbox_fasync, +}; + +static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + u32 wbox_stat; + + if (len < 4) + return -EINVAL; + + ctx = file->private_data; + wbox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 8) & 0xff; + + if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) + return -EFAULT; + + return 4; +} + +static struct file_operations spufs_wbox_stat_fops = { + .open = spufs_pipe_open, + .read = spufs_wbox_stat_read, +}; + +long spufs_run_spu(struct file *file, struct spu_context *ctx, + u32 *npc, u32 *status) +{ + struct spu_problem __iomem *prob; + int ret; + + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (!down_write_trylock(&ctx->backing_sema)) + goto out; + } else { + down_write(&ctx->backing_sema); + } + + prob = ctx->spu->problem; + out_be32(&prob->spu_npc_RW, *npc); + + ret = spu_run(ctx->spu); + + *status = in_be32(&prob->spu_status_R); + *npc = in_be32(&prob->spu_npc_RW); + + up_write(&ctx->backing_sema); + +out: + return ret; +} + +static ssize_t spufs_signal1_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + struct spu_problem *prob; + u32 data; + + ctx = file->private_data; + prob = ctx->spu->problem; + + if (len < 4) + return -EINVAL; + + data = in_be32(&prob->signal_notify1); + if (copy_to_user(buf, &data, 4)) + return -EFAULT; + + return 4; +} + +static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + struct spu_problem *prob; + u32 data; + + ctx = file->private_data; + prob = ctx->spu->problem; + + if (len < 4) + return -EINVAL; + + if (copy_from_user(&data, buf, 4)) + return -EFAULT; + + out_be32(&prob->signal_notify1, data); + + return 4; +} + +static struct file_operations spufs_signal1_fops = { + .open = spufs_pipe_open, + .read = spufs_signal1_read, + .write = spufs_signal1_write, +}; + +static ssize_t spufs_signal2_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + struct spu_problem *prob; + u32 data; + + ctx = file->private_data; + prob = ctx->spu->problem; + + if (len < 4) + return -EINVAL; + + data = in_be32(&prob->signal_notify2); + if (copy_to_user(buf, &data, 4)) + return -EFAULT; + + return 4; +} + +static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, + size_t len, loff_t *pos) +{ + struct spu_context *ctx; + struct spu_problem *prob; + u32 data; + + ctx = file->private_data; + prob = ctx->spu->problem; + + if (len < 4) + return -EINVAL; + + if (copy_from_user(&data, buf, 4)) + return -EFAULT; + + out_be32(&prob->signal_notify2, data); + + return 4; +} + +static struct file_operations spufs_signal2_fops = { + .open = spufs_pipe_open, + .read = spufs_signal2_read, + .write = spufs_signal2_write, +}; + +static void spufs_signal1_type_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_priv2 *priv2 = ctx->spu->priv2; + u64 tmp; + + spin_lock_irq(&ctx->spu->register_lock); + tmp = in_be64(&priv2->spu_cfg_RW); + if (val) + tmp |= 1; + else + tmp &= ~1; + out_be64(&priv2->spu_cfg_RW, tmp); + spin_unlock_irq(&ctx->spu->register_lock); +} + +static u64 spufs_signal1_type_get(void *data) +{ + struct spu_context *ctx = data; + return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, + spufs_signal1_type_set, "%llu"); + +static void spufs_signal2_type_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_priv2 *priv2 = ctx->spu->priv2; + u64 tmp; + + spin_lock_irq(&ctx->spu->register_lock); + tmp = in_be64(&priv2->spu_cfg_RW); + if (val) + tmp |= 2; + else + tmp &= ~2; + out_be64(&priv2->spu_cfg_RW, tmp); + spin_unlock_irq(&ctx->spu->register_lock); +} + +static u64 spufs_signal2_type_get(void *data) +{ + struct spu_context *ctx = data; + return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, + spufs_signal2_type_set, "%llu"); + +static void spufs_npc_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + out_be32(&ctx->spu->problem->spu_npc_RW, val); +} + +static u64 spufs_npc_get(void *data) +{ + struct spu_context *ctx = data; + u64 ret; + ret = in_be32(&ctx->spu->problem->spu_npc_RW); + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") + +struct tree_descr spufs_dir_contents[] = { + { "mem", &spufs_mem_fops, 0666, }, + { "mbox", &spufs_mbox_fops, 0444, }, + { "ibox", &spufs_ibox_fops, 0444, }, + { "wbox", &spufs_wbox_fops, 0222, }, + { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, + { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, + { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, + { "signal1", &spufs_signal1_fops, 0666, }, + { "signal2", &spufs_signal2_fops, 0666, }, + { "signal1_type", &spufs_signal1_type, 0666, }, + { "signal2_type", &spufs_signal2_type, 0666, }, + { "npc", &spufs_npc_ops, 0666, }, + {}, +}; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c new file mode 100644 index 000000000000..f7aa0a6b1ce5 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -0,0 +1,470 @@ +/* + * SPU file system + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "spufs.h" + +static kmem_cache_t *spufs_inode_cache; + +/* Information about the backing dev, same as ramfs */ +#if 0 +static struct backing_dev_info spufs_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | + BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | BDI_CAP_READ_MAP | + BDI_CAP_WRITE_MAP, +}; + +static struct address_space_operations spufs_aops = { + .readpage = simple_readpage, + .prepare_write = simple_prepare_write, + .commit_write = simple_commit_write, +}; +#endif + +/* Inode operations */ + +static struct inode * +spufs_alloc_inode(struct super_block *sb) +{ + struct spufs_inode_info *ei; + + ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL); + if (!ei) + return NULL; + return &ei->vfs_inode; +} + +static void +spufs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(spufs_inode_cache, SPUFS_I(inode)); +} + +static void +spufs_init_once(void *p, kmem_cache_t * cachep, unsigned long flags) +{ + struct spufs_inode_info *ei = p; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + inode_init_once(&ei->vfs_inode); + } +} + +static struct inode * +spufs_new_inode(struct super_block *sb, int mode) +{ + struct inode *inode; + + inode = new_inode(sb); + if (!inode) + goto out; + + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; +out: + return inode; +} + +static int +spufs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + +/* dump_stack(); + pr_debug("ia_size %lld, i_size:%lld\n", attr->ia_size, inode->i_size); +*/ + if ((attr->ia_valid & ATTR_SIZE) && + (attr->ia_size != inode->i_size)) + return -EINVAL; + return inode_setattr(inode, attr); +} + + +static int +spufs_new_file(struct super_block *sb, struct dentry *dentry, + struct file_operations *fops, int mode, + struct spu_context *ctx) +{ + static struct inode_operations spufs_file_iops = { + .getattr = simple_getattr, + .setattr = spufs_setattr, + .unlink = simple_unlink, + }; + struct inode *inode; + int ret; + + ret = -ENOSPC; + inode = spufs_new_inode(sb, S_IFREG | mode); + if (!inode) + goto out; + + ret = 0; + inode->i_op = &spufs_file_iops; + inode->i_fop = fops; + inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); + d_add(dentry, inode); +out: + return ret; +} + +static void +spufs_delete_inode(struct inode *inode) +{ + if (SPUFS_I(inode)->i_ctx) + put_spu_context(SPUFS_I(inode)->i_ctx); + clear_inode(inode); +} + +static int +spufs_fill_dir(struct dentry *dir, struct tree_descr *files, + int mode, struct spu_context *ctx) +{ + struct dentry *dentry; + int ret; + + while (files->name && files->name[0]) { + ret = -ENOMEM; + dentry = d_alloc_name(dir, files->name); + if (!dentry) + goto out; + ret = spufs_new_file(dir->d_sb, dentry, files->ops, + files->mode & mode, ctx); + if (ret) + goto out; + files++; + } + return 0; +out: + // FIXME: remove all files that are left + + return ret; +} + +static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) +{ + struct dentry *dentry; + int err; + + spin_lock(&dcache_lock); + /* remove all entries */ + err = 0; + list_for_each_entry(dentry, &dir_dentry->d_subdirs, d_child) { + if (d_unhashed(dentry) || !dentry->d_inode) + continue; + atomic_dec(&dentry->d_count); + spin_lock(&dentry->d_lock); + __d_drop(dentry); + spin_unlock(&dentry->d_lock); + } + spin_unlock(&dcache_lock); + if (!err) { + shrink_dcache_parent(dir_dentry); + err = simple_rmdir(root, dir_dentry); + } + return err; +} + +static int spufs_dir_close(struct inode *inode, struct file *file) +{ + struct inode *dir; + struct dentry *dentry; + int ret; + + dentry = file->f_dentry; + dir = dentry->d_parent->d_inode; + down(&dir->i_sem); + ret = spufs_rmdir(dir, file->f_dentry); + WARN_ON(ret); + up(&dir->i_sem); + return dcache_dir_close(inode, file); +} + +struct inode_operations spufs_dir_inode_operations = { + .lookup = simple_lookup, +}; + +struct file_operations spufs_autodelete_dir_operations = { + .open = dcache_dir_open, + .release = spufs_dir_close, + .llseek = dcache_dir_lseek, + .read = generic_read_dir, + .readdir = dcache_readdir, + .fsync = simple_sync_file, +}; + +static int +spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int ret; + struct inode *inode; + struct spu_context *ctx; + + ret = -ENOSPC; + inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); + if (!inode) + goto out; + + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + inode->i_mode &= S_ISGID; + } + ctx = alloc_spu_context(); + SPUFS_I(inode)->i_ctx = ctx; + if (!ctx) + goto out_iput; + + inode->i_op = &spufs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); + if (ret) + goto out_free_ctx; + + d_instantiate(dentry, inode); + dget(dentry); + dir->i_nlink++; + goto out; + +out_free_ctx: + put_spu_context(ctx); +out_iput: + iput(inode); +out: + return ret; +} + +long +spufs_create_thread(struct nameidata *nd, const char *name, + unsigned int flags, mode_t mode) +{ + struct dentry *dentry; + struct file *filp; + int ret; + + /* need to be at the root of spufs */ + ret = -EINVAL; + if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC || + nd->dentry != nd->dentry->d_sb->s_root) + goto out; + + dentry = lookup_create(nd, 1); + ret = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out_dir; + + ret = -EEXIST; + if (dentry->d_inode) + goto out_dput; + + mode &= ~current->fs->umask; + ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO); + if (ret) + goto out_dput; + + ret = get_unused_fd(); + if (ret < 0) + goto out_dput; + + dentry->d_inode->i_nlink++; + + filp = filp_open(name, O_RDONLY, mode); + if (IS_ERR(filp)) { + // FIXME: remove directory again + put_unused_fd(ret); + ret = PTR_ERR(filp); + } else { + filp->f_op = &spufs_autodelete_dir_operations; + fd_install(ret, filp); + } + +out_dput: + dput(dentry); +out_dir: + up(&nd->dentry->d_inode->i_sem); +out: + return ret; +} + +/* File system initialization */ +enum { + Opt_uid, Opt_gid, Opt_err, +}; + +static match_table_t spufs_tokens = { + { Opt_uid, "uid=%d" }, + { Opt_gid, "gid=%d" }, + { Opt_err, NULL }, +}; + +static int +spufs_parse_options(char *options, struct inode *root) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + + while ((p = strsep(&options, ",")) != NULL) { + int token, option; + + if (!*p) + continue; + + token = match_token(p, spufs_tokens, args); + switch (token) { + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; + root->i_uid = option; + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; + root->i_gid = option; + break; + default: + return 0; + } + } + return 1; +} + +static int +spufs_create_root(struct super_block *sb, void *data) { + struct inode *inode; + int ret; + + ret = -ENOMEM; + inode = spufs_new_inode(sb, S_IFDIR | 0775); + if (!inode) + goto out; + + inode->i_op = &spufs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + SPUFS_I(inode)->i_ctx = NULL; + + ret = -EINVAL; + if (!spufs_parse_options(data, inode)) + goto out_iput; + + ret = -ENOMEM; + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) + goto out_iput; + + return 0; +out_iput: + iput(inode); +out: + return ret; +} + +static int +spufs_fill_super(struct super_block *sb, void *data, int silent) +{ + static struct super_operations s_ops = { + .alloc_inode = spufs_alloc_inode, + .destroy_inode = spufs_destroy_inode, + .statfs = simple_statfs, + .delete_inode = spufs_delete_inode, + .drop_inode = generic_delete_inode, + }; + + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = SPUFS_MAGIC; + sb->s_op = &s_ops; + + return spufs_create_root(sb, data); +} + +static struct super_block * +spufs_get_sb(struct file_system_type *fstype, int flags, + const char *name, void *data) +{ + return get_sb_single(fstype, flags, data, spufs_fill_super); +} + +static struct file_system_type spufs_type = { + .owner = THIS_MODULE, + .name = "spufs", + .get_sb = spufs_get_sb, + .kill_sb = kill_litter_super, +}; + +static int spufs_init(void) +{ + int ret; + ret = -ENOMEM; + spufs_inode_cache = kmem_cache_create("spufs_inode_cache", + sizeof(struct spufs_inode_info), 0, + SLAB_HWCACHE_ALIGN, spufs_init_once, NULL); + + if (!spufs_inode_cache) + goto out; + ret = register_filesystem(&spufs_type); + if (ret) + goto out_cache; + ret = register_spu_syscalls(&spufs_calls); + if (ret) + goto out_fs; + return 0; +out_fs: + unregister_filesystem(&spufs_type); +out_cache: + kmem_cache_destroy(spufs_inode_cache); +out: + return ret; +} +module_init(spufs_init); + +static void spufs_exit(void) +{ + unregister_spu_syscalls(&spufs_calls); + unregister_filesystem(&spufs_type); + kmem_cache_destroy(spufs_inode_cache); +} +module_exit(spufs_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Arnd Bergmann "); + diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h new file mode 100644 index 000000000000..b37fe797ea1c --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -0,0 +1,71 @@ +/* + * SPU file system + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef SPUFS_H +#define SPUFS_H + +#include +#include +#include +#include + +#include + +/* The magic number for our file system */ +enum { + SPUFS_MAGIC = 0x23c9b64e, +}; + +struct spu_context { + struct spu *spu; /* pointer to a physical SPU */ + struct rw_semaphore backing_sema; /* protects the above */ + spinlock_t mmio_lock; /* protects mmio access */ + + struct kref kref; +}; + +struct spufs_inode_info { + struct spu_context *i_ctx; + struct inode vfs_inode; +}; +#define SPUFS_I(inode) \ + container_of(inode, struct spufs_inode_info, vfs_inode) + +extern struct tree_descr spufs_dir_contents[]; + +/* system call implementation */ +long spufs_run_spu(struct file *file, + struct spu_context *ctx, u32 *npc, u32 *status); +long spufs_create_thread(struct nameidata *nd, const char *name, + unsigned int flags, mode_t mode); + +/* context management */ +struct spu_context * alloc_spu_context(void); +void destroy_spu_context(struct kref *kref); +struct spu_context * get_spu_context(struct spu_context *ctx); +int put_spu_context(struct spu_context *ctx); + +void spu_acquire(struct spu_context *ctx); +void spu_release(struct spu_context *ctx); +void spu_acquire_runnable(struct spu_context *ctx); +void spu_acquire_saved(struct spu_context *ctx); + +#endif diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c new file mode 100644 index 000000000000..3f71bb5e9d8e --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include + +#include + +#include "spufs.h" + +/** + * sys_spu_run - run code loaded into an SPU + * + * @unpc: next program counter for the SPU + * @ustatus: status of the SPU + * + * This system call transfers the control of execution of a + * user space thread to an SPU. It will return when the + * SPU has finished executing or when it hits an error + * condition and it will be interrupted if a signal needs + * to be delivered to a handler in user space. + * + * The next program counter is set to the passed value + * before the SPU starts fetching code and the user space + * pointer gets updated with the new value when returning + * from kernel space. + * + * The status value returned from spu_run reflects the + * value of the spu_status register after the SPU has stopped. + * + */ +long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus) +{ + long ret; + struct spufs_inode_info *i; + u32 npc, status; + + ret = -EFAULT; + if (get_user(npc, unpc)) + goto out; + + ret = -EINVAL; + if (filp->f_vfsmnt->mnt_sb->s_magic != SPUFS_MAGIC) + goto out; + + i = SPUFS_I(filp->f_dentry->d_inode); + ret = spufs_run_spu(filp, i->i_ctx, &npc, &status); + + if (ret ==-EAGAIN || ret == -EIO) + ret = status; + + if (put_user(npc, unpc)) + ret = -EFAULT; + + if (ustatus && put_user(status, ustatus)) + ret = -EFAULT; +out: + return ret; +} + +#ifndef MODULE +asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) +{ + int fput_needed; + struct file *filp; + long ret; + + ret = -EBADF; + filp = fget_light(fd, &fput_needed); + if (filp) { + ret = do_spu_run(filp, unpc, ustatus); + fput_light(filp, fput_needed); + } + + return ret; +} +#endif + +asmlinkage long sys_spu_create(const char __user *pathname, + unsigned int flags, mode_t mode) +{ + char *tmp; + int ret; + + tmp = getname(pathname); + ret = PTR_ERR(tmp); + if (!IS_ERR(tmp)) { + struct nameidata nd; + + ret = path_lookup(tmp, LOOKUP_PARENT| + LOOKUP_OPEN|LOOKUP_CREATE, &nd); + if (!ret) { + ret = spufs_create_thread(&nd, pathname, flags, mode); + path_release(&nd); + } + putname(tmp); + } + + return ret; +} + +struct spufs_calls spufs_calls = { + .create_thread = sys_spu_create, + .spu_run = do_spu_run, + .owner = THIS_MODULE, +}; diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 28f1082e5040..95075f99a6d4 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -307,7 +307,6 @@ EXPORT_SYMBOL(__res); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); -EXPORT_SYMBOL_GPL(__handle_mm_fault); /* For MOL */ EXPORT_SYMBOL(disarm_decr); #ifdef CONFIG_PPC_STD_MMU extern long mol_trampoline; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h new file mode 100644 index 000000000000..b036385cd831 --- /dev/null +++ b/include/asm-powerpc/spu.h @@ -0,0 +1,498 @@ +/* + * SPU core / file system interface and HW structures + * + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * + * Author: Arnd Bergmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _SPU_H +#define _SPU_H +#include +#include +#include + +#define LS_ORDER (6) /* 256 kb */ + +#define LS_SIZE (PAGE_SIZE << LS_ORDER) + +struct spu { + char *name; + unsigned long local_store_phys; + u8 *local_store; + struct spu_problem __iomem *problem; + struct spu_priv1 __iomem *priv1; + struct spu_priv2 __iomem *priv2; + struct list_head list; + int number; + u32 isrc; + u32 node; + struct kref kref; + size_t ls_size; + unsigned int slb_replace; + struct mm_struct *mm; + int class_0_pending; + spinlock_t register_lock; + + u32 stop_code; + wait_queue_head_t stop_wq; + wait_queue_head_t ibox_wq; + wait_queue_head_t wbox_wq; + struct fasync_struct *ibox_fasync; + struct fasync_struct *wbox_fasync; + + char irq_c0[8]; + char irq_c1[8]; + char irq_c2[8]; +}; + +struct spu *spu_alloc(void); +void spu_free(struct spu *spu); +int spu_run(struct spu *spu); + +size_t spu_wbox_write(struct spu *spu, u32 data); +size_t spu_ibox_read(struct spu *spu, u32 *data); + +extern struct spufs_calls { + asmlinkage long (*create_thread)(const char __user *name, + unsigned int flags, mode_t mode); + asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, + __u32 __user *ustatus); + struct module *owner; +} spufs_calls; + +#ifdef CONFIG_SPU_FS_MODULE +int register_spu_syscalls(struct spufs_calls *calls); +void unregister_spu_syscalls(struct spufs_calls *calls); +#else +static inline int register_spu_syscalls(struct spufs_calls *calls) +{ + return 0; +} +static inline void unregister_spu_syscalls(struct spufs_calls *calls) +{ +} +#endif /* MODULE */ + + +/* + * This defines the Local Store, Problem Area and Privlege Area of an SPU. + */ + +union mfc_tag_size_class_cmd { + struct { + u16 mfc_size; + u16 mfc_tag; + u8 pad; + u8 mfc_rclassid; + u16 mfc_cmd; + } u; + struct { + u32 mfc_size_tag32; + u32 mfc_class_cmd32; + } by32; + u64 all64; +}; + +struct mfc_cq_sr { + u64 mfc_cq_data0_RW; + u64 mfc_cq_data1_RW; + u64 mfc_cq_data2_RW; + u64 mfc_cq_data3_RW; +}; + +struct spu_problem { +#define MS_SYNC_PENDING 1L + u64 spc_mssync_RW; /* 0x0000 */ + u8 pad_0x0008_0x3000[0x3000 - 0x0008]; + + /* DMA Area */ + u8 pad_0x3000_0x3004[0x4]; /* 0x3000 */ + u32 mfc_lsa_W; /* 0x3004 */ + u64 mfc_ea_W; /* 0x3008 */ + union mfc_tag_size_class_cmd mfc_union_W; /* 0x3010 */ + u8 pad_0x3018_0x3104[0xec]; /* 0x3018 */ + u32 dma_qstatus_R; /* 0x3104 */ + u8 pad_0x3108_0x3204[0xfc]; /* 0x3108 */ + u32 dma_querytype_RW; /* 0x3204 */ + u8 pad_0x3208_0x321c[0x14]; /* 0x3208 */ + u32 dma_querymask_RW; /* 0x321c */ + u8 pad_0x3220_0x322c[0xc]; /* 0x3220 */ + u32 dma_tagstatus_R; /* 0x322c */ +#define DMA_TAGSTATUS_INTR_ANY 1u +#define DMA_TAGSTATUS_INTR_ALL 2u + u8 pad_0x3230_0x4000[0x4000 - 0x3230]; /* 0x3230 */ + + /* SPU Control Area */ + u8 pad_0x4000_0x4004[0x4]; /* 0x4000 */ + u32 pu_mb_R; /* 0x4004 */ + u8 pad_0x4008_0x400c[0x4]; /* 0x4008 */ + u32 spu_mb_W; /* 0x400c */ + u8 pad_0x4010_0x4014[0x4]; /* 0x4010 */ + u32 mb_stat_R; /* 0x4014 */ + u8 pad_0x4018_0x401c[0x4]; /* 0x4018 */ + u32 spu_runcntl_RW; /* 0x401c */ +#define SPU_RUNCNTL_STOP 0L +#define SPU_RUNCNTL_RUNNABLE 1L + u8 pad_0x4020_0x4024[0x4]; /* 0x4020 */ + u32 spu_status_R; /* 0x4024 */ +#define SPU_STOP_STATUS_SHIFT 16 +#define SPU_STATUS_STOPPED 0x0 +#define SPU_STATUS_RUNNING 0x1 +#define SPU_STATUS_STOPPED_BY_STOP 0x2 +#define SPU_STATUS_STOPPED_BY_HALT 0x4 +#define SPU_STATUS_WAITING_FOR_CHANNEL 0x8 +#define SPU_STATUS_SINGLE_STEP 0x10 +#define SPU_STATUS_INVALID_INSTR 0x20 +#define SPU_STATUS_INVALID_CH 0x40 +#define SPU_STATUS_ISOLATED_STATE 0x80 +#define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200 +#define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400 + u8 pad_0x4028_0x402c[0x4]; /* 0x4028 */ + u32 spu_spe_R; /* 0x402c */ + u8 pad_0x4030_0x4034[0x4]; /* 0x4030 */ + u32 spu_npc_RW; /* 0x4034 */ + u8 pad_0x4038_0x14000[0x14000 - 0x4038]; /* 0x4038 */ + + /* Signal Notification Area */ + u8 pad_0x14000_0x1400c[0xc]; /* 0x14000 */ + u32 signal_notify1; /* 0x1400c */ + u8 pad_0x14010_0x1c00c[0x7ffc]; /* 0x14010 */ + u32 signal_notify2; /* 0x1c00c */ +} __attribute__ ((aligned(0x20000))); + +/* SPU Privilege 2 State Area */ +struct spu_priv2 { + /* MFC Registers */ + u8 pad_0x0000_0x1100[0x1100 - 0x0000]; /* 0x0000 */ + + /* SLB Management Registers */ + u8 pad_0x1100_0x1108[0x8]; /* 0x1100 */ + u64 slb_index_W; /* 0x1108 */ +#define SLB_INDEX_MASK 0x7L + u64 slb_esid_RW; /* 0x1110 */ + u64 slb_vsid_RW; /* 0x1118 */ +#define SLB_VSID_SUPERVISOR_STATE (0x1ull << 11) +#define SLB_VSID_SUPERVISOR_STATE_MASK (0x1ull << 11) +#define SLB_VSID_PROBLEM_STATE (0x1ull << 10) +#define SLB_VSID_PROBLEM_STATE_MASK (0x1ull << 10) +#define SLB_VSID_EXECUTE_SEGMENT (0x1ull << 9) +#define SLB_VSID_NO_EXECUTE_SEGMENT (0x1ull << 9) +#define SLB_VSID_EXECUTE_SEGMENT_MASK (0x1ull << 9) +#define SLB_VSID_4K_PAGE (0x0 << 8) +#define SLB_VSID_LARGE_PAGE (0x1ull << 8) +#define SLB_VSID_PAGE_SIZE_MASK (0x1ull << 8) +#define SLB_VSID_CLASS_MASK (0x1ull << 7) +#define SLB_VSID_VIRTUAL_PAGE_SIZE_MASK (0x1ull << 6) + u64 slb_invalidate_entry_W; /* 0x1120 */ + u64 slb_invalidate_all_W; /* 0x1128 */ + u8 pad_0x1130_0x2000[0x2000 - 0x1130]; /* 0x1130 */ + + /* Context Save / Restore Area */ + struct mfc_cq_sr spuq[16]; /* 0x2000 */ + struct mfc_cq_sr puq[8]; /* 0x2200 */ + u8 pad_0x2300_0x3000[0x3000 - 0x2300]; /* 0x2300 */ + + /* MFC Control */ + u64 mfc_control_RW; /* 0x3000 */ +#define MFC_CNTL_RESUME_DMA_QUEUE (0ull << 0) +#define MFC_CNTL_SUSPEND_DMA_QUEUE (1ull << 0) +#define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK (1ull << 0) +#define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION (0ull << 8) +#define MFC_CNTL_SUSPEND_IN_PROGRESS (1ull << 8) +#define MFC_CNTL_SUSPEND_COMPLETE (3ull << 8) +#define MFC_CNTL_SUSPEND_DMA_STATUS_MASK (3ull << 8) +#define MFC_CNTL_DMA_QUEUES_EMPTY (1ull << 14) +#define MFC_CNTL_DMA_QUEUES_EMPTY_MASK (1ull << 14) +#define MFC_CNTL_PURGE_DMA_REQUEST (1ull << 15) +#define MFC_CNTL_PURGE_DMA_IN_PROGRESS (1ull << 24) +#define MFC_CNTL_PURGE_DMA_COMPLETE (3ull << 24) +#define MFC_CNTL_PURGE_DMA_STATUS_MASK (3ull << 24) +#define MFC_CNTL_RESTART_DMA_COMMAND (1ull << 32) +#define MFC_CNTL_DMA_COMMAND_REISSUE_PENDING (1ull << 32) +#define MFC_CNTL_DMA_COMMAND_REISSUE_STATUS_MASK (1ull << 32) +#define MFC_CNTL_MFC_PRIVILEGE_STATE (2ull << 33) +#define MFC_CNTL_MFC_PROBLEM_STATE (3ull << 33) +#define MFC_CNTL_MFC_KEY_PROTECTION_STATE_MASK (3ull << 33) +#define MFC_CNTL_DECREMENTER_HALTED (1ull << 35) +#define MFC_CNTL_DECREMENTER_RUNNING (1ull << 40) +#define MFC_CNTL_DECREMENTER_STATUS_MASK (1ull << 40) + u8 pad_0x3008_0x4000[0x4000 - 0x3008]; /* 0x3008 */ + + /* Interrupt Mailbox */ + u64 puint_mb_R; /* 0x4000 */ + u8 pad_0x4008_0x4040[0x4040 - 0x4008]; /* 0x4008 */ + + /* SPU Control */ + u64 spu_privcntl_RW; /* 0x4040 */ +#define SPU_PRIVCNTL_MODE_NORMAL (0x0ull << 0) +#define SPU_PRIVCNTL_MODE_SINGLE_STEP (0x1ull << 0) +#define SPU_PRIVCNTL_MODE_MASK (0x1ull << 0) +#define SPU_PRIVCNTL_NO_ATTENTION_EVENT (0x0ull << 1) +#define SPU_PRIVCNTL_ATTENTION_EVENT (0x1ull << 1) +#define SPU_PRIVCNTL_ATTENTION_EVENT_MASK (0x1ull << 1) +#define SPU_PRIVCNT_LOAD_REQUEST_NORMAL (0x0ull << 2) +#define SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK (0x1ull << 2) + u8 pad_0x4048_0x4058[0x10]; /* 0x4048 */ + u64 spu_lslr_RW; /* 0x4058 */ + u64 spu_chnlcntptr_RW; /* 0x4060 */ + u64 spu_chnlcnt_RW; /* 0x4068 */ + u64 spu_chnldata_RW; /* 0x4070 */ + u64 spu_cfg_RW; /* 0x4078 */ + u8 pad_0x4080_0x5000[0x5000 - 0x4080]; /* 0x4080 */ + + /* PV2_ImplRegs: Implementation-specific privileged-state 2 regs */ + u64 spu_pm_trace_tag_status_RW; /* 0x5000 */ + u64 spu_tag_status_query_RW; /* 0x5008 */ +#define TAG_STATUS_QUERY_CONDITION_BITS (0x3ull << 32) +#define TAG_STATUS_QUERY_MASK_BITS (0xffffffffull) + u64 spu_cmd_buf1_RW; /* 0x5010 */ +#define SPU_COMMAND_BUFFER_1_LSA_BITS (0x7ffffull << 32) +#define SPU_COMMAND_BUFFER_1_EAH_BITS (0xffffffffull) + u64 spu_cmd_buf2_RW; /* 0x5018 */ +#define SPU_COMMAND_BUFFER_2_EAL_BITS ((0xffffffffull) << 32) +#define SPU_COMMAND_BUFFER_2_TS_BITS (0xffffull << 16) +#define SPU_COMMAND_BUFFER_2_TAG_BITS (0x3full) + u64 spu_atomic_status_RW; /* 0x5020 */ +} __attribute__ ((aligned(0x20000))); + +/* SPU Privilege 1 State Area */ +struct spu_priv1 { + /* Control and Configuration Area */ + u64 mfc_sr1_RW; /* 0x000 */ +#define MFC_STATE1_LOCAL_STORAGE_DECODE_MASK 0x01ull +#define MFC_STATE1_BUS_TLBIE_MASK 0x02ull +#define MFC_STATE1_REAL_MODE_OFFSET_ENABLE_MASK 0x04ull +#define MFC_STATE1_PROBLEM_STATE_MASK 0x08ull +#define MFC_STATE1_RELOCATE_MASK 0x10ull +#define MFC_STATE1_MASTER_RUN_CONTROL_MASK 0x20ull + u64 mfc_lpid_RW; /* 0x008 */ + u64 spu_idr_RW; /* 0x010 */ + u64 mfc_vr_RO; /* 0x018 */ +#define MFC_VERSION_BITS (0xffff << 16) +#define MFC_REVISION_BITS (0xffff) +#define MFC_GET_VERSION_BITS(vr) (((vr) & MFC_VERSION_BITS) >> 16) +#define MFC_GET_REVISION_BITS(vr) ((vr) & MFC_REVISION_BITS) + u64 spu_vr_RO; /* 0x020 */ +#define SPU_VERSION_BITS (0xffff << 16) +#define SPU_REVISION_BITS (0xffff) +#define SPU_GET_VERSION_BITS(vr) (vr & SPU_VERSION_BITS) >> 16 +#define SPU_GET_REVISION_BITS(vr) (vr & SPU_REVISION_BITS) + u8 pad_0x28_0x100[0x100 - 0x28]; /* 0x28 */ + + + /* Interrupt Area */ + u64 int_mask_class0_RW; /* 0x100 */ +#define CLASS0_ENABLE_DMA_ALIGNMENT_INTR 0x1L +#define CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR 0x2L +#define CLASS0_ENABLE_SPU_ERROR_INTR 0x4L +#define CLASS0_ENABLE_MFC_FIR_INTR 0x8L + u64 int_mask_class1_RW; /* 0x108 */ +#define CLASS1_ENABLE_SEGMENT_FAULT_INTR 0x1L +#define CLASS1_ENABLE_STORAGE_FAULT_INTR 0x2L +#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_GET_INTR 0x4L +#define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_PUT_INTR 0x8L + u64 int_mask_class2_RW; /* 0x110 */ +#define CLASS2_ENABLE_MAILBOX_INTR 0x1L +#define CLASS2_ENABLE_SPU_STOP_INTR 0x2L +#define CLASS2_ENABLE_SPU_HALT_INTR 0x4L +#define CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR 0x8L + u8 pad_0x118_0x140[0x28]; /* 0x118 */ + u64 int_stat_class0_RW; /* 0x140 */ + u64 int_stat_class1_RW; /* 0x148 */ + u64 int_stat_class2_RW; /* 0x150 */ + u8 pad_0x158_0x180[0x28]; /* 0x158 */ + u64 int_route_RW; /* 0x180 */ + + /* Interrupt Routing */ + u8 pad_0x188_0x200[0x200 - 0x188]; /* 0x188 */ + + /* Atomic Unit Control Area */ + u64 mfc_atomic_flush_RW; /* 0x200 */ +#define mfc_atomic_flush_enable 0x1L + u8 pad_0x208_0x280[0x78]; /* 0x208 */ + u64 resource_allocation_groupID_RW; /* 0x280 */ + u64 resource_allocation_enable_RW; /* 0x288 */ + u8 pad_0x290_0x3c8[0x3c8 - 0x290]; /* 0x290 */ + + /* SPU_Cache_ImplRegs: Implementation-dependent cache registers */ + + u64 smf_sbi_signal_sel; /* 0x3c8 */ +#define smf_sbi_mask_lsb 56 +#define smf_sbi_shift (63 - smf_sbi_mask_lsb) +#define smf_sbi_mask (0x301LL << smf_sbi_shift) +#define smf_sbi_bus0_bits (0x001LL << smf_sbi_shift) +#define smf_sbi_bus2_bits (0x100LL << smf_sbi_shift) +#define smf_sbi2_bus0_bits (0x201LL << smf_sbi_shift) +#define smf_sbi2_bus2_bits (0x300LL << smf_sbi_shift) + u64 smf_ato_signal_sel; /* 0x3d0 */ +#define smf_ato_mask_lsb 35 +#define smf_ato_shift (63 - smf_ato_mask_lsb) +#define smf_ato_mask (0x3LL << smf_ato_shift) +#define smf_ato_bus0_bits (0x2LL << smf_ato_shift) +#define smf_ato_bus2_bits (0x1LL << smf_ato_shift) + u8 pad_0x3d8_0x400[0x400 - 0x3d8]; /* 0x3d8 */ + + /* TLB Management Registers */ + u64 mfc_sdr_RW; /* 0x400 */ + u8 pad_0x408_0x500[0xf8]; /* 0x408 */ + u64 tlb_index_hint_RO; /* 0x500 */ + u64 tlb_index_W; /* 0x508 */ + u64 tlb_vpn_RW; /* 0x510 */ + u64 tlb_rpn_RW; /* 0x518 */ + u8 pad_0x520_0x540[0x20]; /* 0x520 */ + u64 tlb_invalidate_entry_W; /* 0x540 */ + u64 tlb_invalidate_all_W; /* 0x548 */ + u8 pad_0x550_0x580[0x580 - 0x550]; /* 0x550 */ + + /* SPU_MMU_ImplRegs: Implementation-dependent MMU registers */ + u64 smm_hid; /* 0x580 */ +#define PAGE_SIZE_MASK 0xf000000000000000ull +#define PAGE_SIZE_16MB_64KB 0x2000000000000000ull + u8 pad_0x588_0x600[0x600 - 0x588]; /* 0x588 */ + + /* MFC Status/Control Area */ + u64 mfc_accr_RW; /* 0x600 */ +#define MFC_ACCR_EA_ACCESS_GET (1 << 0) +#define MFC_ACCR_EA_ACCESS_PUT (1 << 1) +#define MFC_ACCR_LS_ACCESS_GET (1 << 3) +#define MFC_ACCR_LS_ACCESS_PUT (1 << 4) + u8 pad_0x608_0x610[0x8]; /* 0x608 */ + u64 mfc_dsisr_RW; /* 0x610 */ +#define MFC_DSISR_PTE_NOT_FOUND (1 << 30) +#define MFC_DSISR_ACCESS_DENIED (1 << 27) +#define MFC_DSISR_ATOMIC (1 << 26) +#define MFC_DSISR_ACCESS_PUT (1 << 25) +#define MFC_DSISR_ADDR_MATCH (1 << 22) +#define MFC_DSISR_LS (1 << 17) +#define MFC_DSISR_L (1 << 16) +#define MFC_DSISR_ADDRESS_OVERFLOW (1 << 0) + u8 pad_0x618_0x620[0x8]; /* 0x618 */ + u64 mfc_dar_RW; /* 0x620 */ + u8 pad_0x628_0x700[0x700 - 0x628]; /* 0x628 */ + + /* Replacement Management Table (RMT) Area */ + u64 rmt_index_RW; /* 0x700 */ + u8 pad_0x708_0x710[0x8]; /* 0x708 */ + u64 rmt_data1_RW; /* 0x710 */ + u8 pad_0x718_0x800[0x800 - 0x718]; /* 0x718 */ + + /* Control/Configuration Registers */ + u64 mfc_dsir_R; /* 0x800 */ +#define MFC_DSIR_Q (1 << 31) +#define MFC_DSIR_SPU_QUEUE MFC_DSIR_Q + u64 mfc_lsacr_RW; /* 0x808 */ +#define MFC_LSACR_COMPARE_MASK ((~0ull) << 32) +#define MFC_LSACR_COMPARE_ADDR ((~0ull) >> 32) + u64 mfc_lscrr_R; /* 0x810 */ +#define MFC_LSCRR_Q (1 << 31) +#define MFC_LSCRR_SPU_QUEUE MFC_LSCRR_Q +#define MFC_LSCRR_QI_SHIFT 32 +#define MFC_LSCRR_QI_MASK ((~0ull) << MFC_LSCRR_QI_SHIFT) + u8 pad_0x818_0x820[0x8]; /* 0x818 */ + u64 mfc_tclass_id_RW; /* 0x820 */ +#define MFC_TCLASS_ID_ENABLE (1L << 0L) +#define MFC_TCLASS_SLOT2_ENABLE (1L << 5L) +#define MFC_TCLASS_SLOT1_ENABLE (1L << 6L) +#define MFC_TCLASS_SLOT0_ENABLE (1L << 7L) +#define MFC_TCLASS_QUOTA_2_SHIFT 8L +#define MFC_TCLASS_QUOTA_1_SHIFT 16L +#define MFC_TCLASS_QUOTA_0_SHIFT 24L +#define MFC_TCLASS_QUOTA_2_MASK (0x1FL << MFC_TCLASS_QUOTA_2_SHIFT) +#define MFC_TCLASS_QUOTA_1_MASK (0x1FL << MFC_TCLASS_QUOTA_1_SHIFT) +#define MFC_TCLASS_QUOTA_0_MASK (0x1FL << MFC_TCLASS_QUOTA_0_SHIFT) + u8 pad_0x828_0x900[0x900 - 0x828]; /* 0x828 */ + + /* Real Mode Support Registers */ + u64 mfc_rm_boundary; /* 0x900 */ + u8 pad_0x908_0x938[0x30]; /* 0x908 */ + u64 smf_dma_signal_sel; /* 0x938 */ +#define mfc_dma1_mask_lsb 41 +#define mfc_dma1_shift (63 - mfc_dma1_mask_lsb) +#define mfc_dma1_mask (0x3LL << mfc_dma1_shift) +#define mfc_dma1_bits (0x1LL << mfc_dma1_shift) +#define mfc_dma2_mask_lsb 43 +#define mfc_dma2_shift (63 - mfc_dma2_mask_lsb) +#define mfc_dma2_mask (0x3LL << mfc_dma2_shift) +#define mfc_dma2_bits (0x1LL << mfc_dma2_shift) + u8 pad_0x940_0xa38[0xf8]; /* 0x940 */ + u64 smm_signal_sel; /* 0xa38 */ +#define smm_sig_mask_lsb 12 +#define smm_sig_shift (63 - smm_sig_mask_lsb) +#define smm_sig_mask (0x3LL << smm_sig_shift) +#define smm_sig_bus0_bits (0x2LL << smm_sig_shift) +#define smm_sig_bus2_bits (0x1LL << smm_sig_shift) + u8 pad_0xa40_0xc00[0xc00 - 0xa40]; /* 0xa40 */ + + /* DMA Command Error Area */ + u64 mfc_cer_R; /* 0xc00 */ +#define MFC_CER_Q (1 << 31) +#define MFC_CER_SPU_QUEUE MFC_CER_Q + u8 pad_0xc08_0x1000[0x1000 - 0xc08]; /* 0xc08 */ + + /* PV1_ImplRegs: Implementation-dependent privileged-state 1 regs */ + /* DMA Command Error Area */ + u64 spu_ecc_cntl_RW; /* 0x1000 */ +#define SPU_ECC_CNTL_E (1ull << 0ull) +#define SPU_ECC_CNTL_ENABLE SPU_ECC_CNTL_E +#define SPU_ECC_CNTL_DISABLE (~SPU_ECC_CNTL_E & 1L) +#define SPU_ECC_CNTL_S (1ull << 1ull) +#define SPU_ECC_STOP_AFTER_ERROR SPU_ECC_CNTL_S +#define SPU_ECC_CONTINUE_AFTER_ERROR (~SPU_ECC_CNTL_S & 2L) +#define SPU_ECC_CNTL_B (1ull << 2ull) +#define SPU_ECC_BACKGROUND_ENABLE SPU_ECC_CNTL_B +#define SPU_ECC_BACKGROUND_DISABLE (~SPU_ECC_CNTL_B & 4L) +#define SPU_ECC_CNTL_I_SHIFT 3ull +#define SPU_ECC_CNTL_I_MASK (3ull << SPU_ECC_CNTL_I_SHIFT) +#define SPU_ECC_WRITE_ALWAYS (~SPU_ECC_CNTL_I & 12L) +#define SPU_ECC_WRITE_CORRECTABLE (1ull << SPU_ECC_CNTL_I_SHIFT) +#define SPU_ECC_WRITE_UNCORRECTABLE (3ull << SPU_ECC_CNTL_I_SHIFT) +#define SPU_ECC_CNTL_D (1ull << 5ull) +#define SPU_ECC_DETECTION_ENABLE SPU_ECC_CNTL_D +#define SPU_ECC_DETECTION_DISABLE (~SPU_ECC_CNTL_D & 32L) + u64 spu_ecc_stat_RW; /* 0x1008 */ +#define SPU_ECC_CORRECTED_ERROR (1ull << 0ul) +#define SPU_ECC_UNCORRECTED_ERROR (1ull << 1ul) +#define SPU_ECC_SCRUB_COMPLETE (1ull << 2ul) +#define SPU_ECC_SCRUB_IN_PROGRESS (1ull << 3ul) +#define SPU_ECC_INSTRUCTION_ERROR (1ull << 4ul) +#define SPU_ECC_DATA_ERROR (1ull << 5ul) +#define SPU_ECC_DMA_ERROR (1ull << 6ul) +#define SPU_ECC_STATUS_CNT_MASK (256ull << 8) + u64 spu_ecc_addr_RW; /* 0x1010 */ + u64 spu_err_mask_RW; /* 0x1018 */ +#define SPU_ERR_ILLEGAL_INSTR (1ull << 0ul) +#define SPU_ERR_ILLEGAL_CHANNEL (1ull << 1ul) + u8 pad_0x1020_0x1028[0x1028 - 0x1020]; /* 0x1020 */ + + /* SPU Debug-Trace Bus (DTB) Selection Registers */ + u64 spu_trig0_sel; /* 0x1028 */ + u64 spu_trig1_sel; /* 0x1030 */ + u64 spu_trig2_sel; /* 0x1038 */ + u64 spu_trig3_sel; /* 0x1040 */ + u64 spu_trace_sel; /* 0x1048 */ +#define spu_trace_sel_mask 0x1f1fLL +#define spu_trace_sel_bus0_bits 0x1000LL +#define spu_trace_sel_bus2_bits 0x0010LL + u64 spu_event0_sel; /* 0x1050 */ + u64 spu_event1_sel; /* 0x1058 */ + u64 spu_event2_sel; /* 0x1060 */ + u64 spu_event3_sel; /* 0x1068 */ + u64 spu_trace_cntl; /* 0x1070 */ +} __attribute__ ((aligned(0x2000))); + +#endif diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index 0991dfceef1d..9606349855da 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -296,6 +296,8 @@ #define __NR_inotify_init 275 #define __NR_inotify_add_watch 276 #define __NR_inotify_rm_watch 277 +#define __NR_spu_run 278 +#define __NR_spu_create 279 #define __NR_syscalls 278 diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index c7007b1db91d..44fdd48d38e6 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -512,4 +512,9 @@ asmlinkage long sys_ioprio_get(int which, int who); asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, unsigned long maxnode); +asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, + __u32 __user *ustatus); +asmlinkage long sys_spu_create(const char __user *name, + unsigned int flags, mode_t mode); + #endif diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 1ab2370e2efa..d4739a475d23 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -90,3 +90,5 @@ cond_syscall(sys_pciconfig_iobase); cond_syscall(sys32_ipc); cond_syscall(sys32_sysctl); cond_syscall(ppc_rtas); +cond_syscall(sys_spu_run); +cond_syscall(sys_spu_create); diff --git a/mm/memory.c b/mm/memory.c index 7197f9bcd384..3944fec38012 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2267,6 +2267,8 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, return handle_pte_fault(mm, vma, address, pte, pmd, write_access); } +EXPORT_SYMBOL_GPL(__handle_mm_fault); + #ifndef __PAGETABLE_PUD_FOLDED /* * Allocate page upper directory. -- cgit v1.2.3 From 5473af049d8b3556874174e61ce1986c9b5e8fa6 Mon Sep 17 00:00:00 2001 From: Mark Nutter Date: Tue, 15 Nov 2005 15:53:49 -0500 Subject: [PATCH] spufs: switchable spu contexts Add some infrastructure for saving and restoring the context of an SPE. This patch creates a new structure that can hold the whole state of a physical SPE in memory. It also contains code that avoids races during the context switch and the binary code that is loaded to the SPU in order to access its registers. The actual PPE- and SPE-side context switch code are two separate patches. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 27 ++- arch/powerpc/platforms/cell/spufs/Makefile | 4 +- arch/powerpc/platforms/cell/spufs/context.c | 18 ++ .../cell/spufs/spu_restore_dump.h_shipped | 231 +++++++++++++++++++ .../platforms/cell/spufs/spu_save_dump.h_shipped | 191 +++++++++++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 2 + arch/powerpc/platforms/cell/spufs/switch.c | 174 ++++++++++++++ include/asm-powerpc/spu.h | 76 ++++++ include/asm-powerpc/spu_csa.h | 256 +++++++++++++++++++++ 9 files changed, 975 insertions(+), 4 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped create mode 100644 arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped create mode 100644 arch/powerpc/platforms/cell/spufs/switch.c create mode 100644 include/asm-powerpc/spu_csa.h diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 9e9096590a07..44492d87cdf7 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -62,7 +62,9 @@ static int __spu_trap_error(struct spu *spu) static void spu_restart_dma(struct spu *spu) { struct spu_priv2 __iomem *priv2 = spu->priv2; - out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); + + if (!test_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags)) + out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); } static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) @@ -72,6 +74,11 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) pr_debug("%s\n", __FUNCTION__); + if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) { + printk("%s: invalid access during switch!\n", __func__); + return 1; + } + if (REGION_ID(ea) != USER_REGION_ID) { pr_debug("invalid region access at %016lx\n", ea); return 1; @@ -98,6 +105,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) return 0; } +extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX static int __spu_trap_data_map(struct spu *spu, unsigned long ea) { unsigned long dsisr; @@ -107,8 +115,21 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea) priv1 = spu->priv1; dsisr = in_be64(&priv1->mfc_dsisr_RW); - wake_up(&spu->stop_wq); + /* Handle kernel space hash faults immediately. + User hash faults need to be deferred to process context. */ + if ((dsisr & MFC_DSISR_PTE_NOT_FOUND) + && REGION_ID(ea) != USER_REGION_ID + && hash_page(ea, _PAGE_PRESENT, 0x300) == 0) { + spu_restart_dma(spu); + return 0; + } + + if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) { + printk("%s: invalid access during switch!\n", __func__); + return 1; + } + wake_up(&spu->stop_wq); return 0; } @@ -382,7 +403,6 @@ void spu_free(struct spu *spu) } EXPORT_SYMBOL(spu_free); -extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX static int spu_handle_mm_fault(struct spu *spu) { struct spu_priv1 __iomem *priv1; @@ -650,6 +670,7 @@ static int __init create_spu(struct device_node *spe) spu->slb_replace = 0; spu->mm = NULL; spu->class_0_pending = 0; + spu->flags = 0UL; spin_lock_init(&spu->register_lock); out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index 6f496e37bcb7..e70e3cc1158f 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_SPU_FS) += spufs.o -spufs-y += inode.o file.o context.o syscalls.o +spufs-y += inode.o file.o context.o switch.o syscalls.o + +$(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index a69b85e2778a..41eea4576b6d 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -22,6 +22,7 @@ #include #include +#include #include "spufs.h" struct spu_context *alloc_spu_context(void) @@ -30,9 +31,25 @@ struct spu_context *alloc_spu_context(void) ctx = kmalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) goto out; + /* Future enhancement: do not call spu_alloc() + * here. This step should be deferred until + * spu_run()!! + * + * More work needs to be done to read(), + * write(), mmap(), etc., so that operations + * are performed on CSA when the context is + * not currently being run. In this way we + * can support arbitrarily large number of + * entries in /spu, allow state queries, etc. + */ ctx->spu = spu_alloc(); if (!ctx->spu) goto out_free; + spu_init_csa(&ctx->csa); + if (!ctx->csa.lscsa) { + spu_free(ctx->spu); + goto out_free; + } init_rwsem(&ctx->backing_sema); spin_lock_init(&ctx->mmio_lock); kref_init(&ctx->kref); @@ -50,6 +67,7 @@ void destroy_spu_context(struct kref *kref) ctx = container_of(kref, struct spu_context, kref); if (ctx->spu) spu_free(ctx->spu); + spu_fini_csa(&ctx->csa); kfree(ctx); } diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped new file mode 100644 index 000000000000..1b2355ff7036 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped @@ -0,0 +1,231 @@ +/* + * spu_restore_dump.h: Copyright (C) 2005 IBM. + * Hex-dump auto generated from spu_restore.c. + * Do not edit! + */ +static unsigned int spu_restore_code[] __page_aligned = { +0x40800000, 0x409ff801, 0x24000080, 0x24fd8081, +0x1cd80081, 0x33001180, 0x42030003, 0x33800284, +0x1c010204, 0x40200000, 0x40200000, 0x40200000, +0x34000190, 0x34004191, 0x34008192, 0x3400c193, +0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffa85, +0x3080a000, 0x3080a201, 0x3080a402, 0x3080a603, +0x3080a804, 0x3080aa05, 0x3080ac06, 0x3080ae07, +0x3080b008, 0x3080b209, 0x3080b40a, 0x3080b60b, +0x3080b80c, 0x3080ba0d, 0x3080bc0e, 0x3080be0f, +0x00003ffc, 0x00000000, 0x00000000, 0x00000000, +0x01a00182, 0x3ec00083, 0xb0a14103, 0x01a00204, +0x3ec10082, 0x4202800e, 0x04000703, 0xb0a14202, +0x21a00803, 0x3fbf028d, 0x3f20068d, 0x3fbe0682, +0x3fe30102, 0x21a00882, 0x3f82028f, 0x3fe3078f, +0x3fbf0784, 0x3f200204, 0x3fbe0204, 0x3fe30204, +0x04000203, 0x21a00903, 0x40848002, 0x21a00982, +0x40800003, 0x21a00a03, 0x40802002, 0x21a00a82, +0x21a00083, 0x40800082, 0x21a00b02, 0x10002818, +0x40a80002, 0x32800007, 0x4207000c, 0x18008208, +0x40a0000b, 0x4080020a, 0x40800709, 0x00200000, +0x42070002, 0x3ac30384, 0x1cffc489, 0x00200000, +0x18008383, 0x38830382, 0x4cffc486, 0x3ac28185, +0xb0408584, 0x28830382, 0x1c020387, 0x38828182, +0xb0408405, 0x1802c408, 0x28828182, 0x217ff886, +0x04000583, 0x21a00803, 0x3fbe0682, 0x3fe30102, +0x04000106, 0x21a00886, 0x04000603, 0x21a00903, +0x40803c02, 0x21a00982, 0x40800003, 0x04000184, +0x21a00a04, 0x40802202, 0x21a00a82, 0x42028005, +0x34208702, 0x21002282, 0x21a00804, 0x21a00886, +0x3fbf0782, 0x3f200102, 0x3fbe0102, 0x3fe30102, +0x21a00902, 0x40804003, 0x21a00983, 0x21a00a04, +0x40805a02, 0x21a00a82, 0x40800083, 0x21a00b83, +0x01a00c02, 0x01a00d83, 0x3420c282, 0x21a00e02, +0x34210283, 0x21a00f03, 0x34200284, 0x77400200, +0x3421c282, 0x21a00702, 0x34218283, 0x21a00083, +0x34214282, 0x21a00b02, 0x4200480c, 0x00200000, +0x1c010286, 0x34220284, 0x34220302, 0x0f608203, +0x5c024204, 0x3b81810b, 0x42013c02, 0x00200000, +0x18008185, 0x38808183, 0x3b814182, 0x21004e84, +0x4020007f, 0x35000100, 0x000004e0, 0x000002a0, +0x000002e8, 0x00000428, 0x00000360, 0x000002e8, +0x000004a0, 0x00000468, 0x000003c8, 0x00000360, +0x409ffe02, 0x30801203, 0x40800204, 0x3ec40085, +0x10009c09, 0x3ac10606, 0xb060c105, 0x4020007f, +0x4020007f, 0x20801203, 0x38810602, 0xb0408586, +0x28810602, 0x32004180, 0x34204702, 0x21a00382, +0x4020007f, 0x327fdc80, 0x409ffe02, 0x30801203, +0x40800204, 0x3ec40087, 0x40800405, 0x00200000, +0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a, +0xb060c107, 0x20801203, 0x41004003, 0x38810602, +0x4020007f, 0xb0408188, 0x4020007f, 0x28810602, +0x41201002, 0x38814603, 0x10009c09, 0xb060c109, +0x4020007f, 0x28814603, 0x41193f83, 0x38818602, +0x60ffc003, 0xb040818a, 0x28818602, 0x32003080, +0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087, +0x41201008, 0x10009c14, 0x40800405, 0x3ac10609, +0x40800606, 0x3ac1460a, 0xb060c107, 0x3ac1860b, +0x20801203, 0x38810602, 0xb0408409, 0x28810602, +0x38814603, 0xb060c40a, 0x4020007f, 0x28814603, +0x41193f83, 0x38818602, 0x60ffc003, 0xb040818b, +0x28818602, 0x32002380, 0x409ffe02, 0x30801204, +0x40800205, 0x3ec40083, 0x40800406, 0x3ac14607, +0x3ac18608, 0xb0810103, 0x41004002, 0x20801204, +0x4020007f, 0x38814603, 0x10009c0b, 0xb060c107, +0x4020007f, 0x4020007f, 0x28814603, 0x38818602, +0x4020007f, 0x4020007f, 0xb0408588, 0x28818602, +0x4020007f, 0x32001780, 0x409ffe02, 0x1000640e, +0x40800204, 0x30801203, 0x40800405, 0x3ec40087, +0x40800606, 0x3ac10608, 0x3ac14609, 0x3ac1860a, +0xb060c107, 0x20801203, 0x413d8003, 0x38810602, +0x4020007f, 0x327fd780, 0x409ffe02, 0x10007f0c, +0x40800205, 0x30801204, 0x40800406, 0x3ec40083, +0x3ac14607, 0x3ac18608, 0xb0810103, 0x413d8002, +0x20801204, 0x38814603, 0x4020007f, 0x327feb80, +0x409ffe02, 0x30801203, 0x40800204, 0x3ec40087, +0x40800405, 0x1000650a, 0x40800606, 0x3ac10608, +0x3ac14609, 0x3ac1860a, 0xb060c107, 0x20801203, +0x38810602, 0xb0408588, 0x4020007f, 0x327fc980, +0x00400000, 0x40800003, 0x4020007f, 0x35000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped new file mode 100644 index 000000000000..39e54003f1df --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_save_dump.h_shipped @@ -0,0 +1,191 @@ +/* + * spu_save_dump.h: Copyright (C) 2005 IBM. + * Hex-dump auto generated from spu_save.c. + * Do not edit! + */ +static unsigned int spu_save_code[] __page_aligned = { +0x20805000, 0x20805201, 0x20805402, 0x20805603, +0x20805804, 0x20805a05, 0x20805c06, 0x20805e07, +0x20806008, 0x20806209, 0x2080640a, 0x2080660b, +0x2080680c, 0x20806a0d, 0x20806c0e, 0x20806e0f, +0x4201c003, 0x33800184, 0x1c010204, 0x40200000, +0x24000190, 0x24004191, 0x24008192, 0x2400c193, +0x141fc205, 0x23fffd84, 0x1c100183, 0x217ffb85, +0x40800000, 0x409ff801, 0x24000080, 0x24fd8081, +0x1cd80081, 0x33000180, 0x00000000, 0x00000000, +0x01a00182, 0x3ec00083, 0xb1c38103, 0x01a00204, +0x3ec10082, 0x4201400d, 0xb1c38202, 0x01a00583, +0x34218682, 0x3ed80684, 0xb0408184, 0x24218682, +0x01a00603, 0x00200000, 0x34214682, 0x3ed40684, +0xb0408184, 0x40800003, 0x24214682, 0x21a00083, +0x40800082, 0x21a00b02, 0x4020007f, 0x1000251e, +0x40a80002, 0x32800008, 0x4205c00c, 0x00200000, +0x40a0000b, 0x3f82070f, 0x4080020a, 0x40800709, +0x3fe3078f, 0x3fbf0783, 0x3f200183, 0x3fbe0183, +0x3fe30187, 0x18008387, 0x4205c002, 0x3ac30404, +0x1cffc489, 0x00200000, 0x18008403, 0x38830402, +0x4cffc486, 0x3ac28185, 0xb0408584, 0x28830402, +0x1c020408, 0x38828182, 0xb0408385, 0x1802c387, +0x28828182, 0x217ff886, 0x04000582, 0x32800007, +0x21a00802, 0x3fbf0705, 0x3f200285, 0x3fbe0285, +0x3fe30285, 0x21a00885, 0x04000603, 0x21a00903, +0x40803c02, 0x21a00982, 0x04000386, 0x21a00a06, +0x40801202, 0x21a00a82, 0x73000003, 0x24200683, +0x01a00404, 0x00200000, 0x34204682, 0x3ec40683, +0xb0408203, 0x24204682, 0x01a00783, 0x00200000, +0x3421c682, 0x3edc0684, 0xb0408184, 0x2421c682, +0x21a00806, 0x21a00885, 0x3fbf0784, 0x3f200204, +0x3fbe0204, 0x3fe30204, 0x21a00904, 0x40804002, +0x21a00982, 0x21a00a06, 0x40805a02, 0x21a00a82, +0x04000683, 0x21a00803, 0x21a00885, 0x21a00904, +0x40848002, 0x21a00982, 0x21a00a06, 0x40801002, +0x21a00a82, 0x21a00a06, 0x40806602, 0x00200000, +0x35800009, 0x21a00a82, 0x40800083, 0x21a00b83, +0x01a00c02, 0x01a00d83, 0x00003ffb, 0x40800003, +0x4020007f, 0x35000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index b37fe797ea1c..67aff57faf60 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -28,6 +28,7 @@ #include #include +#include /* The magic number for our file system */ enum { @@ -36,6 +37,7 @@ enum { struct spu_context { struct spu *spu; /* pointer to a physical SPU */ + struct spu_state csa; /* SPU context save area. */ struct rw_semaphore backing_sema; /* protects the above */ spinlock_t mmio_lock; /* protects mmio access */ diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c new file mode 100644 index 000000000000..6804342e99c3 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -0,0 +1,174 @@ +/* + * spu_switch.c + * + * (C) Copyright IBM Corp. 2005 + * + * Author: Mark Nutter + * + * Host-side part of SPU context switch sequence outlined in + * Synergistic Processor Element, Book IV. + * + * A fully premptive switch of an SPE is very expensive in terms + * of time and system resources. SPE Book IV indicates that SPE + * allocation should follow a "serially reusable device" model, + * in which the SPE is assigned a task until it completes. When + * this is not possible, this sequence may be used to premptively + * save, and then later (optionally) restore the context of a + * program executing on an SPE. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "spu_save_dump.h" +#include "spu_restore_dump.h" + +/** + * spu_save - SPU context save, with locking. + * @prev: pointer to SPU context save area, to be saved. + * @spu: pointer to SPU iomem structure. + * + * Acquire locks, perform the save operation then return. + */ +int spu_save(struct spu_state *prev, struct spu *spu) +{ + /* XXX missing */ + + return 0; +} + +/** + * spu_restore - SPU context restore, with harvest and locking. + * @new: pointer to SPU context save area, to be restored. + * @spu: pointer to SPU iomem structure. + * + * Perform harvest + restore, as we may not be coming + * from a previous succesful save operation, and the + * hardware state is unknown. + */ +int spu_restore(struct spu_state *new, struct spu *spu) +{ + /* XXX missing */ + + return 0; +} + +/** + * spu_switch - SPU context switch (save + restore). + * @prev: pointer to SPU context save area, to be saved. + * @new: pointer to SPU context save area, to be restored. + * @spu: pointer to SPU iomem structure. + * + * Perform save, then restore. Only harvest if the + * save fails, as cleanup is otherwise not needed. + */ +int spu_switch(struct spu_state *prev, struct spu_state *new, struct spu *spu) +{ + /* XXX missing */ + + return 0; +} + +static void init_prob(struct spu_state *csa) +{ + csa->spu_chnlcnt_RW[9] = 1; + csa->spu_chnlcnt_RW[21] = 16; + csa->spu_chnlcnt_RW[23] = 1; + csa->spu_chnlcnt_RW[28] = 1; + csa->spu_chnlcnt_RW[30] = 1; + csa->prob.spu_runcntl_RW = SPU_RUNCNTL_STOP; +} + +static void init_priv1(struct spu_state *csa) +{ + /* Enable decode, relocate, tlbie response, master runcntl. */ + csa->priv1.mfc_sr1_RW = MFC_STATE1_LOCAL_STORAGE_DECODE_MASK | + MFC_STATE1_MASTER_RUN_CONTROL_MASK | + MFC_STATE1_PROBLEM_STATE_MASK | + MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK; + + /* Set storage description. */ + csa->priv1.mfc_sdr_RW = mfspr(SPRN_SDR1); + + /* Enable OS-specific set of interrupts. */ + csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR | + CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR | + CLASS0_ENABLE_SPU_ERROR_INTR; + csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | + CLASS1_ENABLE_STORAGE_FAULT_INTR; + csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_MAILBOX_INTR | + CLASS2_ENABLE_SPU_STOP_INTR | CLASS2_ENABLE_SPU_HALT_INTR; +} + +static void init_priv2(struct spu_state *csa) +{ + csa->priv2.spu_lslr_RW = LS_ADDR_MASK; + csa->priv2.mfc_control_RW = MFC_CNTL_RESUME_DMA_QUEUE | + MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION | + MFC_CNTL_DMA_QUEUES_EMPTY_MASK; +} + +/** + * spu_alloc_csa - allocate and initialize an SPU context save area. + * + * Allocate and initialize the contents of an SPU context save area. + * This includes enabling address translation, interrupt masks, etc., + * as appropriate for the given OS environment. + * + * Note that storage for the 'lscsa' is allocated separately, + * as it is by far the largest of the context save regions, + * and may need to be pinned or otherwise specially aligned. + */ +void spu_init_csa(struct spu_state *csa) +{ + struct spu_lscsa *lscsa; + + if (!csa) + return; + memset(csa, 0, sizeof(struct spu_state)); + + lscsa = vmalloc(sizeof(struct spu_lscsa)); + if (!lscsa) + return; + + memset(lscsa, 0, sizeof(struct spu_lscsa)); + csa->lscsa = lscsa; + + init_prob(csa); + init_priv1(csa); + init_priv2(csa); +} + +void spu_fini_csa(struct spu_state *csa) +{ + vfree(csa->lscsa); +} diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index b036385cd831..62718f3ba03f 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -29,6 +29,81 @@ #define LS_ORDER (6) /* 256 kb */ #define LS_SIZE (PAGE_SIZE << LS_ORDER) +#define LS_ADDR_MASK (LS_SIZE - 1) + +#define MFC_PUT_CMD 0x20 +#define MFC_PUTS_CMD 0x28 +#define MFC_PUTR_CMD 0x30 +#define MFC_PUTF_CMD 0x22 +#define MFC_PUTB_CMD 0x21 +#define MFC_PUTFS_CMD 0x2A +#define MFC_PUTBS_CMD 0x29 +#define MFC_PUTRF_CMD 0x32 +#define MFC_PUTRB_CMD 0x31 +#define MFC_PUTL_CMD 0x24 +#define MFC_PUTRL_CMD 0x34 +#define MFC_PUTLF_CMD 0x26 +#define MFC_PUTLB_CMD 0x25 +#define MFC_PUTRLF_CMD 0x36 +#define MFC_PUTRLB_CMD 0x35 + +#define MFC_GET_CMD 0x40 +#define MFC_GETS_CMD 0x48 +#define MFC_GETF_CMD 0x42 +#define MFC_GETB_CMD 0x41 +#define MFC_GETFS_CMD 0x4A +#define MFC_GETBS_CMD 0x49 +#define MFC_GETL_CMD 0x44 +#define MFC_GETLF_CMD 0x46 +#define MFC_GETLB_CMD 0x45 + +#define MFC_SDCRT_CMD 0x80 +#define MFC_SDCRTST_CMD 0x81 +#define MFC_SDCRZ_CMD 0x89 +#define MFC_SDCRS_CMD 0x8D +#define MFC_SDCRF_CMD 0x8F + +#define MFC_GETLLAR_CMD 0xD0 +#define MFC_PUTLLC_CMD 0xB4 +#define MFC_PUTLLUC_CMD 0xB0 +#define MFC_PUTQLLUC_CMD 0xB8 +#define MFC_SNDSIG_CMD 0xA0 +#define MFC_SNDSIGB_CMD 0xA1 +#define MFC_SNDSIGF_CMD 0xA2 +#define MFC_BARRIER_CMD 0xC0 +#define MFC_EIEIO_CMD 0xC8 +#define MFC_SYNC_CMD 0xCC + +#define MFC_MIN_DMA_SIZE_SHIFT 4 /* 16 bytes */ +#define MFC_MAX_DMA_SIZE_SHIFT 14 /* 16384 bytes */ +#define MFC_MIN_DMA_SIZE (1 << MFC_MIN_DMA_SIZE_SHIFT) +#define MFC_MAX_DMA_SIZE (1 << MFC_MAX_DMA_SIZE_SHIFT) +#define MFC_MIN_DMA_SIZE_MASK (MFC_MIN_DMA_SIZE - 1) +#define MFC_MAX_DMA_SIZE_MASK (MFC_MAX_DMA_SIZE - 1) +#define MFC_MIN_DMA_LIST_SIZE 0x0008 /* 8 bytes */ +#define MFC_MAX_DMA_LIST_SIZE 0x4000 /* 16K bytes */ + +#define MFC_TAGID_TO_TAGMASK(tag_id) (1 << (tag_id & 0x1F)) + +/* Events for Channels 0-2 */ +#define MFC_DMA_TAG_STATUS_UPDATE_EVENT 0x00000001 +#define MFC_DMA_TAG_CMD_STALL_NOTIFY_EVENT 0x00000002 +#define MFC_DMA_QUEUE_AVAILABLE_EVENT 0x00000008 +#define MFC_SPU_MAILBOX_WRITTEN_EVENT 0x00000010 +#define MFC_DECREMENTER_EVENT 0x00000020 +#define MFC_PU_INT_MAILBOX_AVAILABLE_EVENT 0x00000040 +#define MFC_PU_MAILBOX_AVAILABLE_EVENT 0x00000080 +#define MFC_SIGNAL_2_EVENT 0x00000100 +#define MFC_SIGNAL_1_EVENT 0x00000200 +#define MFC_LLR_LOST_EVENT 0x00000400 +#define MFC_PRIV_ATTN_EVENT 0x00000800 +#define MFC_MULTI_SRC_EVENT 0x00001000 + +/* Flags indicating progress during context switch. */ +#define SPU_CONTEXT_SWITCH_PENDING_nr 0UL +#define SPU_CONTEXT_SWITCH_ACTIVE_nr 1UL +#define SPU_CONTEXT_SWITCH_PENDING (1UL << SPU_CONTEXT_SWITCH_PENDING_nr) +#define SPU_CONTEXT_SWITCH_ACTIVE (1UL << SPU_CONTEXT_SWITCH_ACTIVE_nr) struct spu { char *name; @@ -41,6 +116,7 @@ struct spu { int number; u32 isrc; u32 node; + u64 flags; struct kref kref; size_t ls_size; unsigned int slb_replace; diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h new file mode 100644 index 000000000000..d1d537de4f5c --- /dev/null +++ b/include/asm-powerpc/spu_csa.h @@ -0,0 +1,256 @@ +/* + * spu_csa.h: Definitions for SPU context save area (CSA). + * + * (C) Copyright IBM 2005 + * + * Author: Mark Nutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _SPU_CSA_H_ +#define _SPU_CSA_H_ + +/* + * Total number of 128-bit registers. + */ +#define NR_SPU_GPRS 128 +#define NR_SPU_SPRS 9 +#define NR_SPU_REGS_PAD 7 +#define NR_SPU_SPILL_REGS 144 /* GPRS + SPRS + PAD */ +#define SIZEOF_SPU_SPILL_REGS NR_SPU_SPILL_REGS * 16 + +#define SPU_SAVE_COMPLETE 0x3FFB +#define SPU_RESTORE_COMPLETE 0x3FFC + +/* + * Definitions for various 'stopped' status conditions, + * to be recreated during context restore. + */ +#define SPU_STOPPED_STATUS_P 1 +#define SPU_STOPPED_STATUS_I 2 +#define SPU_STOPPED_STATUS_H 3 +#define SPU_STOPPED_STATUS_S 4 +#define SPU_STOPPED_STATUS_S_I 5 +#define SPU_STOPPED_STATUS_S_P 6 +#define SPU_STOPPED_STATUS_P_H 7 +#define SPU_STOPPED_STATUS_P_I 8 +#define SPU_STOPPED_STATUS_R 9 + +#ifndef __ASSEMBLY__ +/** + * spu_reg128 - generic 128-bit register definition. + */ +struct spu_reg128 { + u32 slot[4]; +}; + +/** + * struct spu_lscsa - Local Store Context Save Area. + * @gprs: Array of saved registers. + * @fpcr: Saved floating point status control register. + * @decr: Saved decrementer value. + * @decr_status: Indicates decrementer run status. + * @ppu_mb: Saved PPU mailbox data. + * @ppuint_mb: Saved PPU interrupting mailbox data. + * @tag_mask: Saved tag group mask. + * @event_mask: Saved event mask. + * @srr0: Saved SRR0. + * @stopped_status: Conditions to be recreated by restore. + * @ls: Saved contents of Local Storage Area. + * + * The LSCSA represents state that is primarily saved and + * restored by SPU-side code. + */ +struct spu_lscsa { + struct spu_reg128 gprs[128]; + struct spu_reg128 fpcr; + struct spu_reg128 decr; + struct spu_reg128 decr_status; + struct spu_reg128 ppu_mb; + struct spu_reg128 ppuint_mb; + struct spu_reg128 tag_mask; + struct spu_reg128 event_mask; + struct spu_reg128 srr0; + struct spu_reg128 stopped_status; + struct spu_reg128 pad[119]; /* 'ls' must be page-aligned. */ + unsigned char ls[LS_SIZE]; +}; + +#ifdef __KERNEL__ + +/* + * struct spu_problem_collapsed - condensed problem state area, w/o pads. + */ +struct spu_problem_collapsed { + u64 spc_mssync_RW; + u32 mfc_lsa_W; + u32 unused_pad0; + u64 mfc_ea_W; + union mfc_tag_size_class_cmd mfc_union_W; + u32 dma_qstatus_R; + u32 dma_querytype_RW; + u32 dma_querymask_RW; + u32 dma_tagstatus_R; + u32 pu_mb_R; + u32 spu_mb_W; + u32 mb_stat_R; + u32 spu_runcntl_RW; + u32 spu_status_R; + u32 spu_spc_R; + u32 spu_npc_RW; + u32 signal_notify1; + u32 signal_notify2; + u32 unused_pad1; +}; + +/* + * struct spu_priv1_collapsed - condensed privileged 1 area, w/o pads. + */ +struct spu_priv1_collapsed { + u64 mfc_sr1_RW; + u64 mfc_lpid_RW; + u64 spu_idr_RW; + u64 mfc_vr_RO; + u64 spu_vr_RO; + u64 int_mask_class0_RW; + u64 int_mask_class1_RW; + u64 int_mask_class2_RW; + u64 int_stat_class0_RW; + u64 int_stat_class1_RW; + u64 int_stat_class2_RW; + u64 int_route_RW; + u64 mfc_atomic_flush_RW; + u64 resource_allocation_groupID_RW; + u64 resource_allocation_enable_RW; + u64 mfc_fir_R; + u64 mfc_fir_status_or_W; + u64 mfc_fir_status_and_W; + u64 mfc_fir_mask_R; + u64 mfc_fir_mask_or_W; + u64 mfc_fir_mask_and_W; + u64 mfc_fir_chkstp_enable_RW; + u64 smf_sbi_signal_sel; + u64 smf_ato_signal_sel; + u64 mfc_sdr_RW; + u64 tlb_index_hint_RO; + u64 tlb_index_W; + u64 tlb_vpn_RW; + u64 tlb_rpn_RW; + u64 tlb_invalidate_entry_W; + u64 tlb_invalidate_all_W; + u64 smm_hid; + u64 mfc_accr_RW; + u64 mfc_dsisr_RW; + u64 mfc_dar_RW; + u64 rmt_index_RW; + u64 rmt_data1_RW; + u64 mfc_dsir_R; + u64 mfc_lsacr_RW; + u64 mfc_lscrr_R; + u64 mfc_tclass_id_RW; + u64 mfc_rm_boundary; + u64 smf_dma_signal_sel; + u64 smm_signal_sel; + u64 mfc_cer_R; + u64 pu_ecc_cntl_RW; + u64 pu_ecc_stat_RW; + u64 spu_ecc_addr_RW; + u64 spu_err_mask_RW; + u64 spu_trig0_sel; + u64 spu_trig1_sel; + u64 spu_trig2_sel; + u64 spu_trig3_sel; + u64 spu_trace_sel; + u64 spu_event0_sel; + u64 spu_event1_sel; + u64 spu_event2_sel; + u64 spu_event3_sel; + u64 spu_trace_cntl; +}; + +/* + * struct spu_priv2_collapsed - condensed priviliged 2 area, w/o pads. + */ +struct spu_priv2_collapsed { + u64 slb_index_W; + u64 slb_esid_RW; + u64 slb_vsid_RW; + u64 slb_invalidate_entry_W; + u64 slb_invalidate_all_W; + struct mfc_cq_sr spuq[16]; + struct mfc_cq_sr puq[8]; + u64 mfc_control_RW; + u64 puint_mb_R; + u64 spu_privcntl_RW; + u64 spu_lslr_RW; + u64 spu_chnlcntptr_RW; + u64 spu_chnlcnt_RW; + u64 spu_chnldata_RW; + u64 spu_cfg_RW; + u64 spu_pm_trace_tag_status_RW; + u64 spu_tag_status_query_RW; + u64 spu_cmd_buf1_RW; + u64 spu_cmd_buf2_RW; + u64 spu_atomic_status_RW; +}; + +/** + * struct spu_state + * @lscsa: Local Store Context Save Area. + * @prob: Collapsed Problem State Area, w/o pads. + * @priv1: Collapsed Privileged 1 Area, w/o pads. + * @priv2: Collapsed Privileged 2 Area, w/o pads. + * @spu_chnlcnt_RW: Array of saved channel counts. + * @spu_chnldata_RW: Array of saved channel data. + * @suspend_time: Time stamp when decrementer disabled. + * @slb_esid_RW: Array of saved SLB esid entries. + * @slb_vsid_RW: Array of saved SLB vsid entries. + * + * Structure representing the whole of the SPU + * context save area (CSA). This struct contains + * all of the state necessary to suspend and then + * later optionally resume execution of an SPU + * context. + * + * The @lscsa region is by far the largest, and is + * allocated separately so that it may either be + * pinned or mapped to/from application memory, as + * appropriate for the OS environment. + */ +struct spu_state { + struct spu_lscsa *lscsa; + struct spu_problem_collapsed prob; + struct spu_priv1_collapsed priv1; + struct spu_priv2_collapsed priv2; + u64 spu_chnlcnt_RW[32]; + u64 spu_chnldata_RW[32]; + u32 spu_mailbox_data[4]; + u32 pu_mailbox_data[1]; + unsigned long suspend_time; + u64 slb_esid_RW[8]; + u64 slb_vsid_RW[8]; +}; + +extern void spu_init_csa(struct spu_state *csa); +extern void spu_fini_csa(struct spu_state *csa); +extern int spu_save(struct spu_state *prev, struct spu *spu); +extern int spu_restore(struct spu_state *new, struct spu *spu); +extern int spu_switch(struct spu_state *prev, struct spu_state *new, + struct spu *spu); + +#endif /* __KERNEL__ */ +#endif /* !__ASSEMBLY__ */ +#endif /* _SPU_CSA_H_ */ -- cgit v1.2.3 From 7c038749d1e6a2d5fb37ed14aed0fffa34c4e504 Mon Sep 17 00:00:00 2001 From: Mark Nutter Date: Tue, 15 Nov 2005 15:53:50 -0500 Subject: [PATCH] kernel-side context switch code for spufs This adds the code needed to perform a context switch from spufs, following the recommended 76-step sequence. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/switch.c | 2042 +++++++++++++++++++++++++++- include/asm-powerpc/spu_csa.h | 1 - 2 files changed, 2036 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 6804342e99c3..70345b0524fc 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -52,6 +52,2019 @@ #include "spu_save_dump.h" #include "spu_restore_dump.h" +#if 0 +#define POLL_WHILE_TRUE(_c) { \ + do { \ + } while (_c); \ + } +#else +#define RELAX_SPIN_COUNT 1000 +#define POLL_WHILE_TRUE(_c) { \ + do { \ + int _i; \ + for (_i=0; _iproblem; + u32 isolate_state; + + /* Save, Step 2: + * Save, Step 6: + * If SPU_Status[E,L,IS] any field is '1', this + * SPU is in isolate state and cannot be context + * saved at this time. + */ + isolate_state = SPU_STATUS_ISOLATED_STATE | + SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS; + return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0; +} + +static inline void disable_interrupts(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 3: + * Restore, Step 2: + * Save INT_Mask_class0 in CSA. + * Write INT_MASK_class0 with value of 0. + * Save INT_Mask_class1 in CSA. + * Write INT_MASK_class1 with value of 0. + * Save INT_Mask_class2 in CSA. + * Write INT_MASK_class2 with value of 0. + */ + spin_lock_irq(&spu->register_lock); + if (csa) { + csa->priv1.int_mask_class0_RW = + in_be64(&priv1->int_mask_class0_RW); + csa->priv1.int_mask_class1_RW = + in_be64(&priv1->int_mask_class1_RW); + csa->priv1.int_mask_class2_RW = + in_be64(&priv1->int_mask_class2_RW); + } + out_be64(&priv1->int_mask_class0_RW, 0UL); + out_be64(&priv1->int_mask_class1_RW, 0UL); + out_be64(&priv1->int_mask_class2_RW, 0UL); + eieio(); + spin_unlock_irq(&spu->register_lock); +} + +static inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu) +{ + /* Save, Step 4: + * Restore, Step 25. + * Set a software watchdog timer, which specifies the + * maximum allowable time for a context save sequence. + * + * For present, this implementation will not set a global + * watchdog timer, as virtualization & variable system load + * may cause unpredictable execution times. + */ +} + +static inline void inhibit_user_access(struct spu_state *csa, struct spu *spu) +{ + /* Save, Step 5: + * Restore, Step 3: + * Inhibit user-space access (if provided) to this + * SPU by unmapping the virtual pages assigned to + * the SPU memory-mapped I/O (MMIO) for problem + * state. TBD. + */ +} + +static inline void set_switch_pending(struct spu_state *csa, struct spu *spu) +{ + /* Save, Step 7: + * Restore, Step 5: + * Set a software context switch pending flag. + */ + set_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags); + mb(); +} + +static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 8: + * Read and save MFC_CNTL[Ss]. + */ + if (csa) { + csa->priv2.mfc_control_RW = in_be64(&priv2->mfc_control_RW) & + MFC_CNTL_SUSPEND_DMA_STATUS_MASK; + } +} + +static inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 9: + * Save SPU_Runcntl in the CSA. This value contains + * the "Application Desired State". + */ + csa->prob.spu_runcntl_RW = in_be32(&prob->spu_runcntl_RW); +} + +static inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 10: + * Save MFC_SR1 in the CSA. + */ + csa->priv1.mfc_sr1_RW = in_be64(&priv1->mfc_sr1_RW); +} + +static inline void save_spu_status(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 11: + * Read SPU_Status[R], and save to CSA. + */ + if ((in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) == 0) { + csa->prob.spu_status_R = in_be32(&prob->spu_status_R); + } else { + u32 stopped; + + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + stopped = + SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | + SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; + if ((in_be32(&prob->spu_status_R) & stopped) == 0) + csa->prob.spu_status_R = SPU_STATUS_RUNNING; + else + csa->prob.spu_status_R = in_be32(&prob->spu_status_R); + } +} + +static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 12: + * Read MFC_CNTL[Ds]. Update saved copy of + * CSA.MFC_CNTL[Ds]. + */ + if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) { + csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; + csa->suspend_time = get_cycles(); + out_be64(&priv2->spu_chnlcntptr_RW, 7ULL); + eieio(); + csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW); + eieio(); + } +} + +static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 13: + * Write MFC_CNTL[Dh] set to a '1' to halt + * the decrementer. + */ + out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED); + eieio(); +} + +static inline void save_timebase(struct spu_state *csa, struct spu *spu) +{ + /* Save, Step 14: + * Read PPE Timebase High and Timebase low registers + * and save in CSA. TBD. + */ + csa->suspend_time = get_cycles(); +} + +static inline void remove_other_spu_access(struct spu_state *csa, + struct spu *spu) +{ + /* Save, Step 15: + * Remove other SPU access to this SPU by unmapping + * this SPU's pages from their address space. TBD. + */ +} + +static inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 16: + * Restore, Step 11. + * Write SPU_MSSync register. Poll SPU_MSSync[P] + * for a value of 0. + */ + out_be64(&prob->spc_mssync_RW, 1UL); + POLL_WHILE_TRUE(in_be64(&prob->spc_mssync_RW) & MS_SYNC_PENDING); +} + +static inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 17: + * Restore, Step 12. + * Restore, Step 48. + * Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register. + * Then issue a PPE sync instruction. + */ + out_be64(&priv1->tlb_invalidate_entry_W, 0UL); + mb(); +} + +static inline void handle_pending_interrupts(struct spu_state *csa, + struct spu *spu) +{ + /* Save, Step 18: + * Handle any pending interrupts from this SPU + * here. This is OS or hypervisor specific. One + * option is to re-enable interrupts to handle any + * pending interrupts, with the interrupt handlers + * recognizing the software Context Switch Pending + * flag, to ensure the SPU execution or MFC command + * queue is not restarted. TBD. + */ +} + +static inline void save_mfc_queues(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + int i; + + /* Save, Step 19: + * If MFC_Cntl[Se]=0 then save + * MFC command queues. + */ + if ((in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DMA_QUEUES_EMPTY) == 0) { + for (i = 0; i < 8; i++) { + csa->priv2.puq[i].mfc_cq_data0_RW = + in_be64(&priv2->puq[i].mfc_cq_data0_RW); + csa->priv2.puq[i].mfc_cq_data1_RW = + in_be64(&priv2->puq[i].mfc_cq_data1_RW); + csa->priv2.puq[i].mfc_cq_data2_RW = + in_be64(&priv2->puq[i].mfc_cq_data2_RW); + csa->priv2.puq[i].mfc_cq_data3_RW = + in_be64(&priv2->puq[i].mfc_cq_data3_RW); + } + for (i = 0; i < 16; i++) { + csa->priv2.spuq[i].mfc_cq_data0_RW = + in_be64(&priv2->spuq[i].mfc_cq_data0_RW); + csa->priv2.spuq[i].mfc_cq_data1_RW = + in_be64(&priv2->spuq[i].mfc_cq_data1_RW); + csa->priv2.spuq[i].mfc_cq_data2_RW = + in_be64(&priv2->spuq[i].mfc_cq_data2_RW); + csa->priv2.spuq[i].mfc_cq_data3_RW = + in_be64(&priv2->spuq[i].mfc_cq_data3_RW); + } + } +} + +static inline void save_ppu_querymask(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 20: + * Save the PPU_QueryMask register + * in the CSA. + */ + csa->prob.dma_querymask_RW = in_be32(&prob->dma_querymask_RW); +} + +static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 21: + * Save the PPU_QueryType register + * in the CSA. + */ + csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW); +} + +static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 22: + * Save the MFC_CSR_TSQ register + * in the LSCSA. + */ + csa->priv2.spu_tag_status_query_RW = + in_be64(&priv2->spu_tag_status_query_RW); +} + +static inline void save_mfc_csr_cmd(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 23: + * Save the MFC_CSR_CMD1 and MFC_CSR_CMD2 + * registers in the CSA. + */ + csa->priv2.spu_cmd_buf1_RW = in_be64(&priv2->spu_cmd_buf1_RW); + csa->priv2.spu_cmd_buf2_RW = in_be64(&priv2->spu_cmd_buf2_RW); +} + +static inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 24: + * Save the MFC_CSR_ATO register in + * the CSA. + */ + csa->priv2.spu_atomic_status_RW = in_be64(&priv2->spu_atomic_status_RW); +} + +static inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 25: + * Save the MFC_TCLASS_ID register in + * the CSA. + */ + csa->priv1.mfc_tclass_id_RW = in_be64(&priv1->mfc_tclass_id_RW); +} + +static inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 26: + * Restore, Step 23. + * Write the MFC_TCLASS_ID register with + * the value 0x10000000. + */ + out_be64(&priv1->mfc_tclass_id_RW, 0x10000000); + eieio(); +} + +static inline void purge_mfc_queue(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 27: + * Restore, Step 14. + * Write MFC_CNTL[Pc]=1 (purge queue). + */ + out_be64(&priv2->mfc_control_RW, MFC_CNTL_PURGE_DMA_REQUEST); + eieio(); +} + +static inline void wait_purge_complete(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 28: + * Poll MFC_CNTL[Ps] until value '11' is read + * (purge complete). + */ + POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) & + MFC_CNTL_PURGE_DMA_COMPLETE); +} + +static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + struct spu_priv2 __iomem *priv2 = spu->priv2; + int i; + + /* Save, Step 29: + * If MFC_SR1[R]='1', save SLBs in CSA. + */ + if (in_be64(&priv1->mfc_sr1_RW) & MFC_STATE1_RELOCATE_MASK) { + csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W); + for (i = 0; i < 8; i++) { + out_be64(&priv2->slb_index_W, i); + eieio(); + csa->slb_esid_RW[i] = in_be64(&priv2->slb_esid_RW); + csa->slb_vsid_RW[i] = in_be64(&priv2->slb_vsid_RW); + eieio(); + } + } +} + +static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 30: + * Restore, Step 18: + * Write MFC_SR1 with MFC_SR1[D=0,S=1] and + * MFC_SR1[TL,R,Pr,T] set correctly for the + * OS specific environment. + * + * Implementation note: The SPU-side code + * for save/restore is privileged, so the + * MFC_SR1[Pr] bit is not set. + * + */ + out_be64(&priv1->mfc_sr1_RW, (MFC_STATE1_MASTER_RUN_CONTROL_MASK | + MFC_STATE1_RELOCATE_MASK | + MFC_STATE1_BUS_TLBIE_MASK)); +} + +static inline void save_spu_npc(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 31: + * Save SPU_NPC in the CSA. + */ + csa->prob.spu_npc_RW = in_be32(&prob->spu_npc_RW); +} + +static inline void save_spu_privcntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 32: + * Save SPU_PrivCntl in the CSA. + */ + csa->priv2.spu_privcntl_RW = in_be64(&priv2->spu_privcntl_RW); +} + +static inline void reset_spu_privcntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 33: + * Restore, Step 16: + * Write SPU_PrivCntl[S,Le,A] fields reset to 0. + */ + out_be64(&priv2->spu_privcntl_RW, 0UL); + eieio(); +} + +static inline void save_spu_lslr(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 34: + * Save SPU_LSLR in the CSA. + */ + csa->priv2.spu_lslr_RW = in_be64(&priv2->spu_lslr_RW); +} + +static inline void reset_spu_lslr(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 35: + * Restore, Step 17. + * Reset SPU_LSLR. + */ + out_be64(&priv2->spu_lslr_RW, LS_ADDR_MASK); + eieio(); +} + +static inline void save_spu_cfg(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 36: + * Save SPU_Cfg in the CSA. + */ + csa->priv2.spu_cfg_RW = in_be64(&priv2->spu_cfg_RW); +} + +static inline void save_pm_trace(struct spu_state *csa, struct spu *spu) +{ + /* Save, Step 37: + * Save PM_Trace_Tag_Wait_Mask in the CSA. + * Not performed by this implementation. + */ +} + +static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Save, Step 38: + * Save RA_GROUP_ID register and the + * RA_ENABLE reigster in the CSA. + */ + csa->priv1.resource_allocation_groupID_RW = + in_be64(&priv1->resource_allocation_groupID_RW); + csa->priv1.resource_allocation_enable_RW = + in_be64(&priv1->resource_allocation_enable_RW); +} + +static inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 39: + * Save MB_Stat register in the CSA. + */ + csa->prob.mb_stat_R = in_be32(&prob->mb_stat_R); +} + +static inline void save_ppu_mb(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 40: + * Save the PPU_MB register in the CSA. + */ + csa->prob.pu_mb_R = in_be32(&prob->pu_mb_R); +} + +static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 41: + * Save the PPUINT_MB register in the CSA. + */ + csa->priv2.puint_mb_R = in_be64(&priv2->puint_mb_R); +} + +static inline void save_ch_part1(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL }; + int i; + + /* Save, Step 42: + * Save the following CH: [0,1,3,4,24,25,27] + */ + for (i = 0; i < 7; i++) { + idx = ch_indices[i]; + out_be64(&priv2->spu_chnlcntptr_RW, idx); + eieio(); + csa->spu_chnldata_RW[idx] = in_be64(&priv2->spu_chnldata_RW); + csa->spu_chnlcnt_RW[idx] = in_be64(&priv2->spu_chnlcnt_RW); + out_be64(&priv2->spu_chnldata_RW, 0UL); + out_be64(&priv2->spu_chnlcnt_RW, 0UL); + eieio(); + } +} + +static inline void save_spu_mb(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + int i; + + /* Save, Step 43: + * Save SPU Read Mailbox Channel. + */ + out_be64(&priv2->spu_chnlcntptr_RW, 29UL); + eieio(); + csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW); + for (i = 0; i < 4; i++) { + csa->pu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW); + } + out_be64(&priv2->spu_chnlcnt_RW, 0UL); + eieio(); +} + +static inline void save_mfc_cmd(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 44: + * Save MFC_CMD Channel. + */ + out_be64(&priv2->spu_chnlcntptr_RW, 21UL); + eieio(); + csa->spu_chnlcnt_RW[21] = in_be64(&priv2->spu_chnlcnt_RW); + eieio(); +} + +static inline void reset_ch(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 ch_indices[4] = { 21UL, 23UL, 28UL, 30UL }; + u64 ch_counts[4] = { 16UL, 1UL, 1UL, 1UL }; + u64 idx; + int i; + + /* Save, Step 45: + * Reset the following CH: [21, 23, 28, 30] + */ + for (i = 0; i < 4; i++) { + idx = ch_indices[i]; + out_be64(&priv2->spu_chnlcntptr_RW, idx); + eieio(); + out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); + eieio(); + } +} + +static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 46: + * Restore, Step 25. + * Write MFC_CNTL[Sc]=0 (resume queue processing). + */ + out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE); +} + +static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Save, Step 45: + * Restore, Step 19: + * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All. + */ + if (in_be64(&priv1->mfc_sr1_RW) & MFC_STATE1_RELOCATE_MASK) { + out_be64(&priv2->slb_invalidate_all_W, 0UL); + eieio(); + } +} + +static inline void get_kernel_slb(u64 ea, u64 slb[2]) +{ + slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; + slb[1] = (ea & ESID_MASK) | SLB_ESID_V; + + /* Large pages are used for kernel text/data, but not vmalloc. */ + if (cpu_has_feature(CPU_FTR_16M_PAGE) + && REGION_ID(ea) == KERNEL_REGION_ID) + slb[0] |= SLB_VSID_L; +} + +static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + out_be64(&priv2->slb_index_W, slbe); + eieio(); + out_be64(&priv2->slb_vsid_RW, slb[0]); + out_be64(&priv2->slb_esid_RW, slb[1]); + eieio(); +} + +static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu) +{ + u64 code_slb[2]; + u64 lscsa_slb[2]; + + /* Save, Step 47: + * Restore, Step 30. + * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All + * register, then initialize SLB_VSID and SLB_ESID + * to provide access to SPU context save code and + * LSCSA. + * + * This implementation places both the context + * switch code and LSCSA in kernel address space. + * + * Further this implementation assumes that the + * MFC_SR1[R]=1 (in other words, assume that + * translation is desired by OS environment). + */ + invalidate_slbs(csa, spu); + get_kernel_slb((unsigned long)&spu_save_code[0], code_slb); + get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb); + load_mfc_slb(spu, code_slb, 0); + if ((lscsa_slb[0] != code_slb[0]) || (lscsa_slb[1] != code_slb[1])) + load_mfc_slb(spu, lscsa_slb, 1); +} + +static inline void set_switch_active(struct spu_state *csa, struct spu *spu) +{ + /* Save, Step 48: + * Restore, Step 23. + * Change the software context switch pending flag + * to context switch active. + */ + set_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags); + clear_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags); + mb(); +} + +static inline void enable_interrupts(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR | + CLASS1_ENABLE_STORAGE_FAULT_INTR; + + /* Save, Step 49: + * Restore, Step 22: + * Reset and then enable interrupts, as + * needed by OS. + * + * This implementation enables only class1 + * (translation) interrupts. + */ + spin_lock_irq(&spu->register_lock); + out_be64(&priv1->int_stat_class0_RW, ~(0UL)); + out_be64(&priv1->int_stat_class1_RW, ~(0UL)); + out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + out_be64(&priv1->int_mask_class0_RW, 0UL); + out_be64(&priv1->int_mask_class1_RW, class1_mask); + out_be64(&priv1->int_mask_class2_RW, 0UL); + spin_unlock_irq(&spu->register_lock); +} + +static inline int send_mfc_dma(struct spu *spu, unsigned long ea, + unsigned int ls_offset, unsigned int size, + unsigned int tag, unsigned int rclass, + unsigned int cmd) +{ + struct spu_problem __iomem *prob = spu->problem; + union mfc_tag_size_class_cmd command; + unsigned int transfer_size; + volatile unsigned int status = 0x0; + + while (size > 0) { + transfer_size = + (size > MFC_MAX_DMA_SIZE) ? MFC_MAX_DMA_SIZE : size; + command.u.mfc_size = transfer_size; + command.u.mfc_tag = tag; + command.u.mfc_rclassid = rclass; + command.u.mfc_cmd = cmd; + do { + out_be32(&prob->mfc_lsa_W, ls_offset); + out_be64(&prob->mfc_ea_W, ea); + out_be64(&prob->mfc_union_W.all64, command.all64); + status = + in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32); + if (unlikely(status & 0x2)) { + cpu_relax(); + } + } while (status & 0x3); + size -= transfer_size; + ea += transfer_size; + ls_offset += transfer_size; + } + return 0; +} + +static inline void save_ls_16kb(struct spu_state *csa, struct spu *spu) +{ + unsigned long addr = (unsigned long)&csa->lscsa->ls[0]; + unsigned int ls_offset = 0x0; + unsigned int size = 16384; + unsigned int tag = 0; + unsigned int rclass = 0; + unsigned int cmd = MFC_PUT_CMD; + + /* Save, Step 50: + * Issue a DMA command to copy the first 16K bytes + * of local storage to the CSA. + */ + send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); +} + +static inline void set_spu_npc(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 51: + * Restore, Step 31. + * Write SPU_NPC[IE]=0 and SPU_NPC[LSA] to entry + * point address of context save code in local + * storage. + * + * This implementation uses SPU-side save/restore + * programs with entry points at LSA of 0. + */ + out_be32(&prob->spu_npc_RW, 0); + eieio(); +} + +static inline void set_signot1(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + union { + u64 ull; + u32 ui[2]; + } addr64; + + /* Save, Step 52: + * Restore, Step 32: + * Write SPU_Sig_Notify_1 register with upper 32-bits + * of the CSA.LSCSA effective address. + */ + addr64.ull = (u64) csa->lscsa; + out_be32(&prob->signal_notify1, addr64.ui[0]); + eieio(); +} + +static inline void set_signot2(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + union { + u64 ull; + u32 ui[2]; + } addr64; + + /* Save, Step 53: + * Restore, Step 33: + * Write SPU_Sig_Notify_2 register with lower 32-bits + * of the CSA.LSCSA effective address. + */ + addr64.ull = (u64) csa->lscsa; + out_be32(&prob->signal_notify2, addr64.ui[1]); + eieio(); +} + +static inline void send_save_code(struct spu_state *csa, struct spu *spu) +{ + unsigned long addr = (unsigned long)&spu_save_code[0]; + unsigned int ls_offset = 0x0; + unsigned int size = sizeof(spu_save_code); + unsigned int tag = 0; + unsigned int rclass = 0; + unsigned int cmd = MFC_GETFS_CMD; + + /* Save, Step 54: + * Issue a DMA command to copy context save code + * to local storage and start SPU. + */ + send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); +} + +static inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save, Step 55: + * Restore, Step 38. + * Write PPU_QueryMask=1 (enable Tag Group 0) + * and issue eieio instruction. + */ + out_be32(&prob->dma_querymask_RW, MFC_TAGID_TO_TAGMASK(0)); + eieio(); +} + +static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + struct spu_problem __iomem *prob = spu->problem; + u32 mask = MFC_TAGID_TO_TAGMASK(0); + unsigned long flags; + + /* Save, Step 56: + * Restore, Step 39. + * Restore, Step 39. + * Restore, Step 46. + * Poll PPU_TagStatus[gn] until 01 (Tag group 0 complete) + * or write PPU_QueryType[TS]=01 and wait for Tag Group + * Complete Interrupt. Write INT_Stat_Class0 or + * INT_Stat_Class2 with value of 'handled'. + */ + POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask); + + local_irq_save(flags); + out_be64(&priv1->int_stat_class0_RW, ~(0UL)); + out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + local_irq_restore(flags); +} + +static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + struct spu_problem __iomem *prob = spu->problem; + unsigned long flags; + + /* Save, Step 57: + * Restore, Step 40. + * Poll until SPU_Status[R]=0 or wait for SPU Class 0 + * or SPU Class 2 interrupt. Write INT_Stat_class0 + * or INT_Stat_class2 with value of handled. + */ + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); + + local_irq_save(flags); + out_be64(&priv1->int_stat_class0_RW, ~(0UL)); + out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + local_irq_restore(flags); +} + +static inline int check_save_status(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + u32 complete; + + /* Save, Step 54: + * If SPU_Status[P]=1 and SPU_Status[SC] = "success", + * context save succeeded, otherwise context save + * failed. + */ + complete = ((SPU_SAVE_COMPLETE << SPU_STOP_STATUS_SHIFT) | + SPU_STATUS_STOPPED_BY_STOP); + return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0; +} + +static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 4: + * If required, notify the "using application" that + * the SPU task has been terminated. TBD. + */ +} + +static inline void suspend_mfc(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 7: + * Restore, Step 47. + * Write MFC_Cntl[Dh,Sc]='1','1' to suspend + * the queue and halt the decrementer. + */ + out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE | + MFC_CNTL_DECREMENTER_HALTED); + eieio(); +} + +static inline void wait_suspend_mfc_complete(struct spu_state *csa, + struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 8: + * Restore, Step 47. + * Poll MFC_CNTL[Ss] until 11 is returned. + */ + POLL_WHILE_FALSE(in_be64(&priv2->mfc_control_RW) & + MFC_CNTL_SUSPEND_COMPLETE); +} + +static inline int suspend_spe(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Restore, Step 9: + * If SPU_Status[R]=1, stop SPU execution + * and wait for stop to complete. + * + * Returns 1 if SPU_Status[R]=1 on entry. + * 0 otherwise + */ + if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) { + if (in_be32(&prob->spu_status_R) & + SPU_STATUS_ISOLATED_EXIT_STAUTUS) { + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } + if ((in_be32(&prob->spu_status_R) & + SPU_STATUS_ISOLATED_LOAD_STAUTUS) + || (in_be32(&prob->spu_status_R) & + SPU_STATUS_ISOLATED_STATE)) { + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + out_be32(&prob->spu_runcntl_RW, 0x2); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } + if (in_be32(&prob->spu_status_R) & + SPU_STATUS_WAITING_FOR_CHANNEL) { + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } + return 1; + } + return 0; +} + +static inline void clear_spu_status(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Restore, Step 10: + * If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1, + * release SPU from isolate state. + */ + if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) { + if (in_be32(&prob->spu_status_R) & + SPU_STATUS_ISOLATED_EXIT_STAUTUS) { + out_be64(&priv1->mfc_sr1_RW, + MFC_STATE1_MASTER_RUN_CONTROL_MASK); + eieio(); + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } + if ((in_be32(&prob->spu_status_R) & + SPU_STATUS_ISOLATED_LOAD_STAUTUS) + || (in_be32(&prob->spu_status_R) & + SPU_STATUS_ISOLATED_STATE)) { + out_be64(&priv1->mfc_sr1_RW, + MFC_STATE1_MASTER_RUN_CONTROL_MASK); + eieio(); + out_be32(&prob->spu_runcntl_RW, 0x2); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } + } +} + +static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL }; + u64 idx; + int i; + + /* Restore, Step 20: + * Reset the following CH: [0,1,3,4,24,25,27] + */ + for (i = 0; i < 7; i++) { + idx = ch_indices[i]; + out_be64(&priv2->spu_chnlcntptr_RW, idx); + eieio(); + out_be64(&priv2->spu_chnldata_RW, 0UL); + out_be64(&priv2->spu_chnlcnt_RW, 0UL); + eieio(); + } +} + +static inline void reset_ch_part2(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 ch_indices[5] = { 21UL, 23UL, 28UL, 29UL, 30UL }; + u64 ch_counts[5] = { 16UL, 1UL, 1UL, 0UL, 1UL }; + u64 idx; + int i; + + /* Restore, Step 21: + * Reset the following CH: [21, 23, 28, 29, 30] + */ + for (i = 0; i < 5; i++) { + idx = ch_indices[i]; + out_be64(&priv2->spu_chnlcntptr_RW, idx); + eieio(); + out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); + eieio(); + } +} + +static inline void setup_spu_status_part1(struct spu_state *csa, + struct spu *spu) +{ + u32 status_P = SPU_STATUS_STOPPED_BY_STOP; + u32 status_I = SPU_STATUS_INVALID_INSTR; + u32 status_H = SPU_STATUS_STOPPED_BY_HALT; + u32 status_S = SPU_STATUS_SINGLE_STEP; + u32 status_S_I = SPU_STATUS_SINGLE_STEP | SPU_STATUS_INVALID_INSTR; + u32 status_S_P = SPU_STATUS_SINGLE_STEP | SPU_STATUS_STOPPED_BY_STOP; + u32 status_P_H = SPU_STATUS_STOPPED_BY_HALT |SPU_STATUS_STOPPED_BY_STOP; + u32 status_P_I = SPU_STATUS_STOPPED_BY_STOP |SPU_STATUS_INVALID_INSTR; + u32 status_code; + + /* Restore, Step 27: + * If the CSA.SPU_Status[I,S,H,P]=1 then add the correct + * instruction sequence to the end of the SPU based restore + * code (after the "context restored" stop and signal) to + * restore the correct SPU status. + * + * NOTE: Rather than modifying the SPU executable, we + * instead add a new 'stopped_status' field to the + * LSCSA. The SPU-side restore reads this field and + * takes the appropriate action when exiting. + */ + + status_code = + (csa->prob.spu_status_R >> SPU_STOP_STATUS_SHIFT) & 0xFFFF; + if ((csa->prob.spu_status_R & status_P_I) == status_P_I) { + + /* SPU_Status[P,I]=1 - Illegal Instruction followed + * by Stop and Signal instruction, followed by 'br -4'. + * + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_I; + csa->lscsa->stopped_status.slot[1] = status_code; + + } else if ((csa->prob.spu_status_R & status_P_H) == status_P_H) { + + /* SPU_Status[P,H]=1 - Halt Conditional, followed + * by Stop and Signal instruction, followed by + * 'br -4'. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P_H; + csa->lscsa->stopped_status.slot[1] = status_code; + + } else if ((csa->prob.spu_status_R & status_S_P) == status_S_P) { + + /* SPU_Status[S,P]=1 - Stop and Signal instruction + * followed by 'br -4'. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_P; + csa->lscsa->stopped_status.slot[1] = status_code; + + } else if ((csa->prob.spu_status_R & status_S_I) == status_S_I) { + + /* SPU_Status[S,I]=1 - Illegal instruction followed + * by 'br -4'. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S_I; + csa->lscsa->stopped_status.slot[1] = status_code; + + } else if ((csa->prob.spu_status_R & status_P) == status_P) { + + /* SPU_Status[P]=1 - Stop and Signal instruction + * followed by 'br -4'. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_P; + csa->lscsa->stopped_status.slot[1] = status_code; + + } else if ((csa->prob.spu_status_R & status_H) == status_H) { + + /* SPU_Status[H]=1 - Halt Conditional, followed + * by 'br -4'. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_H; + + } else if ((csa->prob.spu_status_R & status_S) == status_S) { + + /* SPU_Status[S]=1 - Two nop instructions. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_S; + + } else if ((csa->prob.spu_status_R & status_I) == status_I) { + + /* SPU_Status[I]=1 - Illegal instruction followed + * by 'br -4'. + */ + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_I; + + } +} + +static inline void setup_spu_status_part2(struct spu_state *csa, + struct spu *spu) +{ + u32 mask; + + /* Restore, Step 28: + * If the CSA.SPU_Status[I,S,H,P,R]=0 then + * add a 'br *' instruction to the end of + * the SPU based restore code. + * + * NOTE: Rather than modifying the SPU executable, we + * instead add a new 'stopped_status' field to the + * LSCSA. The SPU-side restore reads this field and + * takes the appropriate action when exiting. + */ + mask = SPU_STATUS_INVALID_INSTR | + SPU_STATUS_SINGLE_STEP | + SPU_STATUS_STOPPED_BY_HALT | + SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING; + if (!(csa->prob.spu_status_R & mask)) { + csa->lscsa->stopped_status.slot[0] = SPU_STOPPED_STATUS_R; + } +} + +static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Restore, Step 29: + * Restore RA_GROUP_ID register and the + * RA_ENABLE reigster from the CSA. + */ + out_be64(&priv1->resource_allocation_groupID_RW, + csa->priv1.resource_allocation_groupID_RW); + out_be64(&priv1->resource_allocation_enable_RW, + csa->priv1.resource_allocation_enable_RW); +} + +static inline void send_restore_code(struct spu_state *csa, struct spu *spu) +{ + unsigned long addr = (unsigned long)&spu_restore_code[0]; + unsigned int ls_offset = 0x0; + unsigned int size = sizeof(spu_restore_code); + unsigned int tag = 0; + unsigned int rclass = 0; + unsigned int cmd = MFC_GETFS_CMD; + + /* Restore, Step 37: + * Issue MFC DMA command to copy context + * restore code to local storage. + */ + send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); +} + +static inline void setup_decr(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 34: + * If CSA.MFC_CNTL[Ds]=1 (decrementer was + * running) then adjust decrementer, set + * decrementer running status in LSCSA, + * and set decrementer "wrapped" status + * in LSCSA. + */ + if (csa->priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) { + cycles_t resume_time = get_cycles(); + cycles_t delta_time = resume_time - csa->suspend_time; + + csa->lscsa->decr.slot[0] = delta_time; + } +} + +static inline void setup_ppu_mb(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 35: + * Copy the CSA.PU_MB data into the LSCSA. + */ + csa->lscsa->ppu_mb.slot[0] = csa->prob.pu_mb_R; +} + +static inline void setup_ppuint_mb(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 36: + * Copy the CSA.PUINT_MB data into the LSCSA. + */ + csa->lscsa->ppuint_mb.slot[0] = csa->priv2.puint_mb_R; +} + +static inline int check_restore_status(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + u32 complete; + + /* Restore, Step 40: + * If SPU_Status[P]=1 and SPU_Status[SC] = "success", + * context restore succeeded, otherwise context restore + * failed. + */ + complete = ((SPU_RESTORE_COMPLETE << SPU_STOP_STATUS_SHIFT) | + SPU_STATUS_STOPPED_BY_STOP); + return (in_be32(&prob->spu_status_R) != complete) ? 1 : 0; +} + +static inline void restore_spu_privcntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 41: + * Restore SPU_PrivCntl from the CSA. + */ + out_be64(&priv2->spu_privcntl_RW, csa->priv2.spu_privcntl_RW); + eieio(); +} + +static inline void restore_status_part1(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + u32 mask; + + /* Restore, Step 42: + * If any CSA.SPU_Status[I,S,H,P]=1, then + * restore the error or single step state. + */ + mask = SPU_STATUS_INVALID_INSTR | + SPU_STATUS_SINGLE_STEP | + SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; + if (csa->prob.spu_status_R & mask) { + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } +} + +static inline void restore_status_part2(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + u32 mask; + + /* Restore, Step 43: + * If all CSA.SPU_Status[I,S,H,P,R]=0 then write + * SPU_RunCntl[R0R1]='01', wait for SPU_Status[R]=1, + * then write '00' to SPU_RunCntl[R0R1] and wait + * for SPU_Status[R]=0. + */ + mask = SPU_STATUS_INVALID_INSTR | + SPU_STATUS_SINGLE_STEP | + SPU_STATUS_STOPPED_BY_HALT | + SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_RUNNING; + if (!(csa->prob.spu_status_R & mask)) { + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); + eieio(); + POLL_WHILE_FALSE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); + eieio(); + POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & + SPU_STATUS_RUNNING); + } +} + +static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu) +{ + unsigned long addr = (unsigned long)&csa->lscsa->ls[0]; + unsigned int ls_offset = 0x0; + unsigned int size = 16384; + unsigned int tag = 0; + unsigned int rclass = 0; + unsigned int cmd = MFC_GET_CMD; + + /* Restore, Step 44: + * Issue a DMA command to restore the first + * 16kb of local storage from CSA. + */ + send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); +} + +static inline void clear_interrupts(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Restore, Step 49: + * Write INT_MASK_class0 with value of 0. + * Write INT_MASK_class1 with value of 0. + * Write INT_MASK_class2 with value of 0. + * Write INT_STAT_class0 with value of -1. + * Write INT_STAT_class1 with value of -1. + * Write INT_STAT_class2 with value of -1. + */ + spin_lock_irq(&spu->register_lock); + out_be64(&priv1->int_mask_class0_RW, 0UL); + out_be64(&priv1->int_mask_class1_RW, 0UL); + out_be64(&priv1->int_mask_class2_RW, 0UL); + out_be64(&priv1->int_stat_class0_RW, ~(0UL)); + out_be64(&priv1->int_stat_class1_RW, ~(0UL)); + out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + spin_unlock_irq(&spu->register_lock); +} + +static inline void restore_mfc_queues(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + int i; + + /* Restore, Step 50: + * If MFC_Cntl[Se]!=0 then restore + * MFC command queues. + */ + if ((csa->priv2.mfc_control_RW & MFC_CNTL_DMA_QUEUES_EMPTY_MASK) == 0) { + for (i = 0; i < 8; i++) { + out_be64(&priv2->puq[i].mfc_cq_data0_RW, + csa->priv2.puq[i].mfc_cq_data0_RW); + out_be64(&priv2->puq[i].mfc_cq_data1_RW, + csa->priv2.puq[i].mfc_cq_data1_RW); + out_be64(&priv2->puq[i].mfc_cq_data2_RW, + csa->priv2.puq[i].mfc_cq_data2_RW); + out_be64(&priv2->puq[i].mfc_cq_data3_RW, + csa->priv2.puq[i].mfc_cq_data3_RW); + } + for (i = 0; i < 16; i++) { + out_be64(&priv2->spuq[i].mfc_cq_data0_RW, + csa->priv2.spuq[i].mfc_cq_data0_RW); + out_be64(&priv2->spuq[i].mfc_cq_data1_RW, + csa->priv2.spuq[i].mfc_cq_data1_RW); + out_be64(&priv2->spuq[i].mfc_cq_data2_RW, + csa->priv2.spuq[i].mfc_cq_data2_RW); + out_be64(&priv2->spuq[i].mfc_cq_data3_RW, + csa->priv2.spuq[i].mfc_cq_data3_RW); + } + } + eieio(); +} + +static inline void restore_ppu_querymask(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Restore, Step 51: + * Restore the PPU_QueryMask register from CSA. + */ + out_be32(&prob->dma_querymask_RW, csa->prob.dma_querymask_RW); + eieio(); +} + +static inline void restore_ppu_querytype(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Restore, Step 52: + * Restore the PPU_QueryType register from CSA. + */ + out_be32(&prob->dma_querytype_RW, csa->prob.dma_querytype_RW); + eieio(); +} + +static inline void restore_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 53: + * Restore the MFC_CSR_TSQ register from CSA. + */ + out_be64(&priv2->spu_tag_status_query_RW, + csa->priv2.spu_tag_status_query_RW); + eieio(); +} + +static inline void restore_mfc_csr_cmd(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 54: + * Restore the MFC_CSR_CMD1 and MFC_CSR_CMD2 + * registers from CSA. + */ + out_be64(&priv2->spu_cmd_buf1_RW, csa->priv2.spu_cmd_buf1_RW); + out_be64(&priv2->spu_cmd_buf2_RW, csa->priv2.spu_cmd_buf2_RW); + eieio(); +} + +static inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 55: + * Restore the MFC_CSR_ATO register from CSA. + */ + out_be64(&priv2->spu_atomic_status_RW, csa->priv2.spu_atomic_status_RW); +} + +static inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Restore, Step 56: + * Restore the MFC_TCLASS_ID register from CSA. + */ + out_be64(&priv1->mfc_tclass_id_RW, csa->priv1.mfc_tclass_id_RW); + eieio(); +} + +static inline void set_llr_event(struct spu_state *csa, struct spu *spu) +{ + u64 ch0_cnt, ch0_data; + u64 ch1_data; + + /* Restore, Step 57: + * Set the Lock Line Reservation Lost Event by: + * 1. OR CSA.SPU_Event_Status with bit 21 (Lr) set to 1. + * 2. If CSA.SPU_Channel_0_Count=0 and + * CSA.SPU_Wr_Event_Mask[Lr]=1 and + * CSA.SPU_Event_Status[Lr]=0 then set + * CSA.SPU_Event_Status_Count=1. + */ + ch0_cnt = csa->spu_chnlcnt_RW[0]; + ch0_data = csa->spu_chnldata_RW[0]; + ch1_data = csa->spu_chnldata_RW[1]; + csa->spu_chnldata_RW[0] |= MFC_LLR_LOST_EVENT; + if ((ch0_cnt == 0) && !(ch0_data & MFC_LLR_LOST_EVENT) && + (ch1_data & MFC_LLR_LOST_EVENT)) { + csa->spu_chnlcnt_RW[0] = 1; + } +} + +static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 58: + * If the status of the CSA software decrementer + * "wrapped" flag is set, OR in a '1' to + * CSA.SPU_Event_Status[Tm]. + */ + if (csa->lscsa->decr_status.slot[0] == 1) { + csa->spu_chnldata_RW[0] |= 0x20; + } + if ((csa->lscsa->decr_status.slot[0] == 1) && + (csa->spu_chnlcnt_RW[0] == 0 && + ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) && + ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) { + csa->spu_chnlcnt_RW[0] = 1; + } +} + +static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 idx, ch_indices[7] = { 0UL, 1UL, 3UL, 4UL, 24UL, 25UL, 27UL }; + int i; + + /* Restore, Step 59: + * Restore the following CH: [0,1,3,4,24,25,27] + */ + for (i = 0; i < 7; i++) { + idx = ch_indices[i]; + out_be64(&priv2->spu_chnlcntptr_RW, idx); + eieio(); + out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[idx]); + out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[idx]); + eieio(); + } +} + +static inline void restore_ch_part2(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 ch_indices[3] = { 9UL, 21UL, 23UL }; + u64 ch_counts[3] = { 1UL, 16UL, 1UL }; + u64 idx; + int i; + + /* Restore, Step 60: + * Restore the following CH: [9,21,23]. + */ + ch_counts[0] = 1UL; + ch_counts[1] = csa->spu_chnlcnt_RW[21]; + ch_counts[2] = 1UL; + for (i = 0; i < 3; i++) { + idx = ch_indices[i]; + out_be64(&priv2->spu_chnlcntptr_RW, idx); + eieio(); + out_be64(&priv2->spu_chnlcnt_RW, ch_counts[i]); + eieio(); + } +} + +static inline void restore_spu_lslr(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 61: + * Restore the SPU_LSLR register from CSA. + */ + out_be64(&priv2->spu_lslr_RW, csa->priv2.spu_lslr_RW); + eieio(); +} + +static inline void restore_spu_cfg(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 62: + * Restore the SPU_Cfg register from CSA. + */ + out_be64(&priv2->spu_cfg_RW, csa->priv2.spu_cfg_RW); + eieio(); +} + +static inline void restore_pm_trace(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 63: + * Restore PM_Trace_Tag_Wait_Mask from CSA. + * Not performed by this implementation. + */ +} + +static inline void restore_spu_npc(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Restore, Step 64: + * Restore SPU_NPC from CSA. + */ + out_be32(&prob->spu_npc_RW, csa->prob.spu_npc_RW); + eieio(); +} + +static inline void restore_spu_mb(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + int i; + + /* Restore, Step 65: + * Restore MFC_RdSPU_MB from CSA. + */ + out_be64(&priv2->spu_chnlcntptr_RW, 29UL); + eieio(); + out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]); + for (i = 0; i < 4; i++) { + out_be64(&priv2->spu_chnldata_RW, csa->pu_mailbox_data[i]); + } + eieio(); +} + +static inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + u32 dummy = 0; + + /* Restore, Step 66: + * If CSA.MB_Stat[P]=0 (mailbox empty) then + * read from the PPU_MB register. + */ + if ((csa->prob.mb_stat_R & 0xFF) == 0) { + dummy = in_be32(&prob->pu_mb_R); + eieio(); + } +} + +static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 dummy = 0UL; + + /* Restore, Step 66: + * If CSA.MB_Stat[I]=0 (mailbox empty) then + * read from the PPUINT_MB register. + */ + if ((csa->prob.mb_stat_R & 0xFF0000) == 0) { + dummy = in_be64(&priv2->puint_mb_R); + eieio(); + out_be64(&priv1->int_stat_class2_RW, + CLASS2_ENABLE_MAILBOX_INTR); + eieio(); + } +} + +static inline void restore_mfc_slbs(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + int i; + + /* Restore, Step 68: + * If MFC_SR1[R]='1', restore SLBs from CSA. + */ + if (csa->priv1.mfc_sr1_RW & MFC_STATE1_RELOCATE_MASK) { + for (i = 0; i < 8; i++) { + out_be64(&priv2->slb_index_W, i); + eieio(); + out_be64(&priv2->slb_esid_RW, csa->slb_esid_RW[i]); + out_be64(&priv2->slb_vsid_RW, csa->slb_vsid_RW[i]); + eieio(); + } + out_be64(&priv2->slb_index_W, csa->priv2.slb_index_W); + eieio(); + } +} + +static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Restore, Step 69: + * Restore the MFC_SR1 register from CSA. + */ + out_be64(&priv1->mfc_sr1_RW, csa->priv1.mfc_sr1_RW); + eieio(); +} + +static inline void restore_other_spu_access(struct spu_state *csa, + struct spu *spu) +{ + /* Restore, Step 70: + * Restore other SPU mappings to this SPU. TBD. + */ +} + +static inline void restore_spu_runcntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Restore, Step 71: + * If CSA.SPU_Status[R]=1 then write + * SPU_RunCntl[R0R1]='01'. + */ + if (csa->prob.spu_status_R & SPU_STATUS_RUNNING) { + out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); + eieio(); + } +} + +static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv2 __iomem *priv2 = spu->priv2; + + /* Restore, Step 72: + * Restore the MFC_CNTL register for the CSA. + */ + out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW); + eieio(); +} + +static inline void enable_user_access(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 73: + * Enable user-space access (if provided) to this + * SPU by mapping the virtual pages assigned to + * the SPU memory-mapped I/O (MMIO) for problem + * state. TBD. + */ +} + +static inline void reset_switch_active(struct spu_state *csa, struct spu *spu) +{ + /* Restore, Step 74: + * Reset the "context switch active" flag. + */ + clear_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags); + mb(); +} + +static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu) +{ + struct spu_priv1 __iomem *priv1 = spu->priv1; + + /* Restore, Step 75: + * Re-enable SPU interrupts. + */ + spin_lock_irq(&spu->register_lock); + out_be64(&priv1->int_mask_class0_RW, csa->priv1.int_mask_class0_RW); + out_be64(&priv1->int_mask_class1_RW, csa->priv1.int_mask_class1_RW); + out_be64(&priv1->int_mask_class2_RW, csa->priv1.int_mask_class2_RW); + spin_unlock_irq(&spu->register_lock); +} + +static int quiece_spu(struct spu_state *prev, struct spu *spu) +{ + /* + * Combined steps 2-18 of SPU context save sequence, which + * quiesce the SPU state (disable SPU execution, MFC command + * queues, decrementer, SPU interrupts, etc.). + * + * Returns 0 on success. + * 2 if failed step 2. + * 6 if failed step 6. + */ + + if (check_spu_isolate(prev, spu)) { /* Step 2. */ + return 2; + } + disable_interrupts(prev, spu); /* Step 3. */ + set_watchdog_timer(prev, spu); /* Step 4. */ + inhibit_user_access(prev, spu); /* Step 5. */ + if (check_spu_isolate(prev, spu)) { /* Step 6. */ + return 6; + } + set_switch_pending(prev, spu); /* Step 7. */ + save_mfc_cntl(prev, spu); /* Step 8. */ + save_spu_runcntl(prev, spu); /* Step 9. */ + save_mfc_sr1(prev, spu); /* Step 10. */ + save_spu_status(prev, spu); /* Step 11. */ + save_mfc_decr(prev, spu); /* Step 12. */ + halt_mfc_decr(prev, spu); /* Step 13. */ + save_timebase(prev, spu); /* Step 14. */ + remove_other_spu_access(prev, spu); /* Step 15. */ + do_mfc_mssync(prev, spu); /* Step 16. */ + issue_mfc_tlbie(prev, spu); /* Step 17. */ + handle_pending_interrupts(prev, spu); /* Step 18. */ + + return 0; +} + +static void save_csa(struct spu_state *prev, struct spu *spu) +{ + /* + * Combine steps 19-44 of SPU context save sequence, which + * save regions of the privileged & problem state areas. + */ + + save_mfc_queues(prev, spu); /* Step 19. */ + save_ppu_querymask(prev, spu); /* Step 20. */ + save_ppu_querytype(prev, spu); /* Step 21. */ + save_mfc_csr_tsq(prev, spu); /* Step 22. */ + save_mfc_csr_cmd(prev, spu); /* Step 23. */ + save_mfc_csr_ato(prev, spu); /* Step 24. */ + save_mfc_tclass_id(prev, spu); /* Step 25. */ + set_mfc_tclass_id(prev, spu); /* Step 26. */ + purge_mfc_queue(prev, spu); /* Step 27. */ + wait_purge_complete(prev, spu); /* Step 28. */ + save_mfc_slbs(prev, spu); /* Step 29. */ + setup_mfc_sr1(prev, spu); /* Step 30. */ + save_spu_npc(prev, spu); /* Step 31. */ + save_spu_privcntl(prev, spu); /* Step 32. */ + reset_spu_privcntl(prev, spu); /* Step 33. */ + save_spu_lslr(prev, spu); /* Step 34. */ + reset_spu_lslr(prev, spu); /* Step 35. */ + save_spu_cfg(prev, spu); /* Step 36. */ + save_pm_trace(prev, spu); /* Step 37. */ + save_mfc_rag(prev, spu); /* Step 38. */ + save_ppu_mb_stat(prev, spu); /* Step 39. */ + save_ppu_mb(prev, spu); /* Step 40. */ + save_ppuint_mb(prev, spu); /* Step 41. */ + save_ch_part1(prev, spu); /* Step 42. */ + save_spu_mb(prev, spu); /* Step 43. */ + save_mfc_cmd(prev, spu); /* Step 44. */ + reset_ch(prev, spu); /* Step 45. */ +} + +static void save_lscsa(struct spu_state *prev, struct spu *spu) +{ + /* + * Perform steps 46-57 of SPU context save sequence, + * which save regions of the local store and register + * file. + */ + + resume_mfc_queue(prev, spu); /* Step 46. */ + setup_mfc_slbs(prev, spu); /* Step 47. */ + set_switch_active(prev, spu); /* Step 48. */ + enable_interrupts(prev, spu); /* Step 49. */ + save_ls_16kb(prev, spu); /* Step 50. */ + set_spu_npc(prev, spu); /* Step 51. */ + set_signot1(prev, spu); /* Step 52. */ + set_signot2(prev, spu); /* Step 53. */ + send_save_code(prev, spu); /* Step 54. */ + set_ppu_querymask(prev, spu); /* Step 55. */ + wait_tag_complete(prev, spu); /* Step 56. */ + wait_spu_stopped(prev, spu); /* Step 57. */ +} + +static void harvest(struct spu_state *prev, struct spu *spu) +{ + /* + * Perform steps 2-25 of SPU context restore sequence, + * which resets an SPU either after a failed save, or + * when using SPU for first time. + */ + + disable_interrupts(prev, spu); /* Step 2. */ + inhibit_user_access(prev, spu); /* Step 3. */ + terminate_spu_app(prev, spu); /* Step 4. */ + set_switch_pending(prev, spu); /* Step 5. */ + remove_other_spu_access(prev, spu); /* Step 6. */ + suspend_mfc(prev, spu); /* Step 7. */ + wait_suspend_mfc_complete(prev, spu); /* Step 8. */ + if (!suspend_spe(prev, spu)) /* Step 9. */ + clear_spu_status(prev, spu); /* Step 10. */ + do_mfc_mssync(prev, spu); /* Step 11. */ + issue_mfc_tlbie(prev, spu); /* Step 12. */ + handle_pending_interrupts(prev, spu); /* Step 13. */ + purge_mfc_queue(prev, spu); /* Step 14. */ + wait_purge_complete(prev, spu); /* Step 15. */ + reset_spu_privcntl(prev, spu); /* Step 16. */ + reset_spu_lslr(prev, spu); /* Step 17. */ + setup_mfc_sr1(prev, spu); /* Step 18. */ + invalidate_slbs(prev, spu); /* Step 19. */ + reset_ch_part1(prev, spu); /* Step 20. */ + reset_ch_part2(prev, spu); /* Step 21. */ + enable_interrupts(prev, spu); /* Step 22. */ + set_switch_active(prev, spu); /* Step 23. */ + set_mfc_tclass_id(prev, spu); /* Step 24. */ + resume_mfc_queue(prev, spu); /* Step 25. */ +} + +static void restore_lscsa(struct spu_state *next, struct spu *spu) +{ + /* + * Perform steps 26-40 of SPU context restore sequence, + * which restores regions of the local store and register + * file. + */ + + set_watchdog_timer(next, spu); /* Step 26. */ + setup_spu_status_part1(next, spu); /* Step 27. */ + setup_spu_status_part2(next, spu); /* Step 28. */ + restore_mfc_rag(next, spu); /* Step 29. */ + setup_mfc_slbs(next, spu); /* Step 30. */ + set_spu_npc(next, spu); /* Step 31. */ + set_signot1(next, spu); /* Step 32. */ + set_signot2(next, spu); /* Step 33. */ + setup_decr(next, spu); /* Step 34. */ + setup_ppu_mb(next, spu); /* Step 35. */ + setup_ppuint_mb(next, spu); /* Step 36. */ + send_restore_code(next, spu); /* Step 37. */ + set_ppu_querymask(next, spu); /* Step 38. */ + wait_tag_complete(next, spu); /* Step 39. */ + wait_spu_stopped(next, spu); /* Step 40. */ +} + +static void restore_csa(struct spu_state *next, struct spu *spu) +{ + /* + * Combine steps 41-76 of SPU context restore sequence, which + * restore regions of the privileged & problem state areas. + */ + + restore_spu_privcntl(next, spu); /* Step 41. */ + restore_status_part1(next, spu); /* Step 42. */ + restore_status_part2(next, spu); /* Step 43. */ + restore_ls_16kb(next, spu); /* Step 44. */ + wait_tag_complete(next, spu); /* Step 45. */ + suspend_mfc(next, spu); /* Step 46. */ + wait_suspend_mfc_complete(next, spu); /* Step 47. */ + issue_mfc_tlbie(next, spu); /* Step 48. */ + clear_interrupts(next, spu); /* Step 49. */ + restore_mfc_queues(next, spu); /* Step 50. */ + restore_ppu_querymask(next, spu); /* Step 51. */ + restore_ppu_querytype(next, spu); /* Step 52. */ + restore_mfc_csr_tsq(next, spu); /* Step 53. */ + restore_mfc_csr_cmd(next, spu); /* Step 54. */ + restore_mfc_csr_ato(next, spu); /* Step 55. */ + restore_mfc_tclass_id(next, spu); /* Step 56. */ + set_llr_event(next, spu); /* Step 57. */ + restore_decr_wrapped(next, spu); /* Step 58. */ + restore_ch_part1(next, spu); /* Step 59. */ + restore_ch_part2(next, spu); /* Step 60. */ + restore_spu_lslr(next, spu); /* Step 61. */ + restore_spu_cfg(next, spu); /* Step 62. */ + restore_pm_trace(next, spu); /* Step 63. */ + restore_spu_npc(next, spu); /* Step 64. */ + restore_spu_mb(next, spu); /* Step 65. */ + check_ppu_mb_stat(next, spu); /* Step 66. */ + check_ppuint_mb_stat(next, spu); /* Step 67. */ + restore_mfc_slbs(next, spu); /* Step 68. */ + restore_mfc_sr1(next, spu); /* Step 69. */ + restore_other_spu_access(next, spu); /* Step 70. */ + restore_spu_runcntl(next, spu); /* Step 71. */ + restore_mfc_cntl(next, spu); /* Step 72. */ + enable_user_access(next, spu); /* Step 73. */ + reset_switch_active(next, spu); /* Step 74. */ + reenable_interrupts(next, spu); /* Step 75. */ +} + +static int __do_spu_save(struct spu_state *prev, struct spu *spu) +{ + int rc; + + /* + * SPU context save can be broken into three phases: + * + * (a) quiesce [steps 2-16]. + * (b) save of CSA, performed by PPE [steps 17-42] + * (c) save of LSCSA, mostly performed by SPU [steps 43-52]. + * + * Returns 0 on success. + * 2,6 if failed to quiece SPU + * 53 if SPU-side of save failed. + */ + + rc = quiece_spu(prev, spu); /* Steps 2-16. */ + switch (rc) { + default: + case 2: + case 6: + harvest(prev, spu); + return rc; + break; + case 0: + break; + } + save_csa(prev, spu); /* Steps 17-43. */ + save_lscsa(prev, spu); /* Steps 44-53. */ + return check_save_status(prev, spu); /* Step 54. */ +} + +static int __do_spu_restore(struct spu_state *next, struct spu *spu) +{ + int rc; + + /* + * SPU context restore can be broken into three phases: + * + * (a) harvest (or reset) SPU [steps 2-24]. + * (b) restore LSCSA [steps 25-40], mostly performed by SPU. + * (c) restore CSA [steps 41-76], performed by PPE. + * + * The 'harvest' step is not performed here, but rather + * as needed below. + */ + + restore_lscsa(next, spu); /* Steps 24-39. */ + rc = check_restore_status(next, spu); /* Step 40. */ + switch (rc) { + default: + /* Failed. Return now. */ + return rc; + break; + case 0: + /* Fall through to next step. */ + break; + } + restore_csa(next, spu); + + return 0; +} + /** * spu_save - SPU context save, with locking. * @prev: pointer to SPU context save area, to be saved. @@ -61,9 +2074,13 @@ */ int spu_save(struct spu_state *prev, struct spu *spu) { - /* XXX missing */ + int rc; - return 0; + acquire_spu_lock(spu); /* Step 1. */ + rc = __do_spu_save(prev, spu); /* Steps 2-53. */ + release_spu_lock(spu); + + return rc; } /** @@ -77,9 +2094,14 @@ int spu_save(struct spu_state *prev, struct spu *spu) */ int spu_restore(struct spu_state *new, struct spu *spu) { - /* XXX missing */ + int rc; - return 0; + acquire_spu_lock(spu); + harvest(NULL, spu); + rc = __do_spu_restore(new, spu); + release_spu_lock(spu); + + return rc; } /** @@ -93,9 +2115,17 @@ int spu_restore(struct spu_state *new, struct spu *spu) */ int spu_switch(struct spu_state *prev, struct spu_state *new, struct spu *spu) { - /* XXX missing */ + int rc; - return 0; + acquire_spu_lock(spu); /* Save, Step 1. */ + rc = __do_spu_save(prev, spu); /* Save, Steps 2-53. */ + if (rc != 0) { + harvest(prev, spu); + } + rc = __do_spu_restore(new, spu); + release_spu_lock(spu); + + return rc; } static void init_prob(struct spu_state *csa) diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h index d1d537de4f5c..989a0688144e 100644 --- a/include/asm-powerpc/spu_csa.h +++ b/include/asm-powerpc/spu_csa.h @@ -200,7 +200,6 @@ struct spu_priv2_collapsed { u64 spu_chnlcnt_RW; u64 spu_chnldata_RW; u64 spu_cfg_RW; - u64 spu_pm_trace_tag_status_RW; u64 spu_tag_status_query_RW; u64 spu_cmd_buf1_RW; u64 spu_cmd_buf2_RW; -- cgit v1.2.3 From 05b841174c289ca62a6b42d883b8791d9ac3a4bd Mon Sep 17 00:00:00 2001 From: Mark Nutter Date: Tue, 15 Nov 2005 15:53:51 -0500 Subject: [PATCH] spufs: add spu-side context switch code Add the source code that is used to generate spu_save_dump.h and spu_restore_dump.h. Since a full spu tool chain is needed to generate these files, the default remains to use the shipped versions in order to keep the number of tools for building the kernel down. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/Makefile | 49 +++ arch/powerpc/platforms/cell/spufs/spu_restore.c | 336 +++++++++++++++++++++ .../platforms/cell/spufs/spu_restore_crt0.S | 116 +++++++ arch/powerpc/platforms/cell/spufs/spu_save.c | 195 ++++++++++++ arch/powerpc/platforms/cell/spufs/spu_save_crt0.S | 102 +++++++ arch/powerpc/platforms/cell/spufs/spu_utils.h | 160 ++++++++++ 6 files changed, 958 insertions(+) create mode 100644 arch/powerpc/platforms/cell/spufs/spu_restore.c create mode 100644 arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S create mode 100644 arch/powerpc/platforms/cell/spufs/spu_save.c create mode 100644 arch/powerpc/platforms/cell/spufs/spu_save_crt0.S create mode 100644 arch/powerpc/platforms/cell/spufs/spu_utils.h diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index e70e3cc1158f..b38ab747efd7 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -2,4 +2,53 @@ obj-$(CONFIG_SPU_FS) += spufs.o spufs-y += inode.o file.o context.o switch.o syscalls.o +# Rules to build switch.o with the help of SPU tool chain +SPU_CROSS := spu- +SPU_CC := $(SPU_CROSS)gcc +SPU_AS := $(SPU_CROSS)gcc +SPU_LD := $(SPU_CROSS)ld +SPU_OBJCOPY := $(SPU_CROSS)objcopy +SPU_CFLAGS := -O2 -Wall -I$(srctree)/include -I$(objtree)/include2 +SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include -I$(objtree)/include2 +SPU_LDFLAGS := -N -Ttext=0x0 + $(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h + +# Compile SPU files + cmd_spu_cc = $(SPU_CC) $(SPU_CFLAGS) -c -o $@ $< +quiet_cmd_spu_cc = SPU_CC $@ +$(obj)/spu_%.o: $(src)/spu_%.c + $(call if_changed,spu_cc) + +# Assemble SPU files + cmd_spu_as = $(SPU_AS) $(SPU_AFLAGS) -o $@ $< +quiet_cmd_spu_as = SPU_AS $@ +$(obj)/spu_%.o: $(src)/spu_%.S + $(call if_changed,spu_as) + +# Link SPU Executables + cmd_spu_ld = $(SPU_LD) $(SPU_LDFLAGS) -o $@ $^ +quiet_cmd_spu_ld = SPU_LD $@ +$(obj)/spu_%: $(obj)/spu_%_crt0.o $(obj)/spu_%.o + $(call if_changed,spu_ld) + +# Copy into binary format + cmd_spu_objcopy = $(SPU_OBJCOPY) -O binary $< $@ +quiet_cmd_spu_objcopy = OBJCOPY $@ +$(obj)/spu_%.bin: $(src)/spu_% + $(call if_changed,spu_objcopy) + +# create C code from ELF executable +cmd_hexdump = ( \ + echo "/*" ; \ + echo " * $*_dump.h: Copyright (C) 2005 IBM." ; \ + echo " * Hex-dump auto generated from $*.c." ; \ + echo " * Do not edit!" ; \ + echo " */" ; \ + echo "static unsigned int $*_code[] __page_aligned = {" ; \ + hexdump -v -e '4/4 "0x%08x, " "\n"' $< ; \ + echo "};" ; \ + ) > $@ +quiet_cmd_hexdump = HEXDUMP $@ +$(obj)/%_dump.h: $(obj)/%.bin + $(call if_changed,hexdump) diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c new file mode 100644 index 000000000000..0bf723dcd677 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c @@ -0,0 +1,336 @@ +/* + * spu_restore.c + * + * (C) Copyright IBM Corp. 2005 + * + * SPU-side context restore sequence outlined in + * Synergistic Processor Element Book IV + * + * Author: Mark Nutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef LS_SIZE +#define LS_SIZE 0x40000 /* 256K (in bytes) */ +#endif + +typedef unsigned int u32; +typedef unsigned long long u64; + +#include +#include +#include "spu_utils.h" + +#define BR_INSTR 0x327fff80 /* br -4 */ +#define NOP_INSTR 0x40200000 /* nop */ +#define HEQ_INSTR 0x7b000000 /* heq $0, $0 */ +#define STOP_INSTR 0x00000000 /* stop 0x0 */ +#define ILLEGAL_INSTR 0x00800000 /* illegal instr */ +#define RESTORE_COMPLETE 0x00003ffc /* stop 0x3ffc */ + +static inline void fetch_regs_from_mem(addr64 lscsa_ea) +{ + unsigned int ls = (unsigned int)®s_spill[0]; + unsigned int size = sizeof(regs_spill); + unsigned int tag_id = 0; + unsigned int cmd = 0x40; /* GET */ + + spu_writech(MFC_LSA, ls); + spu_writech(MFC_EAH, lscsa_ea.ui[0]); + spu_writech(MFC_EAL, lscsa_ea.ui[1]); + spu_writech(MFC_Size, size); + spu_writech(MFC_TagID, tag_id); + spu_writech(MFC_Cmd, cmd); +} + +static inline void restore_upper_240kb(addr64 lscsa_ea) +{ + unsigned int ls = 16384; + unsigned int list = (unsigned int)&dma_list[0]; + unsigned int size = sizeof(dma_list); + unsigned int tag_id = 0; + unsigned int cmd = 0x44; /* GETL */ + + /* Restore, Step 4: + * Enqueue the GETL command (tag 0) to the MFC SPU command + * queue to transfer the upper 240 kb of LS from CSA. + */ + spu_writech(MFC_LSA, ls); + spu_writech(MFC_EAH, lscsa_ea.ui[0]); + spu_writech(MFC_EAL, list); + spu_writech(MFC_Size, size); + spu_writech(MFC_TagID, tag_id); + spu_writech(MFC_Cmd, cmd); +} + +static inline void restore_decr(void) +{ + unsigned int offset; + unsigned int decr_running; + unsigned int decr; + + /* Restore, Step 6: + * If the LSCSA "decrementer running" flag is set + * then write the SPU_WrDec channel with the + * decrementer value from LSCSA. + */ + offset = LSCSA_QW_OFFSET(decr_status); + decr_running = regs_spill[offset].slot[0]; + if (decr_running) { + offset = LSCSA_QW_OFFSET(decr); + decr = regs_spill[offset].slot[0]; + spu_writech(SPU_WrDec, decr); + } +} + +static inline void write_ppu_mb(void) +{ + unsigned int offset; + unsigned int data; + + /* Restore, Step 11: + * Write the MFC_WrOut_MB channel with the PPU_MB + * data from LSCSA. + */ + offset = LSCSA_QW_OFFSET(ppu_mb); + data = regs_spill[offset].slot[0]; + spu_writech(SPU_WrOutMbox, data); +} + +static inline void write_ppuint_mb(void) +{ + unsigned int offset; + unsigned int data; + + /* Restore, Step 12: + * Write the MFC_WrInt_MB channel with the PPUINT_MB + * data from LSCSA. + */ + offset = LSCSA_QW_OFFSET(ppuint_mb); + data = regs_spill[offset].slot[0]; + spu_writech(SPU_WrOutIntrMbox, data); +} + +static inline void restore_fpcr(void) +{ + unsigned int offset; + vector unsigned int fpcr; + + /* Restore, Step 13: + * Restore the floating-point status and control + * register from the LSCSA. + */ + offset = LSCSA_QW_OFFSET(fpcr); + fpcr = regs_spill[offset].v; + spu_mtfpscr(fpcr); +} + +static inline void restore_srr0(void) +{ + unsigned int offset; + unsigned int srr0; + + /* Restore, Step 14: + * Restore the SPU SRR0 data from the LSCSA. + */ + offset = LSCSA_QW_OFFSET(srr0); + srr0 = regs_spill[offset].slot[0]; + spu_writech(SPU_WrSRR0, srr0); +} + +static inline void restore_event_mask(void) +{ + unsigned int offset; + unsigned int event_mask; + + /* Restore, Step 15: + * Restore the SPU_RdEventMsk data from the LSCSA. + */ + offset = LSCSA_QW_OFFSET(event_mask); + event_mask = regs_spill[offset].slot[0]; + spu_writech(SPU_WrEventMask, event_mask); +} + +static inline void restore_tag_mask(void) +{ + unsigned int offset; + unsigned int tag_mask; + + /* Restore, Step 16: + * Restore the SPU_RdTagMsk data from the LSCSA. + */ + offset = LSCSA_QW_OFFSET(tag_mask); + tag_mask = regs_spill[offset].slot[0]; + spu_writech(MFC_WrTagMask, tag_mask); +} + +static inline void restore_complete(void) +{ + extern void exit_fini(void); + unsigned int *exit_instrs = (unsigned int *)exit_fini; + unsigned int offset; + unsigned int stopped_status; + unsigned int stopped_code; + + /* Restore, Step 18: + * Issue a stop-and-signal instruction with + * "good context restore" signal value. + * + * Restore, Step 19: + * There may be additional instructions placed + * here by the PPE Sequence for SPU Context + * Restore in order to restore the correct + * "stopped state". + * + * This step is handled here by analyzing the + * LSCSA.stopped_status and then modifying the + * exit() function to behave appropriately. + */ + + offset = LSCSA_QW_OFFSET(stopped_status); + stopped_status = regs_spill[offset].slot[0]; + stopped_code = regs_spill[offset].slot[1]; + + switch (stopped_status) { + case SPU_STOPPED_STATUS_P_I: + /* SPU_Status[P,I]=1. Add illegal instruction + * followed by stop-and-signal instruction after + * end of restore code. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = ILLEGAL_INSTR; + exit_instrs[2] = STOP_INSTR | stopped_code; + break; + case SPU_STOPPED_STATUS_P_H: + /* SPU_Status[P,H]=1. Add 'heq $0, $0' followed + * by stop-and-signal instruction after end of + * restore code. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = HEQ_INSTR; + exit_instrs[2] = STOP_INSTR | stopped_code; + break; + case SPU_STOPPED_STATUS_S_P: + /* SPU_Status[S,P]=1. Add nop instruction + * followed by 'br -4' after end of restore + * code. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = STOP_INSTR | stopped_code; + exit_instrs[2] = NOP_INSTR; + exit_instrs[3] = BR_INSTR; + break; + case SPU_STOPPED_STATUS_S_I: + /* SPU_Status[S,I]=1. Add illegal instruction + * followed by 'br -4' after end of restore code. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = ILLEGAL_INSTR; + exit_instrs[2] = NOP_INSTR; + exit_instrs[3] = BR_INSTR; + break; + case SPU_STOPPED_STATUS_I: + /* SPU_Status[I]=1. Add illegal instruction followed + * by infinite loop after end of restore sequence. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = ILLEGAL_INSTR; + exit_instrs[2] = NOP_INSTR; + exit_instrs[3] = BR_INSTR; + break; + case SPU_STOPPED_STATUS_S: + /* SPU_Status[S]=1. Add two 'nop' instructions. */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = NOP_INSTR; + exit_instrs[2] = NOP_INSTR; + exit_instrs[3] = BR_INSTR; + break; + case SPU_STOPPED_STATUS_H: + /* SPU_Status[H]=1. Add 'heq $0, $0' instruction + * after end of restore code. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = HEQ_INSTR; + exit_instrs[2] = NOP_INSTR; + exit_instrs[3] = BR_INSTR; + break; + case SPU_STOPPED_STATUS_P: + /* SPU_Status[P]=1. Add stop-and-signal instruction + * after end of restore code. + */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = STOP_INSTR | stopped_code; + break; + case SPU_STOPPED_STATUS_R: + /* SPU_Status[I,S,H,P,R]=0. Add infinite loop. */ + exit_instrs[0] = RESTORE_COMPLETE; + exit_instrs[1] = NOP_INSTR; + exit_instrs[2] = NOP_INSTR; + exit_instrs[3] = BR_INSTR; + break; + default: + /* SPU_Status[R]=1. No additonal instructions. */ + break; + } + spu_sync(); +} + +/** + * main - entry point for SPU-side context restore. + * + * This code deviates from the documented sequence in the + * following aspects: + * + * 1. The EA for LSCSA is passed from PPE in the + * signal notification channels. + * 2. The register spill area is pulled by SPU + * into LS, rather than pushed by PPE. + * 3. All 128 registers are restored by exit(). + * 4. The exit() function is modified at run + * time in order to properly restore the + * SPU_Status register. + */ +int main() +{ + addr64 lscsa_ea; + + lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1); + lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2); + fetch_regs_from_mem(lscsa_ea); + + set_event_mask(); /* Step 1. */ + set_tag_mask(); /* Step 2. */ + build_dma_list(lscsa_ea); /* Step 3. */ + restore_upper_240kb(lscsa_ea); /* Step 4. */ + /* Step 5: done by 'exit'. */ + restore_decr(); /* Step 6. */ + enqueue_putllc(lscsa_ea); /* Step 7. */ + set_tag_update(); /* Step 8. */ + read_tag_status(); /* Step 9. */ + read_llar_status(); /* Step 10. */ + write_ppu_mb(); /* Step 11. */ + write_ppuint_mb(); /* Step 12. */ + restore_fpcr(); /* Step 13. */ + restore_srr0(); /* Step 14. */ + restore_event_mask(); /* Step 15. */ + restore_tag_mask(); /* Step 16. */ + /* Step 17. done by 'exit'. */ + restore_complete(); /* Step 18. */ + + return 0; +} diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S new file mode 100644 index 000000000000..2905949debe1 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_restore_crt0.S @@ -0,0 +1,116 @@ +/* + * crt0_r.S: Entry function for SPU-side context restore. + * + * Copyright (C) 2005 IBM + * + * Entry and exit function for SPU-side of the context restore + * sequence. Sets up an initial stack frame, then branches to + * 'main'. On return, restores all 128 registers from the LSCSA + * and exits. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +.data +.align 7 +.globl regs_spill +regs_spill: +.space SIZEOF_SPU_SPILL_REGS, 0x0 + +.text +.global _start +_start: + /* Initialize the stack pointer to point to 16368 + * (16kb-16). The back chain pointer is initialized + * to NULL. + */ + il $0, 0 + il $SP, 16368 + stqd $0, 0($SP) + + /* Allocate a minimum stack frame for the called main. + * This is needed so that main has a place to save the + * link register when it calls another function. + */ + stqd $SP, -160($SP) + ai $SP, $SP, -160 + + /* Call the program's main function. */ + brsl $0, main + +.global exit +.global _exit +exit: +_exit: + /* SPU Context Restore, Step 5: Restore the remaining 112 GPRs. */ + ila $3, regs_spill + 256 +restore_regs: + lqr $4, restore_reg_insts +restore_reg_loop: + ai $4, $4, 4 + .balignl 16, 0x40200000 +restore_reg_insts: /* must be quad-word aligned. */ + lqd $16, 0($3) + lqd $17, 16($3) + lqd $18, 32($3) + lqd $19, 48($3) + andi $5, $4, 0x7F + stqr $4, restore_reg_insts + ai $3, $3, 64 + brnz $5, restore_reg_loop + + /* SPU Context Restore Step 17: Restore the first 16 GPRs. */ + lqa $0, regs_spill + 0 + lqa $1, regs_spill + 16 + lqa $2, regs_spill + 32 + lqa $3, regs_spill + 48 + lqa $4, regs_spill + 64 + lqa $5, regs_spill + 80 + lqa $6, regs_spill + 96 + lqa $7, regs_spill + 112 + lqa $8, regs_spill + 128 + lqa $9, regs_spill + 144 + lqa $10, regs_spill + 160 + lqa $11, regs_spill + 176 + lqa $12, regs_spill + 192 + lqa $13, regs_spill + 208 + lqa $14, regs_spill + 224 + lqa $15, regs_spill + 240 + + /* Under normal circumstances, the 'exit' function + * terminates with 'stop SPU_RESTORE_COMPLETE', + * indicating that the SPU-side restore code has + * completed. + * + * However it is possible that instructions immediately + * following the 'stop 0x3ffc' have been modified at run + * time so as to recreate the exact SPU_Status settings + * from the application, e.g. illegal instruciton, halt, + * etc. + */ +.global exit_fini +.global _exit_fini +exit_fini: +_exit_fini: + stop SPU_RESTORE_COMPLETE + stop 0 + stop 0 + stop 0 + + /* Pad the size of this crt0.o to be multiple of 16 bytes. */ +.balignl 16, 0x0 diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c new file mode 100644 index 000000000000..196033b8a579 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_save.c @@ -0,0 +1,195 @@ +/* + * spu_save.c + * + * (C) Copyright IBM Corp. 2005 + * + * SPU-side context save sequence outlined in + * Synergistic Processor Element Book IV + * + * Author: Mark Nutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef LS_SIZE +#define LS_SIZE 0x40000 /* 256K (in bytes) */ +#endif + +typedef unsigned int u32; +typedef unsigned long long u64; + +#include +#include +#include "spu_utils.h" + +static inline void save_event_mask(void) +{ + unsigned int offset; + + /* Save, Step 2: + * Read the SPU_RdEventMsk channel and save to the LSCSA. + */ + offset = LSCSA_QW_OFFSET(event_mask); + regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask); +} + +static inline void save_tag_mask(void) +{ + unsigned int offset; + + /* Save, Step 3: + * Read the SPU_RdTagMsk channel and save to the LSCSA. + */ + offset = LSCSA_QW_OFFSET(tag_mask); + regs_spill[offset].slot[0] = spu_readch(MFC_RdTagMask); +} + +static inline void save_upper_240kb(addr64 lscsa_ea) +{ + unsigned int ls = 16384; + unsigned int list = (unsigned int)&dma_list[0]; + unsigned int size = sizeof(dma_list); + unsigned int tag_id = 0; + unsigned int cmd = 0x24; /* PUTL */ + + /* Save, Step 7: + * Enqueue the PUTL command (tag 0) to the MFC SPU command + * queue to transfer the remaining 240 kb of LS to CSA. + */ + spu_writech(MFC_LSA, ls); + spu_writech(MFC_EAH, lscsa_ea.ui[0]); + spu_writech(MFC_EAL, list); + spu_writech(MFC_Size, size); + spu_writech(MFC_TagID, tag_id); + spu_writech(MFC_Cmd, cmd); +} + +static inline void save_fpcr(void) +{ + // vector unsigned int fpcr; + unsigned int offset; + + /* Save, Step 9: + * Issue the floating-point status and control register + * read instruction, and save to the LSCSA. + */ + offset = LSCSA_QW_OFFSET(fpcr); + regs_spill[offset].v = spu_mffpscr(); +} + +static inline void save_decr(void) +{ + unsigned int offset; + + /* Save, Step 10: + * Read and save the SPU_RdDec channel data to + * the LSCSA. + */ + offset = LSCSA_QW_OFFSET(decr); + regs_spill[offset].slot[0] = spu_readch(SPU_RdDec); +} + +static inline void save_srr0(void) +{ + unsigned int offset; + + /* Save, Step 11: + * Read and save the SPU_WSRR0 channel data to + * the LSCSA. + */ + offset = LSCSA_QW_OFFSET(srr0); + regs_spill[offset].slot[0] = spu_readch(SPU_RdSRR0); +} + +static inline void spill_regs_to_mem(addr64 lscsa_ea) +{ + unsigned int ls = (unsigned int)®s_spill[0]; + unsigned int size = sizeof(regs_spill); + unsigned int tag_id = 0; + unsigned int cmd = 0x20; /* PUT */ + + /* Save, Step 13: + * Enqueue a PUT command (tag 0) to send the LSCSA + * to the CSA. + */ + spu_writech(MFC_LSA, ls); + spu_writech(MFC_EAH, lscsa_ea.ui[0]); + spu_writech(MFC_EAL, lscsa_ea.ui[1]); + spu_writech(MFC_Size, size); + spu_writech(MFC_TagID, tag_id); + spu_writech(MFC_Cmd, cmd); +} + +static inline void enqueue_sync(addr64 lscsa_ea) +{ + unsigned int tag_id = 0; + unsigned int cmd = 0xCC; + + /* Save, Step 14: + * Enqueue an MFC_SYNC command (tag 0). + */ + spu_writech(MFC_TagID, tag_id); + spu_writech(MFC_Cmd, cmd); +} + +static inline void save_complete(void) +{ + /* Save, Step 18: + * Issue a stop-and-signal instruction indicating + * "save complete". Note: This function will not + * return!! + */ + spu_stop(SPU_SAVE_COMPLETE); +} + +/** + * main - entry point for SPU-side context save. + * + * This code deviates from the documented sequence as follows: + * + * 1. The EA for LSCSA is passed from PPE in the + * signal notification channels. + * 2. All 128 registers are saved by crt0.o. + */ +int main() +{ + addr64 lscsa_ea; + + lscsa_ea.ui[0] = spu_readch(SPU_RdSigNotify1); + lscsa_ea.ui[1] = spu_readch(SPU_RdSigNotify2); + + /* Step 1: done by exit(). */ + save_event_mask(); /* Step 2. */ + save_tag_mask(); /* Step 3. */ + set_event_mask(); /* Step 4. */ + set_tag_mask(); /* Step 5. */ + build_dma_list(lscsa_ea); /* Step 6. */ + save_upper_240kb(lscsa_ea); /* Step 7. */ + /* Step 8: done by exit(). */ + save_fpcr(); /* Step 9. */ + save_decr(); /* Step 10. */ + save_srr0(); /* Step 11. */ + enqueue_putllc(lscsa_ea); /* Step 12. */ + spill_regs_to_mem(lscsa_ea); /* Step 13. */ + enqueue_sync(lscsa_ea); /* Step 14. */ + set_tag_update(); /* Step 15. */ + read_tag_status(); /* Step 16. */ + read_llar_status(); /* Step 17. */ + save_complete(); /* Step 18. */ + + return 0; +} diff --git a/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S new file mode 100644 index 000000000000..6659d6a66faa --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_save_crt0.S @@ -0,0 +1,102 @@ +/* + * crt0_s.S: Entry function for SPU-side context save. + * + * Copyright (C) 2005 IBM + * + * Entry function for SPU-side of the context save sequence. + * Saves all 128 GPRs, sets up an initial stack frame, then + * branches to 'main'. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +.data +.align 7 +.globl regs_spill +regs_spill: +.space SIZEOF_SPU_SPILL_REGS, 0x0 + +.text +.global _start +_start: + /* SPU Context Save Step 1: Save the first 16 GPRs. */ + stqa $0, regs_spill + 0 + stqa $1, regs_spill + 16 + stqa $2, regs_spill + 32 + stqa $3, regs_spill + 48 + stqa $4, regs_spill + 64 + stqa $5, regs_spill + 80 + stqa $6, regs_spill + 96 + stqa $7, regs_spill + 112 + stqa $8, regs_spill + 128 + stqa $9, regs_spill + 144 + stqa $10, regs_spill + 160 + stqa $11, regs_spill + 176 + stqa $12, regs_spill + 192 + stqa $13, regs_spill + 208 + stqa $14, regs_spill + 224 + stqa $15, regs_spill + 240 + + /* SPU Context Save, Step 8: Save the remaining 112 GPRs. */ + ila $3, regs_spill + 256 +save_regs: + lqr $4, save_reg_insts +save_reg_loop: + ai $4, $4, 4 + .balignl 16, 0x40200000 +save_reg_insts: /* must be quad-word aligned. */ + stqd $16, 0($3) + stqd $17, 16($3) + stqd $18, 32($3) + stqd $19, 48($3) + andi $5, $4, 0x7F + stqr $4, save_reg_insts + ai $3, $3, 64 + brnz $5, save_reg_loop + + /* Initialize the stack pointer to point to 16368 + * (16kb-16). The back chain pointer is initialized + * to NULL. + */ + il $0, 0 + il $SP, 16368 + stqd $0, 0($SP) + + /* Allocate a minimum stack frame for the called main. + * This is needed so that main has a place to save the + * link register when it calls another function. + */ + stqd $SP, -160($SP) + ai $SP, $SP, -160 + + /* Call the program's main function. */ + brsl $0, main + + /* In this case main should not return; if it does + * there has been an error in the sequence. Execute + * stop-and-signal with code=0. + */ +.global exit +.global _exit +exit: +_exit: + stop 0x0 + + /* Pad the size of this crt0.o to be multiple of 16 bytes. */ +.balignl 16, 0x0 + diff --git a/arch/powerpc/platforms/cell/spufs/spu_utils.h b/arch/powerpc/platforms/cell/spufs/spu_utils.h new file mode 100644 index 000000000000..58359feb6c95 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/spu_utils.h @@ -0,0 +1,160 @@ +/* + * utils.h: Utilities for SPU-side of the context switch operation. + * + * (C) Copyright IBM 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _SPU_CONTEXT_UTILS_H_ +#define _SPU_CONTEXT_UTILS_H_ + +/* + * 64-bit safe EA. + */ +typedef union { + unsigned long long ull; + unsigned int ui[2]; +} addr64; + +/* + * 128-bit register template. + */ +typedef union { + unsigned int slot[4]; + vector unsigned int v; +} spu_reg128v; + +/* + * DMA list structure. + */ +struct dma_list_elem { + unsigned int size; + unsigned int ea_low; +}; + +/* + * Declare storage for 8-byte aligned DMA list. + */ +struct dma_list_elem dma_list[15] __attribute__ ((aligned(8))); + +/* + * External definition for storage + * declared in crt0. + */ +extern spu_reg128v regs_spill[NR_SPU_SPILL_REGS]; + +/* + * Compute LSCSA byte offset for a given field. + */ +static struct spu_lscsa *dummy = (struct spu_lscsa *)0; +#define LSCSA_BYTE_OFFSET(_field) \ + ((char *)(&(dummy->_field)) - (char *)(&(dummy->gprs[0].slot[0]))) +#define LSCSA_QW_OFFSET(_field) (LSCSA_BYTE_OFFSET(_field) >> 4) + +static inline void set_event_mask(void) +{ + unsigned int event_mask = 0; + + /* Save, Step 4: + * Restore, Step 1: + * Set the SPU_RdEventMsk channel to zero to mask + * all events. + */ + spu_writech(SPU_WrEventMask, event_mask); +} + +static inline void set_tag_mask(void) +{ + unsigned int tag_mask = 1; + + /* Save, Step 5: + * Restore, Step 2: + * Set the SPU_WrTagMsk channel to '01' to unmask + * only tag group 0. + */ + spu_writech(MFC_WrTagMask, tag_mask); +} + +static inline void build_dma_list(addr64 lscsa_ea) +{ + unsigned int ea_low; + int i; + + /* Save, Step 6: + * Restore, Step 3: + * Update the effective address for the CSA in the + * pre-canned DMA-list in local storage. + */ + ea_low = lscsa_ea.ui[1]; + ea_low += LSCSA_BYTE_OFFSET(ls[16384]); + + for (i = 0; i < 15; i++, ea_low += 16384) { + dma_list[i].size = 16384; + dma_list[i].ea_low = ea_low; + } +} + +static inline void enqueue_putllc(addr64 lscsa_ea) +{ + unsigned int ls = 0; + unsigned int size = 128; + unsigned int tag_id = 0; + unsigned int cmd = 0xB4; /* PUTLLC */ + + /* Save, Step 12: + * Restore, Step 7: + * Send a PUTLLC (tag 0) command to the MFC using + * an effective address in the CSA in order to + * remove any possible lock-line reservation. + */ + spu_writech(MFC_LSA, ls); + spu_writech(MFC_EAH, lscsa_ea.ui[0]); + spu_writech(MFC_EAL, lscsa_ea.ui[1]); + spu_writech(MFC_Size, size); + spu_writech(MFC_TagID, tag_id); + spu_writech(MFC_Cmd, cmd); +} + +static inline void set_tag_update(void) +{ + unsigned int update_any = 1; + + /* Save, Step 15: + * Restore, Step 8: + * Write the MFC_TagUpdate channel with '01'. + */ + spu_writech(MFC_WrTagUpdate, update_any); +} + +static inline void read_tag_status(void) +{ + /* Save, Step 16: + * Restore, Step 9: + * Read the MFC_TagStat channel data. + */ + spu_readch(MFC_RdTagStat); +} + +static inline void read_llar_status(void) +{ + /* Save, Step 17: + * Restore, Step 10: + * Read the MFC_AtomicStat channel data. + */ + spu_readch(MFC_RdAtomicStat); +} + +#endif /* _SPU_CONTEXT_UTILS_H_ */ -- cgit v1.2.3 From 8b3d6663c6217e4f50cc3720935a96da9b984117 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 15 Nov 2005 15:53:52 -0500 Subject: [PATCH] spufs: cooperative scheduler support This adds a scheduler for SPUs to make it possible to use more logical SPUs than physical ones are present in the system. Currently, there is no support for preempting a running SPU thread, they have to leave the SPU by either triggering an event on the SPU that causes it to return to the owning thread or by sending a signal to it. This patch also adds operations that enable accessing an SPU in either runnable or saved state. We use an RW semaphore to protect the state of the SPU from changing underneath us, while we are holding it readable. In order to change the state, it is acquired writeable and a context save or restore is executed before downgrading the semaphore to read-only. From: Mark Nutter , Uli Weigand Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/setup.c | 75 +++ arch/powerpc/platforms/cell/spu_base.c | 138 +++--- arch/powerpc/platforms/cell/spufs/Makefile | 2 +- arch/powerpc/platforms/cell/spufs/backing_ops.c | 252 ++++++++++ arch/powerpc/platforms/cell/spufs/context.c | 114 ++++- arch/powerpc/platforms/cell/spufs/file.c | 599 +++++++++++++++++------- arch/powerpc/platforms/cell/spufs/hw_ops.c | 206 ++++++++ arch/powerpc/platforms/cell/spufs/inode.c | 62 ++- arch/powerpc/platforms/cell/spufs/sched.c | 419 +++++++++++++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 55 ++- arch/powerpc/platforms/cell/spufs/switch.c | 51 +- arch/powerpc/platforms/cell/spufs/syscalls.c | 10 +- include/asm-powerpc/spu.h | 19 +- include/asm-powerpc/spu_csa.h | 1 + 14 files changed, 1680 insertions(+), 323 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spufs/backing_ops.c create mode 100644 arch/powerpc/platforms/cell/spufs/hw_ops.c create mode 100644 arch/powerpc/platforms/cell/spufs/sched.c diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index d45dc18855a5..25e0f68d0531 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -68,6 +68,77 @@ void cell_show_cpuinfo(struct seq_file *m) of_node_put(root); } +#ifdef CONFIG_SPARSEMEM +static int __init find_spu_node_id(struct device_node *spe) +{ + unsigned int *id; +#ifdef CONFIG_NUMA + struct device_node *cpu; + cpu = spe->parent->parent; + id = (unsigned int *)get_property(cpu, "node-id", NULL); +#else + id = NULL; +#endif + return id ? *id : 0; +} + +static void __init cell_spuprop_present(struct device_node *spe, + const char *prop, int early) +{ + struct address_prop { + unsigned long address; + unsigned int len; + } __attribute__((packed)) *p; + int proplen; + + unsigned long start_pfn, end_pfn, pfn; + int node_id; + + p = (void*)get_property(spe, prop, &proplen); + WARN_ON(proplen != sizeof (*p)); + + node_id = find_spu_node_id(spe); + + start_pfn = p->address >> PAGE_SHIFT; + end_pfn = (p->address + p->len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + /* We need to call memory_present *before* the call to sparse_init, + but we can initialize the page structs only *after* that call. + Thus, we're being called twice. */ + if (early) + memory_present(node_id, start_pfn, end_pfn); + else { + /* As the pages backing SPU LS and I/O are outside the range + of regular memory, their page structs were not initialized + by free_area_init. Do it here instead. */ + for (pfn = start_pfn; pfn < end_pfn; pfn++) { + struct page *page = pfn_to_page(pfn); + set_page_links(page, ZONE_DMA, node_id, pfn); + set_page_count(page, 0); + reset_page_mapcount(page); + SetPageReserved(page); + INIT_LIST_HEAD(&page->lru); + } + } +} + +static void __init cell_spumem_init(int early) +{ + struct device_node *node; + for (node = of_find_node_by_type(NULL, "spe"); + node; node = of_find_node_by_type(node, "spe")) { + cell_spuprop_present(node, "local-store", early); + cell_spuprop_present(node, "problem", early); + cell_spuprop_present(node, "priv1", early); + cell_spuprop_present(node, "priv2", early); + } +} +#else +static void __init cell_spumem_init(int early) +{ +} +#endif + static void cell_progress(char *s, unsigned short hex) { printk("*** %04x : %s\n", hex, s ? s : ""); @@ -99,6 +170,8 @@ static void __init cell_setup_arch(void) #endif mmio_nvram_init(); + + cell_spumem_init(0); } /* @@ -114,6 +187,8 @@ static void __init cell_init_early(void) ppc64_interrupt_controller = IC_CELL_PIC; + cell_spumem_init(1); + DBG(" <- cell_init_early()\n"); } diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 44492d87cdf7..408c455cff08 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -69,51 +69,49 @@ static void spu_restart_dma(struct spu *spu) static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) { - struct spu_priv2 __iomem *priv2; - struct mm_struct *mm; + struct spu_priv2 __iomem *priv2 = spu->priv2; + struct mm_struct *mm = spu->mm; + u64 esid, vsid; pr_debug("%s\n", __FUNCTION__); if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) { + /* SLBs are pre-loaded for context switch, so + * we should never get here! + */ printk("%s: invalid access during switch!\n", __func__); return 1; } - - if (REGION_ID(ea) != USER_REGION_ID) { + if (!mm || (REGION_ID(ea) != USER_REGION_ID)) { + /* Future: support kernel segments so that drivers + * can use SPUs. + */ pr_debug("invalid region access at %016lx\n", ea); return 1; } - priv2 = spu->priv2; - mm = spu->mm; + esid = (ea & ESID_MASK) | SLB_ESID_V; + vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | SLB_VSID_USER; + if (in_hugepage_area(mm->context, ea)) + vsid |= SLB_VSID_L; + out_be64(&priv2->slb_index_W, spu->slb_replace); + out_be64(&priv2->slb_vsid_RW, vsid); + out_be64(&priv2->slb_esid_RW, esid); + + spu->slb_replace++; if (spu->slb_replace >= 8) spu->slb_replace = 0; - out_be64(&priv2->slb_index_W, spu->slb_replace); - out_be64(&priv2->slb_vsid_RW, - (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) - | SLB_VSID_USER); - out_be64(&priv2->slb_esid_RW, (ea & ESID_MASK) | SLB_ESID_V); - spu_restart_dma(spu); - pr_debug("set slb %d context %lx, ea %016lx, vsid %016lx, esid %016lx\n", - spu->slb_replace, mm->context.id, ea, - (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT)| SLB_VSID_USER, - (ea & ESID_MASK) | SLB_ESID_V); return 0; } extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX -static int __spu_trap_data_map(struct spu *spu, unsigned long ea) +static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) { - unsigned long dsisr; - struct spu_priv1 __iomem *priv1; - pr_debug("%s\n", __FUNCTION__); - priv1 = spu->priv1; - dsisr = in_be64(&priv1->mfc_dsisr_RW); /* Handle kernel space hash faults immediately. User hash faults need to be deferred to process context. */ @@ -129,14 +127,17 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea) return 1; } + spu->dar = ea; + spu->dsisr = dsisr; + mb(); wake_up(&spu->stop_wq); return 0; } static int __spu_trap_mailbox(struct spu *spu) { - wake_up_all(&spu->ibox_wq); - kill_fasync(&spu->ibox_fasync, SIGIO, POLLIN); + if (spu->ibox_callback) + spu->ibox_callback(spu); /* atomically disable SPU mailbox interrupts */ spin_lock(&spu->register_lock); @@ -171,8 +172,8 @@ static int __spu_trap_tag_group(struct spu *spu) static int __spu_trap_spubox(struct spu *spu) { - wake_up_all(&spu->wbox_wq); - kill_fasync(&spu->wbox_fasync, SIGIO, POLLOUT); + if (spu->wbox_callback) + spu->wbox_callback(spu); /* atomically disable SPU mailbox interrupts */ spin_lock(&spu->register_lock); @@ -220,17 +221,25 @@ static irqreturn_t spu_irq_class_1(int irq, void *data, struct pt_regs *regs) { struct spu *spu; - unsigned long stat, dar; + unsigned long stat, mask, dar, dsisr; spu = data; - stat = in_be64(&spu->priv1->int_stat_class1_RW); + + /* atomically read & clear class1 status. */ + spin_lock(&spu->register_lock); + mask = in_be64(&spu->priv1->int_mask_class1_RW); + stat = in_be64(&spu->priv1->int_stat_class1_RW) & mask; dar = in_be64(&spu->priv1->mfc_dar_RW); + dsisr = in_be64(&spu->priv1->mfc_dsisr_RW); + out_be64(&spu->priv1->mfc_dsisr_RW, 0UL); + out_be64(&spu->priv1->int_stat_class1_RW, stat); + spin_unlock(&spu->register_lock); if (stat & 1) /* segment fault */ __spu_trap_data_seg(spu, dar); if (stat & 2) { /* mapping fault */ - __spu_trap_data_map(spu, dar); + __spu_trap_data_map(spu, dar, dsisr); } if (stat & 4) /* ls compare & suspend on get */ @@ -239,7 +248,6 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) if (stat & 8) /* ls compare & suspend on put */ ; - out_be64(&spu->priv1->int_stat_class1_RW, stat); return stat ? IRQ_HANDLED : IRQ_NONE; } @@ -396,8 +404,6 @@ EXPORT_SYMBOL(spu_alloc); void spu_free(struct spu *spu) { down(&spu_mutex); - spu->ibox_fasync = NULL; - spu->wbox_fasync = NULL; list_add_tail(&spu->list, &spu_list); up(&spu_mutex); } @@ -405,15 +411,13 @@ EXPORT_SYMBOL(spu_free); static int spu_handle_mm_fault(struct spu *spu) { - struct spu_priv1 __iomem *priv1; struct mm_struct *mm = spu->mm; struct vm_area_struct *vma; u64 ea, dsisr, is_write; int ret; - priv1 = spu->priv1; - ea = in_be64(&priv1->mfc_dar_RW); - dsisr = in_be64(&priv1->mfc_dsisr_RW); + ea = spu->dar; + dsisr = spu->dsisr; #if 0 if (!IS_VALID_EA(ea)) { return -EFAULT; @@ -476,15 +480,14 @@ bad_area: static int spu_handle_pte_fault(struct spu *spu) { - struct spu_priv1 __iomem *priv1; u64 ea, dsisr, access, error = 0UL; int ret = 0; - priv1 = spu->priv1; - ea = in_be64(&priv1->mfc_dar_RW); - dsisr = in_be64(&priv1->mfc_dsisr_RW); - access = (_PAGE_PRESENT | _PAGE_USER); + ea = spu->dar; + dsisr = spu->dsisr; if (dsisr & MFC_DSISR_PTE_NOT_FOUND) { + access = (_PAGE_PRESENT | _PAGE_USER); + access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; if (hash_page(ea, access, 0x300) != 0) error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; } @@ -495,18 +498,33 @@ static int spu_handle_pte_fault(struct spu *spu) else error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR; } - if (!error) + spu->dar = 0UL; + spu->dsisr = 0UL; + if (!error) { spu_restart_dma(spu); - + } else { + __spu_trap_invalid_dma(spu); + } return ret; } +static inline int spu_pending(struct spu *spu, u32 * stat) +{ + struct spu_problem __iomem *prob = spu->problem; + u64 pte_fault; + + *stat = in_be32(&prob->spu_status_R); + pte_fault = spu->dsisr & + (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); + return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; +} + int spu_run(struct spu *spu) { struct spu_problem __iomem *prob; struct spu_priv1 __iomem *priv1; struct spu_priv2 __iomem *priv2; - unsigned long status; + u32 status; int ret; prob = spu->problem; @@ -514,21 +532,15 @@ int spu_run(struct spu *spu) priv2 = spu->priv2; /* Let SPU run. */ - spu->mm = current->mm; eieio(); out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); do { ret = wait_event_interruptible(spu->stop_wq, - (!((status = in_be32(&prob->spu_status_R)) & 0x1)) - || (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND) - || spu->class_0_pending); - - if (status & SPU_STATUS_STOPPED_BY_STOP) - ret = -EAGAIN; - else if (status & SPU_STATUS_STOPPED_BY_HALT) - ret = -EIO; - else if (in_be64(&priv1->mfc_dsisr_RW) & MFC_DSISR_PTE_NOT_FOUND) + spu_pending(spu, &status)); + + if (spu->dsisr & + (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) ret = spu_handle_pte_fault(spu); if (spu->class_0_pending) @@ -537,7 +549,9 @@ int spu_run(struct spu *spu) if (!ret && signal_pending(current)) ret = -ERESTARTSYS; - } while (!ret); + } while (!ret && !(status & + (SPU_STATUS_STOPPED_BY_STOP | + SPU_STATUS_STOPPED_BY_HALT))); /* Ensure SPU is stopped. */ out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); @@ -549,8 +563,6 @@ int spu_run(struct spu *spu) out_be64(&priv1->tlb_invalidate_entry_W, 0UL); eieio(); - spu->mm = NULL; - /* Check for SPU breakpoint. */ if (unlikely(current->ptrace & PT_PTRACED)) { status = in_be32(&prob->spu_status_R); @@ -669,19 +681,21 @@ static int __init create_spu(struct device_node *spe) spu->stop_code = 0; spu->slb_replace = 0; spu->mm = NULL; + spu->ctx = NULL; + spu->rq = NULL; + spu->pid = 0; spu->class_0_pending = 0; spu->flags = 0UL; + spu->dar = 0UL; + spu->dsisr = 0UL; spin_lock_init(&spu->register_lock); out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); out_be64(&spu->priv1->mfc_sr1_RW, 0x33); init_waitqueue_head(&spu->stop_wq); - init_waitqueue_head(&spu->wbox_wq); - init_waitqueue_head(&spu->ibox_wq); - - spu->ibox_fasync = NULL; - spu->wbox_fasync = NULL; + spu->ibox_callback = NULL; + spu->wbox_callback = NULL; down(&spu_mutex); spu->number = number++; diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index b38ab747efd7..ac86b2596d04 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_SPU_FS) += spufs.o - spufs-y += inode.o file.o context.o switch.o syscalls.o +spufs-y += sched.o backing_ops.o hw_ops.o # Rules to build switch.o with the help of SPU tool chain SPU_CROSS := spu- diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c new file mode 100644 index 000000000000..caf0984064e2 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -0,0 +1,252 @@ +/* backing_ops.c - query/set operations on saved SPU context. + * + * Copyright (C) IBM 2005 + * Author: Mark Nutter + * + * These register operations allow SPUFS to operate on saved + * SPU contexts rather than hardware. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "spufs.h" + +/* + * Reads/writes to various problem and priv2 registers require + * state changes, i.e. generate SPU events, modify channel + * counts, etc. + */ + +static void gen_spu_event(struct spu_context *ctx, u32 event) +{ + u64 ch0_cnt; + u64 ch0_data; + u64 ch1_data; + + ch0_cnt = ctx->csa.spu_chnlcnt_RW[0]; + ch0_data = ctx->csa.spu_chnldata_RW[0]; + ch1_data = ctx->csa.spu_chnldata_RW[1]; + ctx->csa.spu_chnldata_RW[0] |= event; + if ((ch0_cnt == 0) && !(ch0_data & event) && (ch1_data & event)) { + ctx->csa.spu_chnlcnt_RW[0] = 1; + } +} + +static int spu_backing_mbox_read(struct spu_context *ctx, u32 * data) +{ + u32 mbox_stat; + int ret = 0; + + spin_lock(&ctx->csa.register_lock); + mbox_stat = ctx->csa.prob.mb_stat_R; + if (mbox_stat & 0x0000ff) { + /* Read the first available word. + * Implementation note: the depth + * of pu_mb_R is currently 1. + */ + *data = ctx->csa.prob.pu_mb_R; + ctx->csa.prob.mb_stat_R &= ~(0x0000ff); + ctx->csa.spu_chnlcnt_RW[28] = 1; + gen_spu_event(ctx, MFC_PU_MAILBOX_AVAILABLE_EVENT); + ret = 4; + } + spin_unlock(&ctx->csa.register_lock); + return ret; +} + +static u32 spu_backing_mbox_stat_read(struct spu_context *ctx) +{ + return ctx->csa.prob.mb_stat_R; +} + +static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data) +{ + int ret; + + spin_lock(&ctx->csa.register_lock); + if (ctx->csa.prob.mb_stat_R & 0xff0000) { + /* Read the first available word. + * Implementation note: the depth + * of puint_mb_R is currently 1. + */ + *data = ctx->csa.priv2.puint_mb_R; + ctx->csa.prob.mb_stat_R &= ~(0xff0000); + ctx->csa.spu_chnlcnt_RW[30] = 1; + gen_spu_event(ctx, MFC_PU_INT_MAILBOX_AVAILABLE_EVENT); + ret = 4; + } else { + /* make sure we get woken up by the interrupt */ + ctx->csa.priv1.int_mask_class2_RW |= 0x1UL; + ret = 0; + } + spin_unlock(&ctx->csa.register_lock); + return ret; +} + +static int spu_backing_wbox_write(struct spu_context *ctx, u32 data) +{ + int ret; + + spin_lock(&ctx->csa.register_lock); + if ((ctx->csa.prob.mb_stat_R) & 0x00ff00) { + int slot = ctx->csa.spu_chnlcnt_RW[29]; + int avail = (ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8; + + /* We have space to write wbox_data. + * Implementation note: the depth + * of spu_mb_W is currently 4. + */ + BUG_ON(avail != (4 - slot)); + ctx->csa.spu_mailbox_data[slot] = data; + ctx->csa.spu_chnlcnt_RW[29] = ++slot; + ctx->csa.prob.mb_stat_R = (((4 - slot) & 0xff) << 8); + gen_spu_event(ctx, MFC_SPU_MAILBOX_WRITTEN_EVENT); + ret = 4; + } else { + /* make sure we get woken up by the interrupt when space + becomes available */ + ctx->csa.priv1.int_mask_class2_RW |= 0x10; + ret = 0; + } + spin_unlock(&ctx->csa.register_lock); + return ret; +} + +static u32 spu_backing_signal1_read(struct spu_context *ctx) +{ + return ctx->csa.spu_chnldata_RW[3]; +} + +static void spu_backing_signal1_write(struct spu_context *ctx, u32 data) +{ + spin_lock(&ctx->csa.register_lock); + if (ctx->csa.priv2.spu_cfg_RW & 0x1) + ctx->csa.spu_chnldata_RW[3] |= data; + else + ctx->csa.spu_chnldata_RW[3] = data; + ctx->csa.spu_chnlcnt_RW[3] = 1; + gen_spu_event(ctx, MFC_SIGNAL_1_EVENT); + spin_unlock(&ctx->csa.register_lock); +} + +static u32 spu_backing_signal2_read(struct spu_context *ctx) +{ + return ctx->csa.spu_chnldata_RW[4]; +} + +static void spu_backing_signal2_write(struct spu_context *ctx, u32 data) +{ + spin_lock(&ctx->csa.register_lock); + if (ctx->csa.priv2.spu_cfg_RW & 0x2) + ctx->csa.spu_chnldata_RW[4] |= data; + else + ctx->csa.spu_chnldata_RW[4] = data; + ctx->csa.spu_chnlcnt_RW[4] = 1; + gen_spu_event(ctx, MFC_SIGNAL_2_EVENT); + spin_unlock(&ctx->csa.register_lock); +} + +static void spu_backing_signal1_type_set(struct spu_context *ctx, u64 val) +{ + u64 tmp; + + spin_lock(&ctx->csa.register_lock); + tmp = ctx->csa.priv2.spu_cfg_RW; + if (val) + tmp |= 1; + else + tmp &= ~1; + ctx->csa.priv2.spu_cfg_RW = tmp; + spin_unlock(&ctx->csa.register_lock); +} + +static u64 spu_backing_signal1_type_get(struct spu_context *ctx) +{ + return ((ctx->csa.priv2.spu_cfg_RW & 1) != 0); +} + +static void spu_backing_signal2_type_set(struct spu_context *ctx, u64 val) +{ + u64 tmp; + + spin_lock(&ctx->csa.register_lock); + tmp = ctx->csa.priv2.spu_cfg_RW; + if (val) + tmp |= 2; + else + tmp &= ~2; + ctx->csa.priv2.spu_cfg_RW = tmp; + spin_unlock(&ctx->csa.register_lock); +} + +static u64 spu_backing_signal2_type_get(struct spu_context *ctx) +{ + return ((ctx->csa.priv2.spu_cfg_RW & 2) != 0); +} + +static u32 spu_backing_npc_read(struct spu_context *ctx) +{ + return ctx->csa.prob.spu_npc_RW; +} + +static void spu_backing_npc_write(struct spu_context *ctx, u32 val) +{ + ctx->csa.prob.spu_npc_RW = val; +} + +static u32 spu_backing_status_read(struct spu_context *ctx) +{ + return ctx->csa.prob.spu_status_R; +} + +static char *spu_backing_get_ls(struct spu_context *ctx) +{ + return ctx->csa.lscsa->ls; +} + +struct spu_context_ops spu_backing_ops = { + .mbox_read = spu_backing_mbox_read, + .mbox_stat_read = spu_backing_mbox_stat_read, + .ibox_read = spu_backing_ibox_read, + .wbox_write = spu_backing_wbox_write, + .signal1_read = spu_backing_signal1_read, + .signal1_write = spu_backing_signal1_write, + .signal2_read = spu_backing_signal2_read, + .signal2_write = spu_backing_signal2_write, + .signal1_type_set = spu_backing_signal1_type_set, + .signal1_type_get = spu_backing_signal1_type_get, + .signal2_type_set = spu_backing_signal2_type_set, + .signal2_type_get = spu_backing_signal2_type_get, + .npc_read = spu_backing_npc_read, + .npc_write = spu_backing_npc_write, + .status_read = spu_backing_status_read, + .get_ls = spu_backing_get_ls, +}; diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 41eea4576b6d..5d6195fc107d 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -20,39 +20,38 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include #include #include #include #include "spufs.h" -struct spu_context *alloc_spu_context(void) +struct spu_context *alloc_spu_context(struct address_space *local_store) { struct spu_context *ctx; ctx = kmalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) goto out; - /* Future enhancement: do not call spu_alloc() - * here. This step should be deferred until - * spu_run()!! - * - * More work needs to be done to read(), - * write(), mmap(), etc., so that operations - * are performed on CSA when the context is - * not currently being run. In this way we - * can support arbitrarily large number of - * entries in /spu, allow state queries, etc. + /* Binding to physical processor deferred + * until spu_activate(). */ - ctx->spu = spu_alloc(); - if (!ctx->spu) - goto out_free; spu_init_csa(&ctx->csa); if (!ctx->csa.lscsa) { - spu_free(ctx->spu); goto out_free; } - init_rwsem(&ctx->backing_sema); spin_lock_init(&ctx->mmio_lock); kref_init(&ctx->kref); + init_rwsem(&ctx->state_sema); + init_waitqueue_head(&ctx->ibox_wq); + init_waitqueue_head(&ctx->wbox_wq); + ctx->ibox_fasync = NULL; + ctx->wbox_fasync = NULL; + ctx->state = SPU_STATE_SAVED; + ctx->local_store = local_store; + ctx->spu = NULL; + ctx->ops = &spu_backing_ops; + ctx->owner = get_task_mm(current); goto out; out_free: kfree(ctx); @@ -65,8 +64,11 @@ void destroy_spu_context(struct kref *kref) { struct spu_context *ctx; ctx = container_of(kref, struct spu_context, kref); - if (ctx->spu) - spu_free(ctx->spu); + down_write(&ctx->state_sema); + spu_deactivate(ctx); + ctx->ibox_fasync = NULL; + ctx->wbox_fasync = NULL; + up_write(&ctx->state_sema); spu_fini_csa(&ctx->csa); kfree(ctx); } @@ -82,4 +84,80 @@ int put_spu_context(struct spu_context *ctx) return kref_put(&ctx->kref, &destroy_spu_context); } +/* give up the mm reference when the context is about to be destroyed */ +void spu_forget(struct spu_context *ctx) +{ + struct mm_struct *mm; + spu_acquire_saved(ctx); + mm = ctx->owner; + ctx->owner = NULL; + mmput(mm); + spu_release(ctx); +} + +void spu_acquire(struct spu_context *ctx) +{ + down_read(&ctx->state_sema); +} + +void spu_release(struct spu_context *ctx) +{ + up_read(&ctx->state_sema); +} + +static void spu_unmap_mappings(struct spu_context *ctx) +{ + unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); +} + +int spu_acquire_runnable(struct spu_context *ctx) +{ + int ret = 0; + down_read(&ctx->state_sema); + if (ctx->state == SPU_STATE_RUNNABLE) + return 0; + /* ctx is about to be freed, can't acquire any more */ + if (!ctx->owner) { + ret = -EINVAL; + goto out; + } + up_read(&ctx->state_sema); + + down_write(&ctx->state_sema); + if (ctx->state == SPU_STATE_SAVED) { + spu_unmap_mappings(ctx); + ret = spu_activate(ctx, 0); + ctx->state = SPU_STATE_RUNNABLE; + } + downgrade_write(&ctx->state_sema); + if (ret) + goto out; + + /* On success, we return holding the lock */ + return ret; +out: + /* Release here, to simplify calling code. */ + up_read(&ctx->state_sema); + + return ret; +} + +void spu_acquire_saved(struct spu_context *ctx) +{ + down_read(&ctx->state_sema); + + if (ctx->state == SPU_STATE_SAVED) + return; + + up_read(&ctx->state_sema); + down_write(&ctx->state_sema); + + if (ctx->state == SPU_STATE_RUNNABLE) { + spu_unmap_mappings(ctx); + spu_deactivate(ctx); + ctx->state = SPU_STATE_SAVED; + } + + downgrade_write(&ctx->state_sema); +} diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index c1e643310494..786fdb1a1cc1 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -32,11 +32,13 @@ #include "spufs.h" + static int spufs_mem_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); file->private_data = i->i_ctx; + file->f_mapping = i->i_ctx->local_store; return 0; } @@ -44,23 +46,16 @@ static ssize_t spufs_mem_read(struct file *file, char __user *buffer, size_t size, loff_t *pos) { - struct spu *spu; - struct spu_context *ctx; + struct spu_context *ctx = file->private_data; + char *local_store; int ret; - ctx = file->private_data; - spu = ctx->spu; + spu_acquire(ctx); - down_read(&ctx->backing_sema); - if (spu->number & 0/*1*/) { - ret = generic_file_read(file, buffer, size, pos); - goto out; - } + local_store = ctx->ops->get_ls(ctx); + ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); - ret = simple_read_from_buffer(buffer, size, pos, - spu->local_store, LS_SIZE); -out: - up_read(&ctx->backing_sema); + spu_release(ctx); return ret; } @@ -69,50 +64,181 @@ spufs_mem_write(struct file *file, const char __user *buffer, size_t size, loff_t *pos) { struct spu_context *ctx = file->private_data; - struct spu *spu = ctx->spu; - - if (spu->number & 0) //1) - return generic_file_write(file, buffer, size, pos); + char *local_store; + int ret; size = min_t(ssize_t, LS_SIZE - *pos, size); if (size <= 0) return -EFBIG; *pos += size; - return copy_from_user(spu->local_store + *pos - size, - buffer, size) ? -EFAULT : size; + + spu_acquire(ctx); + + local_store = ctx->ops->get_ls(ctx); + ret = copy_from_user(local_store + *pos - size, + buffer, size) ? -EFAULT : size; + + spu_release(ctx); + return ret; } +#ifdef CONFIG_SPARSEMEM +static struct page * +spufs_mem_mmap_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + struct page *page = NOPAGE_SIGBUS; + + struct spu_context *ctx = vma->vm_file->private_data; + unsigned long offset = address - vma->vm_start; + offset += vma->vm_pgoff << PAGE_SHIFT; + + spu_acquire(ctx); + + if (ctx->state == SPU_STATE_SAVED) + page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); + else + page = pfn_to_page((ctx->spu->local_store_phys + offset) + >> PAGE_SHIFT); + + spu_release(ctx); + + if (type) + *type = VM_FAULT_MINOR; + + return page; +} + +static struct vm_operations_struct spufs_mem_mmap_vmops = { + .nopage = spufs_mem_mmap_nopage, +}; + static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) { - struct spu_context *ctx = file->private_data; - struct spu *spu = ctx->spu; - unsigned long pfn; - - if (spu->number & 0) //1) - return generic_file_mmap(file, vma); + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + /* FIXME: */ vma->vm_flags |= VM_RESERVED; - vma->vm_page_prot = __pgprot(pgprot_val (vma->vm_page_prot) - | _PAGE_NO_CACHE); - pfn = spu->local_store_phys >> PAGE_SHIFT; - /* - * This will work for actual SPUs, but not for vmalloc memory: - */ - if (remap_pfn_range(vma, vma->vm_start, pfn, - vma->vm_end-vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE); + + vma->vm_ops = &spufs_mem_mmap_vmops; return 0; } +#endif static struct file_operations spufs_mem_fops = { .open = spufs_mem_open, .read = spufs_mem_read, .write = spufs_mem_write, + .llseek = generic_file_llseek, +#ifdef CONFIG_SPARSEMEM .mmap = spufs_mem_mmap, +#endif +}; + +static int +spufs_regs_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + file->private_data = i->i_ctx; + return 0; +} + +static ssize_t +spufs_regs_read(struct file *file, char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + int ret; + + spu_acquire_saved(ctx); + + ret = simple_read_from_buffer(buffer, size, pos, + lscsa->gprs, sizeof lscsa->gprs); + + spu_release(ctx); + return ret; +} + +static ssize_t +spufs_regs_write(struct file *file, const char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + int ret; + + size = min_t(ssize_t, sizeof lscsa->gprs - *pos, size); + if (size <= 0) + return -EFBIG; + *pos += size; + + spu_acquire_saved(ctx); + + ret = copy_from_user(lscsa->gprs + *pos - size, + buffer, size) ? -EFAULT : size; + + spu_release(ctx); + return ret; +} + +static struct file_operations spufs_regs_fops = { + .open = spufs_regs_open, + .read = spufs_regs_read, + .write = spufs_regs_write, .llseek = generic_file_llseek, }; +static ssize_t +spufs_fpcr_read(struct file *file, char __user * buffer, + size_t size, loff_t * pos) +{ + struct spu_context *ctx = file->private_data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + int ret; + + spu_acquire_saved(ctx); + + ret = simple_read_from_buffer(buffer, size, pos, + &lscsa->fpcr, sizeof(lscsa->fpcr)); + + spu_release(ctx); + return ret; +} + +static ssize_t +spufs_fpcr_write(struct file *file, const char __user * buffer, + size_t size, loff_t * pos) +{ + struct spu_context *ctx = file->private_data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + int ret; + + size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); + if (size <= 0) + return -EFBIG; + *pos += size; + + spu_acquire_saved(ctx); + + ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, + buffer, size) ? -EFAULT : size; + + spu_release(ctx); + return ret; +} + +static struct file_operations spufs_fpcr_fops = { + .open = spufs_regs_open, + .read = spufs_fpcr_read, + .write = spufs_fpcr_write, + .llseek = generic_file_llseek, +}; + /* generic open function for all pipe-like files */ static int spufs_pipe_open(struct inode *inode, struct file *file) { @@ -125,21 +251,19 @@ static int spufs_pipe_open(struct inode *inode, struct file *file) static ssize_t spufs_mbox_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; - struct spu_problem __iomem *prob; - u32 mbox_stat; + struct spu_context *ctx = file->private_data; u32 mbox_data; + int ret; if (len < 4) return -EINVAL; - ctx = file->private_data; - prob = ctx->spu->problem; - mbox_stat = in_be32(&prob->mb_stat_R); - if (!(mbox_stat & 0x0000ff)) - return -EAGAIN; + spu_acquire(ctx); + ret = ctx->ops->mbox_read(ctx, &mbox_data); + spu_release(ctx); - mbox_data = in_be32(&prob->pu_mb_R); + if (!ret) + return -EAGAIN; if (copy_to_user(buf, &mbox_data, sizeof mbox_data)) return -EFAULT; @@ -155,14 +279,17 @@ static struct file_operations spufs_mbox_fops = { static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; + struct spu_context *ctx = file->private_data; u32 mbox_stat; if (len < 4) return -EINVAL; - ctx = file->private_data; - mbox_stat = in_be32(&ctx->spu->problem->mb_stat_R) & 0xff; + spu_acquire(ctx); + + mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; + + spu_release(ctx); if (copy_to_user(buf, &mbox_stat, sizeof mbox_stat)) return -EFAULT; @@ -175,57 +302,78 @@ static struct file_operations spufs_mbox_stat_fops = { .read = spufs_mbox_stat_read, }; +/* + * spufs_wait + * Same as wait_event_interruptible(), except that here + * we need to call spu_release(ctx) before sleeping, and + * then spu_acquire(ctx) when awoken. + */ + +#define spufs_wait(wq, condition) \ +({ \ + int __ret = 0; \ + DEFINE_WAIT(__wait); \ + for (;;) { \ + prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + spu_release(ctx); \ + schedule(); \ + spu_acquire(ctx); \ + continue; \ + } \ + __ret = -ERESTARTSYS; \ + break; \ + } \ + finish_wait(&(wq), &__wait); \ + __ret; \ +}) + /* low-level ibox access function */ -size_t spu_ibox_read(struct spu *spu, u32 *data) +size_t spu_ibox_read(struct spu_context *ctx, u32 *data) { - int ret; - - spin_lock_irq(&spu->register_lock); + return ctx->ops->ibox_read(ctx, data); +} - if (in_be32(&spu->problem->mb_stat_R) & 0xff0000) { - /* read the first available word */ - *data = in_be64(&spu->priv2->puint_mb_R); - ret = 4; - } else { - /* make sure we get woken up by the interrupt */ - out_be64(&spu->priv1->int_mask_class2_RW, - in_be64(&spu->priv1->int_mask_class2_RW) | 0x1); - ret = 0; - } +static int spufs_ibox_fasync(int fd, struct file *file, int on) +{ + struct spu_context *ctx = file->private_data; - spin_unlock_irq(&spu->register_lock); - return ret; + return fasync_helper(fd, file, on, &ctx->ibox_fasync); } -EXPORT_SYMBOL(spu_ibox_read); -static int spufs_ibox_fasync(int fd, struct file *file, int on) +/* interrupt-level ibox callback function. */ +void spufs_ibox_callback(struct spu *spu) { - struct spu_context *ctx; - ctx = file->private_data; - return fasync_helper(fd, file, on, &ctx->spu->ibox_fasync); + struct spu_context *ctx = spu->ctx; + + wake_up_all(&ctx->ibox_wq); + kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); } static ssize_t spufs_ibox_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; + struct spu_context *ctx = file->private_data; u32 ibox_data; ssize_t ret; if (len < 4) return -EINVAL; - ctx = file->private_data; + spu_acquire(ctx); ret = 0; if (file->f_flags & O_NONBLOCK) { - if (!spu_ibox_read(ctx->spu, &ibox_data)) + if (!spu_ibox_read(ctx, &ibox_data)) ret = -EAGAIN; } else { - ret = wait_event_interruptible(ctx->spu->ibox_wq, - spu_ibox_read(ctx->spu, &ibox_data)); + ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data)); } + spu_release(ctx); + if (ret) return ret; @@ -238,16 +386,17 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf, static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) { - struct spu_context *ctx; - struct spu_problem __iomem *prob; + struct spu_context *ctx = file->private_data; u32 mbox_stat; unsigned int mask; - ctx = file->private_data; - prob = ctx->spu->problem; - mbox_stat = in_be32(&prob->mb_stat_R); + spu_acquire(ctx); + + mbox_stat = ctx->ops->mbox_stat_read(ctx); + + spu_release(ctx); - poll_wait(file, &ctx->spu->ibox_wq, wait); + poll_wait(file, &ctx->ibox_wq, wait); mask = 0; if (mbox_stat & 0xff0000) @@ -266,14 +415,15 @@ static struct file_operations spufs_ibox_fops = { static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; + struct spu_context *ctx = file->private_data; u32 ibox_stat; if (len < 4) return -EINVAL; - ctx = file->private_data; - ibox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 16) & 0xff; + spu_acquire(ctx); + ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; + spu_release(ctx); if (copy_to_user(buf, &ibox_stat, sizeof ibox_stat)) return -EFAULT; @@ -287,75 +437,69 @@ static struct file_operations spufs_ibox_stat_fops = { }; /* low-level mailbox write */ -size_t spu_wbox_write(struct spu *spu, u32 data) +size_t spu_wbox_write(struct spu_context *ctx, u32 data) { - int ret; + return ctx->ops->wbox_write(ctx, data); +} - spin_lock_irq(&spu->register_lock); +static int spufs_wbox_fasync(int fd, struct file *file, int on) +{ + struct spu_context *ctx = file->private_data; + int ret; - if (in_be32(&spu->problem->mb_stat_R) & 0x00ff00) { - /* we have space to write wbox_data to */ - out_be32(&spu->problem->spu_mb_W, data); - ret = 4; - } else { - /* make sure we get woken up by the interrupt when space - becomes available */ - out_be64(&spu->priv1->int_mask_class2_RW, - in_be64(&spu->priv1->int_mask_class2_RW) | 0x10); - ret = 0; - } + ret = fasync_helper(fd, file, on, &ctx->wbox_fasync); - spin_unlock_irq(&spu->register_lock); return ret; } -EXPORT_SYMBOL(spu_wbox_write); -static int spufs_wbox_fasync(int fd, struct file *file, int on) +/* interrupt-level wbox callback function. */ +void spufs_wbox_callback(struct spu *spu) { - struct spu_context *ctx; - ctx = file->private_data; - return fasync_helper(fd, file, on, &ctx->spu->wbox_fasync); + struct spu_context *ctx = spu->ctx; + + wake_up_all(&ctx->wbox_wq); + kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); } static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; + struct spu_context *ctx = file->private_data; u32 wbox_data; int ret; if (len < 4) return -EINVAL; - ctx = file->private_data; - if (copy_from_user(&wbox_data, buf, sizeof wbox_data)) return -EFAULT; + spu_acquire(ctx); + ret = 0; if (file->f_flags & O_NONBLOCK) { - if (!spu_wbox_write(ctx->spu, wbox_data)) + if (!spu_wbox_write(ctx, wbox_data)) ret = -EAGAIN; } else { - ret = wait_event_interruptible(ctx->spu->wbox_wq, - spu_wbox_write(ctx->spu, wbox_data)); + ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data)); } + spu_release(ctx); + return ret ? ret : sizeof wbox_data; } static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) { - struct spu_context *ctx; - struct spu_problem __iomem *prob; + struct spu_context *ctx = file->private_data; u32 mbox_stat; unsigned int mask; - ctx = file->private_data; - prob = ctx->spu->problem; - mbox_stat = in_be32(&prob->mb_stat_R); + spu_acquire(ctx); + mbox_stat = ctx->ops->mbox_stat_read(ctx); + spu_release(ctx); - poll_wait(file, &ctx->spu->wbox_wq, wait); + poll_wait(file, &ctx->wbox_wq, wait); mask = 0; if (mbox_stat & 0x00ff00) @@ -374,14 +518,15 @@ static struct file_operations spufs_wbox_fops = { static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; + struct spu_context *ctx = file->private_data; u32 wbox_stat; if (len < 4) return -EINVAL; - ctx = file->private_data; - wbox_stat = (in_be32(&ctx->spu->problem->mb_stat_R) >> 8) & 0xff; + spu_acquire(ctx); + wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; + spu_release(ctx); if (copy_to_user(buf, &wbox_stat, sizeof wbox_stat)) return -EFAULT; @@ -395,47 +540,41 @@ static struct file_operations spufs_wbox_stat_fops = { }; long spufs_run_spu(struct file *file, struct spu_context *ctx, - u32 *npc, u32 *status) + u32 *npc, u32 *status) { - struct spu_problem __iomem *prob; int ret; - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - if (!down_write_trylock(&ctx->backing_sema)) - goto out; - } else { - down_write(&ctx->backing_sema); - } + ret = spu_acquire_runnable(ctx); + if (ret) + return ret; - prob = ctx->spu->problem; - out_be32(&prob->spu_npc_RW, *npc); + ctx->ops->npc_write(ctx, *npc); ret = spu_run(ctx->spu); - *status = in_be32(&prob->spu_status_R); - *npc = in_be32(&prob->spu_npc_RW); + if (!ret) + ret = ctx->ops->status_read(ctx); - up_write(&ctx->backing_sema); + *npc = ctx->ops->npc_read(ctx); -out: + spu_release(ctx); + spu_yield(ctx); return ret; } static ssize_t spufs_signal1_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { - struct spu_context *ctx; - struct spu_problem *prob; + struct spu_context *ctx = file->private_data; u32 data; - ctx = file->private_data; - prob = ctx->spu->problem; - if (len < 4) return -EINVAL; - data = in_be32(&prob->signal_notify1); + spu_acquire(ctx); + data = ctx->ops->signal1_read(ctx); + spu_release(ctx); + if (copy_to_user(buf, &data, 4)) return -EFAULT; @@ -446,11 +585,9 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx; - struct spu_problem *prob; u32 data; ctx = file->private_data; - prob = ctx->spu->problem; if (len < 4) return -EINVAL; @@ -458,7 +595,9 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, if (copy_from_user(&data, buf, 4)) return -EFAULT; - out_be32(&prob->signal_notify1, data); + spu_acquire(ctx); + ctx->ops->signal1_write(ctx, data); + spu_release(ctx); return 4; } @@ -473,16 +612,17 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx; - struct spu_problem *prob; u32 data; ctx = file->private_data; - prob = ctx->spu->problem; if (len < 4) return -EINVAL; - data = in_be32(&prob->signal_notify2); + spu_acquire(ctx); + data = ctx->ops->signal2_read(ctx); + spu_release(ctx); + if (copy_to_user(buf, &data, 4)) return -EFAULT; @@ -493,11 +633,9 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx; - struct spu_problem *prob; u32 data; ctx = file->private_data; - prob = ctx->spu->problem; if (len < 4) return -EINVAL; @@ -505,7 +643,9 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, if (copy_from_user(&data, buf, 4)) return -EFAULT; - out_be32(&prob->signal_notify2, data); + spu_acquire(ctx); + ctx->ops->signal2_write(ctx, data); + spu_release(ctx); return 4; } @@ -519,23 +659,22 @@ static struct file_operations spufs_signal2_fops = { static void spufs_signal1_type_set(void *data, u64 val) { struct spu_context *ctx = data; - struct spu_priv2 *priv2 = ctx->spu->priv2; - u64 tmp; - spin_lock_irq(&ctx->spu->register_lock); - tmp = in_be64(&priv2->spu_cfg_RW); - if (val) - tmp |= 1; - else - tmp &= ~1; - out_be64(&priv2->spu_cfg_RW, tmp); - spin_unlock_irq(&ctx->spu->register_lock); + spu_acquire(ctx); + ctx->ops->signal1_type_set(ctx, val); + spu_release(ctx); } static u64 spufs_signal1_type_get(void *data) { struct spu_context *ctx = data; - return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0; + u64 ret; + + spu_acquire(ctx); + ret = ctx->ops->signal1_type_get(ctx); + spu_release(ctx); + + return ret; } DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, spufs_signal1_type_set, "%llu"); @@ -543,23 +682,22 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, static void spufs_signal2_type_set(void *data, u64 val) { struct spu_context *ctx = data; - struct spu_priv2 *priv2 = ctx->spu->priv2; - u64 tmp; - spin_lock_irq(&ctx->spu->register_lock); - tmp = in_be64(&priv2->spu_cfg_RW); - if (val) - tmp |= 2; - else - tmp &= ~2; - out_be64(&priv2->spu_cfg_RW, tmp); - spin_unlock_irq(&ctx->spu->register_lock); + spu_acquire(ctx); + ctx->ops->signal2_type_set(ctx, val); + spu_release(ctx); } static u64 spufs_signal2_type_get(void *data) { struct spu_context *ctx = data; - return (in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0; + u64 ret; + + spu_acquire(ctx); + ret = ctx->ops->signal2_type_get(ctx); + spu_release(ctx); + + return ret; } DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, spufs_signal2_type_set, "%llu"); @@ -567,20 +705,135 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, static void spufs_npc_set(void *data, u64 val) { struct spu_context *ctx = data; - out_be32(&ctx->spu->problem->spu_npc_RW, val); + spu_acquire(ctx); + ctx->ops->npc_write(ctx, val); + spu_release(ctx); } static u64 spufs_npc_get(void *data) { struct spu_context *ctx = data; u64 ret; - ret = in_be32(&ctx->spu->problem->spu_npc_RW); + spu_acquire(ctx); + ret = ctx->ops->npc_read(ctx); + spu_release(ctx); return ret; } DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, "%llx\n") +static void spufs_decr_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + spu_acquire_saved(ctx); + lscsa->decr.slot[0] = (u32) val; + spu_release(ctx); +} + +static u64 spufs_decr_get(void *data) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + u64 ret; + spu_acquire_saved(ctx); + ret = lscsa->decr.slot[0]; + spu_release(ctx); + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, + "%llx\n") + +static void spufs_decr_status_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + spu_acquire_saved(ctx); + lscsa->decr_status.slot[0] = (u32) val; + spu_release(ctx); +} + +static u64 spufs_decr_status_get(void *data) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + u64 ret; + spu_acquire_saved(ctx); + ret = lscsa->decr_status.slot[0]; + spu_release(ctx); + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, + spufs_decr_status_set, "%llx\n") + +static void spufs_spu_tag_mask_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + spu_acquire_saved(ctx); + lscsa->tag_mask.slot[0] = (u32) val; + spu_release(ctx); +} + +static u64 spufs_spu_tag_mask_get(void *data) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + u64 ret; + spu_acquire_saved(ctx); + ret = lscsa->tag_mask.slot[0]; + spu_release(ctx); + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_spu_tag_mask_ops, spufs_spu_tag_mask_get, + spufs_spu_tag_mask_set, "%llx\n") + +static void spufs_event_mask_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + spu_acquire_saved(ctx); + lscsa->event_mask.slot[0] = (u32) val; + spu_release(ctx); +} + +static u64 spufs_event_mask_get(void *data) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + u64 ret; + spu_acquire_saved(ctx); + ret = lscsa->event_mask.slot[0]; + spu_release(ctx); + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, + spufs_event_mask_set, "%llx\n") + +static void spufs_srr0_set(void *data, u64 val) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + spu_acquire_saved(ctx); + lscsa->srr0.slot[0] = (u32) val; + spu_release(ctx); +} + +static u64 spufs_srr0_get(void *data) +{ + struct spu_context *ctx = data; + struct spu_lscsa *lscsa = ctx->csa.lscsa; + u64 ret; + spu_acquire_saved(ctx); + ret = lscsa->srr0.slot[0]; + spu_release(ctx); + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, + "%llx\n") + struct tree_descr spufs_dir_contents[] = { { "mem", &spufs_mem_fops, 0666, }, + { "regs", &spufs_regs_fops, 0666, }, { "mbox", &spufs_mbox_fops, 0444, }, { "ibox", &spufs_ibox_fops, 0444, }, { "wbox", &spufs_wbox_fops, 0222, }, @@ -592,5 +845,11 @@ struct tree_descr spufs_dir_contents[] = { { "signal1_type", &spufs_signal1_type, 0666, }, { "signal2_type", &spufs_signal2_type, 0666, }, { "npc", &spufs_npc_ops, 0666, }, + { "fpcr", &spufs_fpcr_fops, 0666, }, + { "decr", &spufs_decr_ops, 0666, }, + { "decr_status", &spufs_decr_status_ops, 0666, }, + { "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, }, + { "event_mask", &spufs_event_mask_ops, 0666, }, + { "srr0", &spufs_srr0_ops, 0666, }, {}, }; diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c new file mode 100644 index 000000000000..2e90cae98a87 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -0,0 +1,206 @@ +/* hw_ops.c - query/set operations on active SPU context. + * + * Copyright (C) IBM 2005 + * Author: Mark Nutter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "spufs.h" + +static int spu_hw_mbox_read(struct spu_context *ctx, u32 * data) +{ + struct spu *spu = ctx->spu; + struct spu_problem __iomem *prob = spu->problem; + u32 mbox_stat; + int ret = 0; + + spin_lock_irq(&spu->register_lock); + mbox_stat = in_be32(&prob->mb_stat_R); + if (mbox_stat & 0x0000ff) { + *data = in_be32(&prob->pu_mb_R); + ret = 4; + } + spin_unlock_irq(&spu->register_lock); + return ret; +} + +static u32 spu_hw_mbox_stat_read(struct spu_context *ctx) +{ + return in_be32(&ctx->spu->problem->mb_stat_R); +} + +static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data) +{ + struct spu *spu = ctx->spu; + struct spu_problem __iomem *prob = spu->problem; + struct spu_priv1 __iomem *priv1 = spu->priv1; + struct spu_priv2 __iomem *priv2 = spu->priv2; + int ret; + + spin_lock_irq(&spu->register_lock); + if (in_be32(&prob->mb_stat_R) & 0xff0000) { + /* read the first available word */ + *data = in_be64(&priv2->puint_mb_R); + ret = 4; + } else { + /* make sure we get woken up by the interrupt */ + out_be64(&priv1->int_mask_class2_RW, + in_be64(&priv1->int_mask_class2_RW) | 0x1); + ret = 0; + } + spin_unlock_irq(&spu->register_lock); + return ret; +} + +static int spu_hw_wbox_write(struct spu_context *ctx, u32 data) +{ + struct spu *spu = ctx->spu; + struct spu_problem __iomem *prob = spu->problem; + struct spu_priv1 __iomem *priv1 = spu->priv1; + int ret; + + spin_lock_irq(&spu->register_lock); + if (in_be32(&prob->mb_stat_R) & 0x00ff00) { + /* we have space to write wbox_data to */ + out_be32(&prob->spu_mb_W, data); + ret = 4; + } else { + /* make sure we get woken up by the interrupt when space + becomes available */ + out_be64(&priv1->int_mask_class2_RW, + in_be64(&priv1->int_mask_class2_RW) | 0x10); + ret = 0; + } + spin_unlock_irq(&spu->register_lock); + return ret; +} + +static u32 spu_hw_signal1_read(struct spu_context *ctx) +{ + return in_be32(&ctx->spu->problem->signal_notify1); +} + +static void spu_hw_signal1_write(struct spu_context *ctx, u32 data) +{ + out_be32(&ctx->spu->problem->signal_notify1, data); +} + +static u32 spu_hw_signal2_read(struct spu_context *ctx) +{ + return in_be32(&ctx->spu->problem->signal_notify1); +} + +static void spu_hw_signal2_write(struct spu_context *ctx, u32 data) +{ + out_be32(&ctx->spu->problem->signal_notify2, data); +} + +static void spu_hw_signal1_type_set(struct spu_context *ctx, u64 val) +{ + struct spu *spu = ctx->spu; + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 tmp; + + spin_lock_irq(&spu->register_lock); + tmp = in_be64(&priv2->spu_cfg_RW); + if (val) + tmp |= 1; + else + tmp &= ~1; + out_be64(&priv2->spu_cfg_RW, tmp); + spin_unlock_irq(&spu->register_lock); +} + +static u64 spu_hw_signal1_type_get(struct spu_context *ctx) +{ + return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 1) != 0); +} + +static void spu_hw_signal2_type_set(struct spu_context *ctx, u64 val) +{ + struct spu *spu = ctx->spu; + struct spu_priv2 __iomem *priv2 = spu->priv2; + u64 tmp; + + spin_lock_irq(&spu->register_lock); + tmp = in_be64(&priv2->spu_cfg_RW); + if (val) + tmp |= 2; + else + tmp &= ~2; + out_be64(&priv2->spu_cfg_RW, tmp); + spin_unlock_irq(&spu->register_lock); +} + +static u64 spu_hw_signal2_type_get(struct spu_context *ctx) +{ + return ((in_be64(&ctx->spu->priv2->spu_cfg_RW) & 2) != 0); +} + +static u32 spu_hw_npc_read(struct spu_context *ctx) +{ + return in_be32(&ctx->spu->problem->spu_npc_RW); +} + +static void spu_hw_npc_write(struct spu_context *ctx, u32 val) +{ + out_be32(&ctx->spu->problem->spu_npc_RW, val); +} + +static u32 spu_hw_status_read(struct spu_context *ctx) +{ + return in_be32(&ctx->spu->problem->spu_status_R); +} + +static char *spu_hw_get_ls(struct spu_context *ctx) +{ + return ctx->spu->local_store; +} + +struct spu_context_ops spu_hw_ops = { + .mbox_read = spu_hw_mbox_read, + .mbox_stat_read = spu_hw_mbox_stat_read, + .ibox_read = spu_hw_ibox_read, + .wbox_write = spu_hw_wbox_write, + .signal1_read = spu_hw_signal1_read, + .signal1_write = spu_hw_signal1_write, + .signal2_read = spu_hw_signal2_read, + .signal2_write = spu_hw_signal2_write, + .signal1_type_set = spu_hw_signal1_type_set, + .signal1_type_get = spu_hw_signal1_type_get, + .signal2_type_set = spu_hw_signal2_type_set, + .signal2_type_get = spu_hw_signal2_type_get, + .npc_read = spu_hw_npc_read, + .npc_write = spu_hw_npc_write, + .status_read = spu_hw_status_read, + .get_ls = spu_hw_get_ls, +}; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index f7aa0a6b1ce5..2c3ba4eb41cb 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -41,24 +41,6 @@ static kmem_cache_t *spufs_inode_cache; -/* Information about the backing dev, same as ramfs */ -#if 0 -static struct backing_dev_info spufs_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | - BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY | BDI_CAP_READ_MAP | - BDI_CAP_WRITE_MAP, -}; - -static struct address_space_operations spufs_aops = { - .readpage = simple_readpage, - .prepare_write = simple_prepare_write, - .commit_write = simple_commit_write, -}; -#endif - -/* Inode operations */ - static struct inode * spufs_alloc_inode(struct super_block *sb) { @@ -111,9 +93,6 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; -/* dump_stack(); - pr_debug("ia_size %lld, i_size:%lld\n", attr->ia_size, inode->i_size); -*/ if ((attr->ia_valid & ATTR_SIZE) && (attr->ia_size != inode->i_size)) return -EINVAL; @@ -127,9 +106,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry, struct spu_context *ctx) { static struct inode_operations spufs_file_iops = { - .getattr = simple_getattr, .setattr = spufs_setattr, - .unlink = simple_unlink, }; struct inode *inode; int ret; @@ -183,21 +160,32 @@ out: static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) { - struct dentry *dentry; + struct dentry *dentry, *tmp; + struct spu_context *ctx; int err; - spin_lock(&dcache_lock); /* remove all entries */ err = 0; - list_for_each_entry(dentry, &dir_dentry->d_subdirs, d_child) { - if (d_unhashed(dentry) || !dentry->d_inode) - continue; - atomic_dec(&dentry->d_count); + list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) { + spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); - __d_drop(dentry); - spin_unlock(&dentry->d_lock); + if (!(d_unhashed(dentry)) && dentry->d_inode) { + dget_locked(dentry); + __d_drop(dentry); + spin_unlock(&dentry->d_lock); + simple_unlink(dir_dentry->d_inode, dentry); + spin_unlock(&dcache_lock); + dput(dentry); + } else { + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + } } - spin_unlock(&dcache_lock); + + /* We have to give up the mm_struct */ + ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx; + spu_forget(ctx); + if (!err) { shrink_dcache_parent(dir_dentry); err = simple_rmdir(root, dir_dentry); @@ -249,7 +237,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) inode->i_gid = dir->i_gid; inode->i_mode &= S_ISGID; } - ctx = alloc_spu_context(); + ctx = alloc_spu_context(inode->i_mapping); SPUFS_I(inode)->i_ctx = ctx; if (!ctx) goto out_iput; @@ -368,7 +356,8 @@ spufs_parse_options(char *options, struct inode *root) } static int -spufs_create_root(struct super_block *sb, void *data) { +spufs_create_root(struct super_block *sb, void *data) +{ struct inode *inode; int ret; @@ -441,6 +430,10 @@ static int spufs_init(void) if (!spufs_inode_cache) goto out; + if (spu_sched_init() != 0) { + kmem_cache_destroy(spufs_inode_cache); + goto out; + } ret = register_filesystem(&spufs_type); if (ret) goto out_cache; @@ -459,6 +452,7 @@ module_init(spufs_init); static void spufs_exit(void) { + spu_sched_exit(); unregister_spu_syscalls(&spufs_calls); unregister_filesystem(&spufs_type); kmem_cache_destroy(spufs_inode_cache); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c new file mode 100644 index 000000000000..c0d9d83a9ac3 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -0,0 +1,419 @@ +/* sched.c - SPU scheduler. + * + * Copyright (C) IBM 2005 + * Author: Mark Nutter + * + * SPU scheduler, based on Linux thread priority. For now use + * a simple "cooperative" yield model with no preemption. SPU + * scheduling will eventually be preemptive: When a thread with + * a higher static priority gets ready to run, then an active SPU + * context will be preempted and returned to the waitq. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define DEBUG 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "spufs.h" + +#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) +struct spu_prio_array { + atomic_t nr_blocked; + unsigned long bitmap[SPU_BITMAP_SIZE]; + wait_queue_head_t waitq[MAX_PRIO]; +}; + +/* spu_runqueue - This is the main runqueue data structure for SPUs. */ +struct spu_runqueue { + struct semaphore sem; + unsigned long nr_active; + unsigned long nr_idle; + unsigned long nr_switches; + struct list_head active_list; + struct list_head idle_list; + struct spu_prio_array prio; +}; + +static struct spu_runqueue *spu_runqueues = NULL; + +static inline struct spu_runqueue *spu_rq(void) +{ + /* Future: make this a per-NODE array, + * and use cpu_to_node(smp_processor_id()) + */ + return spu_runqueues; +} + +static inline struct spu *del_idle(struct spu_runqueue *rq) +{ + struct spu *spu; + + BUG_ON(rq->nr_idle <= 0); + BUG_ON(list_empty(&rq->idle_list)); + /* Future: Move SPU out of low-power SRI state. */ + spu = list_entry(rq->idle_list.next, struct spu, sched_list); + list_del_init(&spu->sched_list); + rq->nr_idle--; + return spu; +} + +static inline void del_active(struct spu_runqueue *rq, struct spu *spu) +{ + BUG_ON(rq->nr_active <= 0); + BUG_ON(list_empty(&rq->active_list)); + list_del_init(&spu->sched_list); + rq->nr_active--; +} + +static inline void add_idle(struct spu_runqueue *rq, struct spu *spu) +{ + /* Future: Put SPU into low-power SRI state. */ + list_add_tail(&spu->sched_list, &rq->idle_list); + rq->nr_idle++; +} + +static inline void add_active(struct spu_runqueue *rq, struct spu *spu) +{ + rq->nr_active++; + rq->nr_switches++; + list_add_tail(&spu->sched_list, &rq->active_list); +} + +static void prio_wakeup(struct spu_runqueue *rq) +{ + if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) { + int best = sched_find_first_bit(rq->prio.bitmap); + if (best < MAX_PRIO) { + wait_queue_head_t *wq = &rq->prio.waitq[best]; + wake_up_interruptible_nr(wq, 1); + } + } +} + +static void prio_wait(struct spu_runqueue *rq, u64 flags) +{ + int prio = current->prio; + wait_queue_head_t *wq = &rq->prio.waitq[prio]; + DEFINE_WAIT(wait); + + __set_bit(prio, rq->prio.bitmap); + atomic_inc(&rq->prio.nr_blocked); + prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE); + if (!signal_pending(current)) { + up(&rq->sem); + pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__, + current->pid, current->prio); + schedule(); + down(&rq->sem); + } + finish_wait(wq, &wait); + atomic_dec(&rq->prio.nr_blocked); + if (!waitqueue_active(wq)) + __clear_bit(prio, rq->prio.bitmap); +} + +static inline int is_best_prio(struct spu_runqueue *rq) +{ + int best_prio; + + best_prio = sched_find_first_bit(rq->prio.bitmap); + return (current->prio < best_prio) ? 1 : 0; +} + +static inline void mm_needs_global_tlbie(struct mm_struct *mm) +{ + /* Global TLBIE broadcast required with SPEs. */ +#if (NR_CPUS > 1) + __cpus_setall(&mm->cpu_vm_mask, NR_CPUS); +#else + __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */ +#endif +} + +static inline void bind_context(struct spu *spu, struct spu_context *ctx) +{ + pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid, + spu->number); + spu->ctx = ctx; + spu->flags = 0; + ctx->spu = spu; + ctx->ops = &spu_hw_ops; + spu->pid = current->pid; + spu->prio = current->prio; + spu->mm = ctx->owner; + mm_needs_global_tlbie(spu->mm); + spu->ibox_callback = spufs_ibox_callback; + spu->wbox_callback = spufs_wbox_callback; + mb(); + spu_restore(&ctx->csa, spu); +} + +static inline void unbind_context(struct spu *spu, struct spu_context *ctx) +{ + pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__, + spu->pid, spu->number); + spu_save(&ctx->csa, spu); + ctx->state = SPU_STATE_SAVED; + spu->ibox_callback = NULL; + spu->wbox_callback = NULL; + spu->mm = NULL; + spu->pid = 0; + spu->prio = MAX_PRIO; + ctx->ops = &spu_backing_ops; + ctx->spu = NULL; + spu->ctx = NULL; +} + +static struct spu *preempt_active(struct spu_runqueue *rq) +{ + struct list_head *p; + struct spu_context *ctx; + struct spu *spu; + + /* Future: implement real preemption. For now just + * boot a lower priority ctx that is in "detached" + * state, i.e. on a processor but not currently in + * spu_run(). + */ + list_for_each(p, &rq->active_list) { + spu = list_entry(p, struct spu, sched_list); + if (current->prio < spu->prio) { + ctx = spu->ctx; + if (down_write_trylock(&ctx->state_sema)) { + if (ctx->state != SPU_STATE_RUNNABLE) { + up_write(&ctx->state_sema); + continue; + } + pr_debug("%s: booting pid=%d from SPU %d\n", + __FUNCTION__, spu->pid, spu->number); + del_active(rq, spu); + up(&rq->sem); + unbind_context(spu, ctx); + up_write(&ctx->state_sema); + return spu; + } + } + } + return NULL; +} + +static struct spu *get_idle_spu(u64 flags) +{ + struct spu_runqueue *rq; + struct spu *spu = NULL; + + rq = spu_rq(); + down(&rq->sem); + for (;;) { + if (rq->nr_idle > 0) { + if (is_best_prio(rq)) { + /* Fall through. */ + spu = del_idle(rq); + break; + } else { + prio_wakeup(rq); + up(&rq->sem); + yield(); + if (signal_pending(current)) { + return NULL; + } + rq = spu_rq(); + down(&rq->sem); + continue; + } + } else { + if (is_best_prio(rq)) { + if ((spu = preempt_active(rq)) != NULL) + return spu; + } + prio_wait(rq, flags); + if (signal_pending(current)) { + prio_wakeup(rq); + spu = NULL; + break; + } + continue; + } + } + up(&rq->sem); + return spu; +} + +static void put_idle_spu(struct spu *spu) +{ + struct spu_runqueue *rq = spu->rq; + + down(&rq->sem); + add_idle(rq, spu); + prio_wakeup(rq); + up(&rq->sem); +} + +static int get_active_spu(struct spu *spu) +{ + struct spu_runqueue *rq = spu->rq; + struct list_head *p; + struct spu *tmp; + int rc = 0; + + down(&rq->sem); + list_for_each(p, &rq->active_list) { + tmp = list_entry(p, struct spu, sched_list); + if (tmp == spu) { + del_active(rq, spu); + rc = 1; + break; + } + } + up(&rq->sem); + return rc; +} + +static void put_active_spu(struct spu *spu) +{ + struct spu_runqueue *rq = spu->rq; + + down(&rq->sem); + add_active(rq, spu); + up(&rq->sem); +} + +/* Lock order: + * spu_activate() & spu_deactivate() require the + * caller to have down_write(&ctx->state_sema). + * + * The rq->sem is breifly held (inside or outside a + * given ctx lock) for list management, but is never + * held during save/restore. + */ + +int spu_activate(struct spu_context *ctx, u64 flags) +{ + struct spu *spu; + + if (ctx->spu) + return 0; + spu = get_idle_spu(flags); + if (!spu) + return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN; + bind_context(spu, ctx); + put_active_spu(spu); + return 0; +} + +void spu_deactivate(struct spu_context *ctx) +{ + struct spu *spu; + int needs_idle; + + spu = ctx->spu; + if (!spu) + return; + needs_idle = get_active_spu(spu); + unbind_context(spu, ctx); + if (needs_idle) + put_idle_spu(spu); +} + +void spu_yield(struct spu_context *ctx) +{ + struct spu *spu; + + if (!down_write_trylock(&ctx->state_sema)) + return; + spu = ctx->spu; + if ((ctx->state == SPU_STATE_RUNNABLE) && + (sched_find_first_bit(spu->rq->prio.bitmap) <= current->prio)) { + pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number); + spu_deactivate(ctx); + ctx->state = SPU_STATE_SAVED; + } + up_write(&ctx->state_sema); +} + +int __init spu_sched_init(void) +{ + struct spu_runqueue *rq; + struct spu *spu; + int i; + + rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL); + if (!rq) { + printk(KERN_WARNING "%s: Unable to allocate runqueues.\n", + __FUNCTION__); + return 1; + } + memset(rq, 0, sizeof(struct spu_runqueue)); + init_MUTEX(&rq->sem); + INIT_LIST_HEAD(&rq->active_list); + INIT_LIST_HEAD(&rq->idle_list); + rq->nr_active = 0; + rq->nr_idle = 0; + rq->nr_switches = 0; + atomic_set(&rq->prio.nr_blocked, 0); + for (i = 0; i < MAX_PRIO; i++) { + init_waitqueue_head(&rq->prio.waitq[i]); + __clear_bit(i, rq->prio.bitmap); + } + __set_bit(MAX_PRIO, rq->prio.bitmap); + for (;;) { + spu = spu_alloc(); + if (!spu) + break; + pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number); + add_idle(rq, spu); + spu->rq = rq; + } + if (!rq->nr_idle) { + printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__); + kfree(rq); + return 1; + } + return 0; +} + +void __exit spu_sched_exit(void) +{ + struct spu_runqueue *rq = spu_rq(); + struct spu *spu; + + if (!rq) { + printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__); + return; + } + while (rq->nr_idle > 0) { + spu = del_idle(rq); + if (!spu) + break; + spu_free(spu); + } + kfree(rq); +} diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 67aff57faf60..93c6a0537562 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -35,15 +35,50 @@ enum { SPUFS_MAGIC = 0x23c9b64e, }; +struct spu_context_ops; + struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ - struct rw_semaphore backing_sema; /* protects the above */ spinlock_t mmio_lock; /* protects mmio access */ + struct address_space *local_store;/* local store backing store */ + + enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; + struct rw_semaphore state_sema; + + struct mm_struct *owner; struct kref kref; + wait_queue_head_t ibox_wq; + wait_queue_head_t wbox_wq; + struct fasync_struct *ibox_fasync; + struct fasync_struct *wbox_fasync; + struct spu_context_ops *ops; +}; + +/* SPU context query/set operations. */ +struct spu_context_ops { + int (*mbox_read) (struct spu_context * ctx, u32 * data); + u32(*mbox_stat_read) (struct spu_context * ctx); + int (*ibox_read) (struct spu_context * ctx, u32 * data); + int (*wbox_write) (struct spu_context * ctx, u32 data); + u32(*signal1_read) (struct spu_context * ctx); + void (*signal1_write) (struct spu_context * ctx, u32 data); + u32(*signal2_read) (struct spu_context * ctx); + void (*signal2_write) (struct spu_context * ctx, u32 data); + void (*signal1_type_set) (struct spu_context * ctx, u64 val); + u64(*signal1_type_get) (struct spu_context * ctx); + void (*signal2_type_set) (struct spu_context * ctx, u64 val); + u64(*signal2_type_get) (struct spu_context * ctx); + u32(*npc_read) (struct spu_context * ctx); + void (*npc_write) (struct spu_context * ctx, u32 data); + u32(*status_read) (struct spu_context * ctx); + char*(*get_ls) (struct spu_context * ctx); }; +extern struct spu_context_ops spu_hw_ops; +extern struct spu_context_ops spu_backing_ops; + struct spufs_inode_info { struct spu_context *i_ctx; struct inode vfs_inode; @@ -60,14 +95,28 @@ long spufs_create_thread(struct nameidata *nd, const char *name, unsigned int flags, mode_t mode); /* context management */ -struct spu_context * alloc_spu_context(void); +struct spu_context * alloc_spu_context(struct address_space *local_store); void destroy_spu_context(struct kref *kref); struct spu_context * get_spu_context(struct spu_context *ctx); int put_spu_context(struct spu_context *ctx); +void spu_forget(struct spu_context *ctx); void spu_acquire(struct spu_context *ctx); void spu_release(struct spu_context *ctx); -void spu_acquire_runnable(struct spu_context *ctx); +int spu_acquire_runnable(struct spu_context *ctx); void spu_acquire_saved(struct spu_context *ctx); +int spu_activate(struct spu_context *ctx, u64 flags); +void spu_deactivate(struct spu_context *ctx); +void spu_yield(struct spu_context *ctx); +int __init spu_sched_init(void); +void __exit spu_sched_exit(void); + +size_t spu_wbox_write(struct spu_context *ctx, u32 data); +size_t spu_ibox_read(struct spu_context *ctx, u32 *data); + +/* irq callback funcs. */ +void spufs_ibox_callback(struct spu *spu); +void spufs_wbox_callback(struct spu *spu); + #endif diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 70345b0524fc..51266257b0a5 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -646,7 +646,7 @@ static inline void save_spu_mb(struct spu_state *csa, struct spu *spu) eieio(); csa->spu_chnlcnt_RW[29] = in_be64(&priv2->spu_chnlcnt_RW); for (i = 0; i < 4; i++) { - csa->pu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW); + csa->spu_mailbox_data[i] = in_be64(&priv2->spu_chnldata_RW); } out_be64(&priv2->spu_chnlcnt_RW, 0UL); eieio(); @@ -1667,7 +1667,7 @@ static inline void restore_spu_mb(struct spu_state *csa, struct spu *spu) eieio(); out_be64(&priv2->spu_chnlcnt_RW, csa->spu_chnlcnt_RW[29]); for (i = 0; i < 4; i++) { - out_be64(&priv2->spu_chnldata_RW, csa->pu_mailbox_data[i]); + out_be64(&priv2->spu_chnldata_RW, csa->spu_mailbox_data[i]); } eieio(); } @@ -2079,7 +2079,10 @@ int spu_save(struct spu_state *prev, struct spu *spu) acquire_spu_lock(spu); /* Step 1. */ rc = __do_spu_save(prev, spu); /* Steps 2-53. */ release_spu_lock(spu); - + if (rc) { + panic("%s failed on SPU[%d], rc=%d.\n", + __func__, spu->number, rc); + } return rc; } @@ -2098,34 +2101,31 @@ int spu_restore(struct spu_state *new, struct spu *spu) acquire_spu_lock(spu); harvest(NULL, spu); + spu->stop_code = 0; + spu->dar = 0; + spu->dsisr = 0; + spu->slb_replace = 0; + spu->class_0_pending = 0; rc = __do_spu_restore(new, spu); release_spu_lock(spu); - + if (rc) { + panic("%s failed on SPU[%d] rc=%d.\n", + __func__, spu->number, rc); + } return rc; } /** - * spu_switch - SPU context switch (save + restore). - * @prev: pointer to SPU context save area, to be saved. - * @new: pointer to SPU context save area, to be restored. + * spu_harvest - SPU harvest (reset) operation * @spu: pointer to SPU iomem structure. * - * Perform save, then restore. Only harvest if the - * save fails, as cleanup is otherwise not needed. + * Perform SPU harvest (reset) operation. */ -int spu_switch(struct spu_state *prev, struct spu_state *new, struct spu *spu) +void spu_harvest(struct spu *spu) { - int rc; - - acquire_spu_lock(spu); /* Save, Step 1. */ - rc = __do_spu_save(prev, spu); /* Save, Steps 2-53. */ - if (rc != 0) { - harvest(prev, spu); - } - rc = __do_spu_restore(new, spu); + acquire_spu_lock(spu); + harvest(NULL, spu); release_spu_lock(spu); - - return rc; } static void init_prob(struct spu_state *csa) @@ -2181,6 +2181,7 @@ static void init_priv2(struct spu_state *csa) void spu_init_csa(struct spu_state *csa) { struct spu_lscsa *lscsa; + unsigned char *p; if (!csa) return; @@ -2192,6 +2193,11 @@ void spu_init_csa(struct spu_state *csa) memset(lscsa, 0, sizeof(struct spu_lscsa)); csa->lscsa = lscsa; + csa->register_lock = SPIN_LOCK_UNLOCKED; + + /* Set LS pages reserved to allow for user-space mapping. */ + for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE) + SetPageReserved(vmalloc_to_page(p)); init_prob(csa); init_priv1(csa); @@ -2200,5 +2206,10 @@ void spu_init_csa(struct spu_state *csa) void spu_fini_csa(struct spu_state *csa) { + /* Clear reserved bit before vfree. */ + unsigned char *p; + for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE) + ClearPageReserved(vmalloc_to_page(p)); + vfree(csa->lscsa); } diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 3f71bb5e9d8e..17a2b51c94bc 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -36,7 +36,7 @@ long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus) u32 npc, status; ret = -EFAULT; - if (get_user(npc, unpc)) + if (get_user(npc, unpc) || get_user(status, ustatus)) goto out; ret = -EINVAL; @@ -46,13 +46,7 @@ long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus) i = SPUFS_I(filp->f_dentry->d_inode); ret = spufs_run_spu(filp, i->i_ctx, &npc, &status); - if (ret ==-EAGAIN || ret == -EIO) - ret = status; - - if (put_user(npc, unpc)) - ret = -EFAULT; - - if (ustatus && put_user(status, ustatus)) + if (put_user(npc, unpc) || put_user(status, ustatus)) ret = -EFAULT; out: return ret; diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 62718f3ba03f..092ec97be326 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -105,6 +105,9 @@ #define SPU_CONTEXT_SWITCH_PENDING (1UL << SPU_CONTEXT_SWITCH_PENDING_nr) #define SPU_CONTEXT_SWITCH_ACTIVE (1UL << SPU_CONTEXT_SWITCH_ACTIVE_nr) +struct spu_context; +struct spu_runqueue; + struct spu { char *name; unsigned long local_store_phys; @@ -113,23 +116,28 @@ struct spu { struct spu_priv1 __iomem *priv1; struct spu_priv2 __iomem *priv2; struct list_head list; + struct list_head sched_list; int number; u32 isrc; u32 node; u64 flags; + u64 dar; + u64 dsisr; struct kref kref; size_t ls_size; unsigned int slb_replace; struct mm_struct *mm; + struct spu_context *ctx; + struct spu_runqueue *rq; + pid_t pid; + int prio; int class_0_pending; spinlock_t register_lock; u32 stop_code; wait_queue_head_t stop_wq; - wait_queue_head_t ibox_wq; - wait_queue_head_t wbox_wq; - struct fasync_struct *ibox_fasync; - struct fasync_struct *wbox_fasync; + void (* wbox_callback)(struct spu *spu); + void (* ibox_callback)(struct spu *spu); char irq_c0[8]; char irq_c1[8]; @@ -140,9 +148,6 @@ struct spu *spu_alloc(void); void spu_free(struct spu *spu); int spu_run(struct spu *spu); -size_t spu_wbox_write(struct spu *spu, u32 data); -size_t spu_ibox_read(struct spu *spu, u32 *data); - extern struct spufs_calls { asmlinkage long (*create_thread)(const char __user *name, unsigned int flags, mode_t mode); diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h index 989a0688144e..2a8af416638f 100644 --- a/include/asm-powerpc/spu_csa.h +++ b/include/asm-powerpc/spu_csa.h @@ -241,6 +241,7 @@ struct spu_state { unsigned long suspend_time; u64 slb_esid_RW[8]; u64 slb_vsid_RW[8]; + spinlock_t register_lock; }; extern void spu_init_csa(struct spu_state *csa); -- cgit v1.2.3 From d6a55504b31dac7a0fd5d12bb6bd9f3773c88569 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 18 Nov 2005 13:16:43 +1100 Subject: powerpc: Update __NR_syscalls to account for SPU syscalls A previous patch ended up not increasing __NR_syscalls to account for the new SPU syscalls (probably my fault). Signed-off-by: Paul Mackerras --- include/asm-powerpc/unistd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index 9606349855da..19eaac3fbbf9 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -299,7 +299,7 @@ #define __NR_spu_run 278 #define __NR_spu_create 279 -#define __NR_syscalls 278 +#define __NR_syscalls 280 #ifdef __KERNEL__ #define __NR__exit __NR_exit -- cgit v1.2.3 From c1189c9275dbaa474e1f5ce0b62f6b4d9be67d51 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 18 Nov 2005 22:30:06 +1100 Subject: ppc: remove duplicate bseip.h include/asm-ppc/bseip.h is a duplicate of arch/ppc/platforms/bseip.h and is not referenced anywhere, so get rid of it. Pointed out by Marcelo Tosatti. Signed-off-by: Paul Mackerras --- include/asm-ppc/bseip.h | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 include/asm-ppc/bseip.h diff --git a/include/asm-ppc/bseip.h b/include/asm-ppc/bseip.h deleted file mode 100644 index 691f4a52b0a5..000000000000 --- a/include/asm-ppc/bseip.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * A collection of structures, addresses, and values associated with - * the Bright Star Engineering ip-Engine board. Copied from the MBX stuff. - * - * Copyright (c) 1998 Dan Malek (dmalek@jlc.net) - */ -#ifndef __MACH_BSEIP_DEFS -#define __MACH_BSEIP_DEFS - -#ifndef __ASSEMBLY__ -/* A Board Information structure that is given to a program when - * prom starts it up. - */ -typedef struct bd_info { - unsigned int bi_memstart; /* Memory start address */ - unsigned int bi_memsize; /* Memory (end) size in bytes */ - unsigned int bi_intfreq; /* Internal Freq, in Hz */ - unsigned int bi_busfreq; /* Bus Freq, in Hz */ - unsigned char bi_enetaddr[6]; - unsigned int bi_baudrate; -} bd_t; - -extern bd_t m8xx_board_info; - -/* Memory map is configured by the PROM startup. - * All we need to get started is the IMMR. - */ -#define IMAP_ADDR ((uint)0xff000000) -#define IMAP_SIZE ((uint)(64 * 1024)) -#define PCMCIA_MEM_ADDR ((uint)0x04000000) -#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) -#endif /* !__ASSEMBLY__ */ - -/* We don't use the 8259. -*/ -#define NR_8259_INTS 0 - -#endif -- cgit v1.2.3 From bcb05504edf0e27a648aa1059cbb71e8746758a1 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 18 Nov 2005 12:15:33 +0000 Subject: [PATCH] ppc64 syscall_exit_work: call the save_nvgprs function, not its descriptor. On Tue, 2005-11-15 at 18:52 +0000, David Woodhouse wrote: > This cleanup patch speeds up the null syscall path on ppc64 by about 3%, > and brings the ppc32 and ppc64 code slightly closer together. Needs this unless your binutils, like mine, are clever enough to notice my stupidity and fix it up automatically... Spotted by Paul. Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/entry_64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 0bff31f166dd..7b9397169709 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -241,7 +241,7 @@ syscall_exit_work: bne- 3b subi r12,r12,TI_FLAGS -4: bl save_nvgprs +4: bl .save_nvgprs /* Anything else left to do? */ andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) beq .ret_from_except_lite -- cgit v1.2.3 From d1405b869850982f05c7ec0d3f137ca27588192f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 23 Nov 2005 17:53:42 +1100 Subject: [PATCH] powerpc: Add OF address parsing code (#2) Parsing addresses extracted from Open Firmware isn't a simple matter. We have various bits of code that try to do it in various place, including some heuristics in prom.c that pre-parse addresses at boot and fill device-nodes "addrs", but those are dodgy at best and I want to deprecate them. So this patch introduces a new set of routines that should be capable of parsing most types of addresses and translating them into CPU physical addresses. It currently works for things on PCI busses and ISA busses and should work on "standard" busses like the root bus or the MacIO bus that don't put funky flags in addresses. If you have other bus types that do use funky flags, you'll have to add new bus type translators, which is fairly easy. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 3 +- arch/powerpc/kernel/prom_parse.c | 420 +++++++++++++++++++++++++++++++++++++++ include/asm-powerpc/mmu.h | 4 + include/asm-powerpc/prom.h | 9 + include/asm-ppc/prom.h | 10 + 5 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/kernel/prom_parse.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 78f7b90c98f8..aab0ae33a42a 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -12,7 +12,8 @@ CFLAGS_btext.o += -fPIC endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ - irq.o align.o signal_32.o pmc.o vdso.o + irq.o align.o signal_32.o pmc.o vdso.o \ + prom_parse.o obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ signal_64.o ptrace32.o systbl.o \ diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c new file mode 100644 index 000000000000..9c2a5be7a56a --- /dev/null +++ b/arch/powerpc/kernel/prom_parse.c @@ -0,0 +1,420 @@ +#undef DEBUG + +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define DBG(fmt...) do { printk(fmt); } while(0) +#else +#define DBG(fmt...) do { } while(0) +#endif + +#ifdef CONFIG_PPC64 +#define PRu64 "%lx" +#else +#define PRu64 "%llx" +#endif + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ + (ns) > 0) + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr(const char *s, u32 *addr, int na) +{ + printk("%s", s); + while(na--) + printk(" %08x", *(addr++)); + printk("\n"); +} +#else +static void of_dump_addr(const char *s, u32 *addr, int na) { } +#endif + +/* Read a big address */ +static inline u64 of_read_addr(u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +/* Callbacks for bus specific translators */ +struct of_bus { + const char *name; + const char *addresses; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); +}; + + +/* + * Default translator (generic bus) + */ + +static void of_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = prom_n_addr_cells(dev); + if (sizec) + *sizec = prom_n_size_cells(dev); +} + +static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_addr(range, na); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr, na); + + DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n", + cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_default_translate(u32 *addr, u64 offset, int na) +{ + u64 a = of_read_addr(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = a >> 32; + addr[na - 1] = a & 0xffffffffu; + + return 0; +} + + +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + return !strcmp(np->type, "pci"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x03000000) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_pci_translate(u32 *addr, u64 offset, int na) +{ + return of_default_translate(addr + 1, offset, na - 1); +} + +/* + * ISA bus specific translator + */ + +static int of_bus_isa_match(struct device_node *np) +{ + return !strcmp(np->name, "isa"); +} + +static void of_bus_isa_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x00000001) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(u32 *addr, u64 offset, int na) +{ + return of_default_translate(addr + 1, offset, na - 1); +} + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { + /* PCI */ + { + .name = "pci", + .addresses = "assigned-addresses", + .match = of_bus_pci_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_pci_map, + .translate = of_bus_pci_translate, + }, + /* ISA */ + { + .name = "isa", + .addresses = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + }, + /* Default */ + { + .name = "default", + .addresses = "reg", + .match = NULL, + .count_cells = of_default_count_cells, + .map = of_default_map, + .translate = of_default_translate, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i ++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static int of_translate_one(struct device_node *parent, struct of_bus *bus, + struct of_bus *pbus, u32 *addr, + int na, int ns, int pna) +{ + u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + /* Normally, an absence of a "ranges" property means we are + * crossing a non-translatable boundary, and thus the addresses + * below the current not cannot be converted to CPU physical ones. + * Unfortunately, while this is very clear in the spec, it's not + * what Apple understood, and they do have things like /uni-n or + * /ht nodes with no "ranges" property and a lot of perfectly + * useable mapped devices below them. Thus we treat the absence of + * "ranges" as equivalent to an empty "ranges" property which means + * a 1:1 translation at that level. It's up to the caller not to try + * to translate addresses that aren't supposed to be translated in + * the first place. --BenH. + */ + ranges = (u32 *)get_property(parent, "ranges", &rlen); + if (ranges == NULL || rlen == 0) { + offset = of_read_addr(addr, na); + memset(addr, 0, pna); + goto finish; + } + + DBG("OF: walking ranges...\n"); + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) { + DBG("OF: not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + + finish: + of_dump_addr("OF: parent translation for:", addr, pna); + DBG("OF: with offset: %lx\n", offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +u64 of_translate_address(struct device_node *dev, u32 *in_addr) +{ + struct device_node *parent = NULL; + struct of_bus *bus, *pbus; + u32 addr[OF_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = OF_BAD_ADDR; + + DBG("OF: ** translation for device %s **\n", dev->full_name); + + /* Increase refcount at current level */ + of_node_get(dev); + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + goto bail; + bus = of_match_bus(parent); + + /* Cound address cells & copy address locally */ + bus->count_cells(dev, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + dev->full_name); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + DBG("OF: bus is %s (na=%d, ns=%d) on %s\n", + bus->name, na, ns, parent->full_name); + of_dump_addr("OF: translating address:", addr, na); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + of_node_put(dev); + dev = parent; + parent = of_get_parent(dev); + + /* If root, we have finished */ + if (parent == NULL) { + DBG("OF: reached root node\n"); + result = of_read_addr(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = of_match_bus(parent); + pbus->count_cells(dev, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + dev->full_name); + break; + } + + DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n", + pbus->name, pna, pns, parent->full_name); + + /* Apply bus translation */ + if (of_translate_one(dev, bus, pbus, addr, na, ns, pna)) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + of_dump_addr("OF: one level translation:", addr, na); + } + bail: + of_node_put(parent); + of_node_put(dev); + + return result; +} +EXPORT_SYMBOL(of_translate_address); + +u32 *of_get_address(struct device_node *dev, int index, u64 *size) +{ + u32 *prop; + unsigned int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_COUNTS(na, ns)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = (u32 *)get_property(dev, bus->addresses, &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) + if (i == index) { + if (size) + *size = of_read_addr(prop + na, ns); + return prop; + } + return NULL; +} +EXPORT_SYMBOL(of_get_address); + +u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size) +{ + u32 *addr; + int index; + + for (index = 0; (addr = of_get_address(dev, index, size)) != NULL; + index++) { + if ((addr[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) + return addr; + } + return NULL; +} +EXPORT_SYMBOL(of_get_pci_address); diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 29b0bb0086d3..29613500c2c2 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -394,6 +394,10 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea) #define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS) #define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea)) +/* Physical address used by some IO functions */ +typedef unsigned long phys_addr_t; + + #endif /* __ASSEMBLY */ #endif /* CONFIG_PPC64 */ diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index f999df1c5c90..fb732c992bd2 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -223,5 +223,14 @@ extern struct resource *request_OF_resource(struct device_node* node, int index, const char* name_postfix); extern int release_OF_resource(struct device_node* node, int index); +/* + * Address translation function(s) + */ +#define OF_BAD_ADDR ((u64)-1) +extern u64 of_translate_address(struct device_node *np, u32 *addr); +extern u32 *of_get_address(struct device_node *dev, int index, u64 *size); +extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size); + + #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index 3e39827ed566..a10a2d64b300 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -136,5 +136,15 @@ extern unsigned long sub_reloc_offset(unsigned long); #define PTRRELOC(x) ((typeof(x))add_reloc_offset((unsigned long)(x))) #define PTRUNRELOC(x) ((typeof(x))sub_reloc_offset((unsigned long)(x))) + +/* + * Address translation function(s) + */ +#define OF_BAD_ADDR ((u64)-1) +extern u64 of_translate_address(struct device_node *np, u32 *addr); +extern u32 *of_get_address(struct device_node *dev, int index, u64 *size); +extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size); + + #endif /* _PPC_PROM_H */ #endif /* __KERNEL__ */ -- cgit v1.2.3 From 463ce0e103f419f51b1769111e73fe8bb305d0ec Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 23 Nov 2005 17:56:06 +1100 Subject: [PATCH] powerpc: serial port discovery (#2) This moves the discovery of legacy serial ports to a separate file, makes it common to ppc32 and ppc64, and reworks it to use the new OF address translators to get to the ports early. This new version can also detect some PCI serial cards using legacy chips and will probably match those discovered port with the default console choice. Only ppc64 gets udbg still yet, unifying udbg isn't finished yet. It also adds some speed-probing code to udbg so that the default console can come up at the same speed it was set to by the firmware. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 9 +- arch/powerpc/kernel/legacy_serial.c | 478 +++++++++++++++++++++++++++++++++ arch/powerpc/kernel/pci_64.c | 15 ++ arch/powerpc/kernel/setup-common.c | 123 --------- arch/powerpc/kernel/setup_32.c | 8 + arch/powerpc/kernel/setup_64.c | 190 +------------ arch/powerpc/kernel/udbg.c | 2 +- arch/powerpc/kernel/udbg_16550.c | 63 ++++- arch/powerpc/platforms/maple/setup.c | 14 - arch/powerpc/platforms/pseries/lpar.c | 68 +++-- arch/powerpc/platforms/pseries/setup.c | 14 - arch/ppc/kernel/pci.c | 3 +- include/asm-powerpc/pci-bridge.h | 3 + include/asm-powerpc/serial.h | 2 + include/asm-powerpc/udbg.h | 5 +- 15 files changed, 607 insertions(+), 390 deletions(-) create mode 100644 arch/powerpc/kernel/legacy_serial.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index aab0ae33a42a..bf3fd6f02249 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -33,10 +33,6 @@ obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o -obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o -obj-$(CONFIG_PPC_MAPLE) += udbg_16550.o -udbgscc-$(CONFIG_PPC64) := udbg_scc.o -obj-$(CONFIG_PPC_PMAC) += $(udbgscc-y) obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o ifeq ($(CONFIG_PPC_MERGE),y) @@ -59,14 +55,15 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_6xx) += idle_6xx.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o - +obj-$(CONFIG_PPC_MULTIPLATFORM) += legacy_serial.o +obj64-$(CONFIG_PPC_MULTIPLATFORM) += udbg_16550.o +obj64-$(CONFIG_PPC_PMAC) += udbg_scc.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \ pci_direct_iommu.o iomap.o obj-$(CONFIG_PCI) += $(pci64-y) - kexec-$(CONFIG_PPC64) := machine_kexec_64.o kexec-$(CONFIG_PPC32) := machine_kexec_32.o obj-$(CONFIG_KEXEC) += machine_kexec.o $(kexec-y) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c new file mode 100644 index 000000000000..28ad50e424a9 --- /dev/null +++ b/arch/powerpc/kernel/legacy_serial.c @@ -0,0 +1,478 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) do { printk(fmt); } while(0) +#else +#define DBG(fmt...) do { } while(0) +#endif + +#define MAX_LEGACY_SERIAL_PORTS 8 + +static struct plat_serial8250_port +legacy_serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; +static struct legacy_serial_info { + struct device_node *np; + unsigned int speed; + unsigned int clock; + phys_addr_t taddr; +} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS]; +static unsigned int legacy_serial_count; +static int legacy_serial_console = -1; + +static int __init add_legacy_port(struct device_node *np, int want_index, + int iotype, phys_addr_t base, + phys_addr_t taddr, unsigned long irq) +{ + u32 *clk, *spd, clock; + int index; + + /* get clock freq. if present */ + clk = (u32 *)get_property(np, "clock-frequency", NULL); + clock = clk ? *clk : BASE_BAUD * 16; + + /* get default speed if present */ + spd = (u32 *)get_property(np, "current-speed", NULL); + + /* If we have a location index, then try to use it */ + if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS) + index = want_index; + else + index = legacy_serial_count; + + /* if our index is still out of range, that mean that + * array is full, we could scan for a free slot but that + * make little sense to bother, just skip the port + */ + if (index >= MAX_LEGACY_SERIAL_PORTS) + return -1; + if (index >= legacy_serial_count) + legacy_serial_count = index + 1; + + /* Check if there is a port who already claimed our slot */ + if (legacy_serial_infos[index].np != 0) { + /* if we still have some room, move it, else override */ + if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) { + printk(KERN_INFO "Moved legacy port %d -> %d\n", + index, legacy_serial_count); + legacy_serial_ports[legacy_serial_count] = + legacy_serial_ports[index]; + legacy_serial_infos[legacy_serial_count] = + legacy_serial_infos[index]; + legacy_serial_count++; + } else { + printk(KERN_INFO "Replacing legacy port %d\n", index); + } + } + + /* Now fill the entry */ + memset(&legacy_serial_ports[index], 0, + sizeof(struct plat_serial8250_port)); + if (iotype == UPIO_PORT) + legacy_serial_ports[index].iobase = base; + else + legacy_serial_ports[index].membase = (void __iomem *)base; + legacy_serial_ports[index].iotype = iotype; + legacy_serial_ports[index].uartclk = clock; + legacy_serial_ports[index].irq = irq; + legacy_serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; + legacy_serial_infos[index].taddr = taddr; + legacy_serial_infos[index].np = of_node_get(np); + legacy_serial_infos[index].clock = clock; + legacy_serial_infos[index].speed = spd ? *spd : 0; + + printk(KERN_INFO "Found legacy serial port %d for %s\n", + index, np->full_name); + printk(KERN_INFO " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n", + (iotype == UPIO_PORT) ? "port" : "mem", + (unsigned long long)base, (unsigned long long)taddr, irq, + legacy_serial_ports[index].uartclk, + legacy_serial_infos[index].speed); + + return index; +} + +static int __init add_legacy_isa_port(struct device_node *np, + struct device_node *isa_bridge) +{ + u32 *reg; + char *typep; + int index = -1; + phys_addr_t taddr; + + /* Get the ISA port number */ + reg = (u32 *)get_property(np, "reg", NULL); + if (reg == NULL) + return -1; + + /* Verify it's an IO port, we don't support anything else */ + if (!(reg[0] & 0x00000001)) + return -1; + + /* Now look for an "ibm,aix-loc" property that gives us ordering + * if any... + */ + typep = (char *)get_property(np, "ibm,aix-loc", NULL); + + /* If we have a location index, then use it */ + if (typep && *typep == 'S') + index = simple_strtol(typep+1, NULL, 0) - 1; + + /* Translate ISA address */ + taddr = of_translate_address(np, reg); + + /* Add port, irq will be dealt with later */ + return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ); + +} + +static int __init add_legacy_pci_port(struct device_node *np, + struct device_node *pci_dev) +{ + phys_addr_t addr, base; + u32 *addrp; + int iotype, index = -1; + +#if 0 + /* We only support ports that have a clock frequency properly + * encoded in the device-tree (that is have an fcode). Anything + * else can't be used that early and will be normally probed by + * the generic 8250_pci driver later on. + */ + if (get_property(np, "clock-frequency", NULL) == NULL) + return -1; +#endif + + /* Get the PCI address. Assume BAR 0 */ + addrp = of_get_pci_address(pci_dev, 0, NULL); + if (addrp == NULL) + return -1; + + /* We only support BAR 0 for now */ + iotype = (addrp[0] & 0x02000000) ? UPIO_MEM : UPIO_PORT; + addr = of_translate_address(pci_dev, addrp); + + /* Set the IO base to the same as the translated address for MMIO, + * or to the domain local IO base for PIO (it will be fixed up later) + */ + if (iotype == UPIO_MEM) + base = addr; + else + base = addrp[2]; + + /* Try to guess an index... If we have subdevices of the pci dev, + * we get to their "reg" property + */ + if (np != pci_dev) { + u32 *reg = (u32 *)get_property(np, "reg", NULL); + if (reg && (*reg < 4)) + index = legacy_serial_count + *reg; + } + + /* Add port, irq will be dealt with later. We passed a translated + * IO port value. It will be fixed up later along with the irq + */ + return add_legacy_port(np, index, iotype, base, addr, NO_IRQ); +} + +/* + * This is called very early, as part of setup_system() or eventually + * setup_arch(), basically before anything else in this file. This function + * will try to build a list of all the available 8250-compatible serial ports + * in the machine using the Open Firmware device-tree. It currently only deals + * with ISA and PCI busses but could be extended. It allows a very early boot + * console to be initialized, that list is also used later to provide 8250 with + * the machine non-PCI ports and to properly pick the default console port + */ +void __init find_legacy_serial_ports(void) +{ + struct device_node *np, *stdout; + char *path; + int index; + + DBG(" -> find_legacy_serial_port()\n"); + + /* Now find out if one of these is out firmware console */ + path = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (path == NULL) { + DBG(" no linux,stdout-path !\n"); + return; + } + stdout = of_find_node_by_path(path); + if (stdout) { + DBG("stdout is %s\n", stdout->full_name); + } + + /* First fill our array with ISA ports */ + for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { + struct device_node *isa = of_get_parent(np); + if (isa && !strcmp(isa->name, "isa")) { + index = add_legacy_isa_port(np, isa); + if (index >= 0 && np == stdout) + legacy_serial_console = index; + } + of_node_put(isa); + } + + /* Next, try to locate PCI ports */ + for (np = NULL; (np = of_find_all_nodes(np));) { + struct device_node *pci, *parent = of_get_parent(np); + if (parent && !strcmp(parent->name, "isa")) { + of_node_put(parent); + continue; + } + if (strcmp(np->name, "serial") && strcmp(np->type, "serial")) { + of_node_put(parent); + continue; + } + /* Check for known pciclass, and also check wether we have + * a device with child nodes for ports or not + */ + if (device_is_compatible(np, "pciclass,0700") || + device_is_compatible(np, "pciclass,070002")) + pci = np; + else if (device_is_compatible(parent, "pciclass,0700") || + device_is_compatible(parent, "pciclass,070002")) + pci = parent; + else { + of_node_put(parent); + continue; + } + index = add_legacy_pci_port(np, pci); + if (index >= 0 && np == stdout) + legacy_serial_console = index; + of_node_put(parent); + } + + DBG("legacy_serial_console = %d\n", legacy_serial_console); + + /* udbg is 64 bits only for now, that will change soon though ... */ +#ifdef CONFIG_PPC64 + while (legacy_serial_console >= 0) { + struct legacy_serial_info *info = + &legacy_serial_infos[legacy_serial_console]; + void __iomem *addr; + + if (info->taddr == 0) + break; + addr = ioremap(info->taddr, 0x1000); + if (addr == NULL) + break; + if (info->speed == 0) + info->speed = udbg_probe_uart_speed(addr, info->clock); + DBG("default console speed = %d\n", info->speed); + udbg_init_uart(addr, info->speed, info->clock); + break; + } +#endif /* CONFIG_PPC64 */ + + DBG(" <- find_legacy_serial_port()\n"); +} + +static struct platform_device serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = legacy_serial_ports, + }, +}; + +static void __init fixup_port_irq(int index, + struct device_node *np, + struct plat_serial8250_port *port) +{ + DBG("fixup_port_irq(%d)\n", index); + + /* Check for interrupts in that node */ + if (np->n_intrs > 0) { + port->irq = np->intrs[0].line; + DBG(" port %d (%s), irq=%d\n", + index, np->full_name, port->irq); + return; + } + + /* Check for interrupts in the parent */ + np = of_get_parent(np); + if (np == NULL) + return; + + if (np->n_intrs > 0) { + port->irq = np->intrs[0].line; + DBG(" port %d (%s), irq=%d\n", + index, np->full_name, port->irq); + } + of_node_put(np); +} + +static void __init fixup_port_pio(int index, + struct device_node *np, + struct plat_serial8250_port *port) +{ + struct pci_controller *hose; + + DBG("fixup_port_pio(%d)\n", index); + + hose = pci_find_hose_for_OF_device(np); + if (hose) { + unsigned long offset = (unsigned long)hose->io_base_virt - +#ifdef CONFIG_PPC64 + pci_io_base; +#else + isa_io_base; +#endif + DBG("port %d, IO %lx -> %lx\n", + index, port->iobase, port->iobase + offset); + port->iobase += offset; + } +} + +/* + * This is called as an arch initcall, hopefully before the PCI bus is + * probed and/or the 8250 driver loaded since we need to register our + * platform devices before 8250 PCI ones are detected as some of them + * must properly "override" the platform ones. + * + * This function fixes up the interrupt value for platform ports as it + * couldn't be done earlier before interrupt maps have been parsed. It + * also "corrects" the IO address for PIO ports for the same reason, + * since earlier, the PHBs virtual IO space wasn't assigned yet. It then + * registers all those platform ports for use by the 8250 driver when it + * finally loads. + */ +static int __init serial_dev_init(void) +{ + int i; + + if (legacy_serial_count == 0) + return -ENODEV; + + /* + * Before we register the platfrom serial devices, we need + * to fixup their interrutps and their IO ports. + */ + DBG("Fixing serial ports interrupts and IO ports ...\n"); + + for (i = 0; i < legacy_serial_count; i++) { + struct plat_serial8250_port *port = &legacy_serial_ports[i]; + struct device_node *np = legacy_serial_infos[i].np; + + if (port->irq == NO_IRQ) + fixup_port_irq(i, np, port); + if (port->iotype == UPIO_PORT) + fixup_port_pio(i, np, port); + } + + DBG("Registering platform serial ports\n"); + + return platform_device_register(&serial_device); +} +arch_initcall(serial_dev_init); + + +/* + * This is called very early, as part of console_init() (typically just after + * time_init()). This function is respondible for trying to find a good + * default console on serial ports. It tries to match the open firmware + * default output with one of the available serial console drivers, either + * one of the platform serial ports that have been probed earlier by + * find_legacy_serial_ports() or some more platform specific ones. + */ +static int __init check_legacy_serial_console(void) +{ + struct device_node *prom_stdout = NULL; + int speed = 0, offset = 0; + char *name; + u32 *spd; + + DBG(" -> check_legacy_serial_console()\n"); + + /* The user has requested a console so this is already set up. */ + if (strstr(saved_command_line, "console=")) { + DBG(" console was specified !\n"); + return -EBUSY; + } + + if (!of_chosen) { + DBG(" of_chosen is NULL !\n"); + return -ENODEV; + } + /* We are getting a weird phandle from OF ... */ + /* ... So use the full path instead */ + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) { + DBG(" no linux,stdout-path !\n"); + return -ENODEV; + } + prom_stdout = of_find_node_by_path(name); + if (!prom_stdout) { + DBG(" can't find stdout package %s !\n", name); + return -ENODEV; + } + DBG("stdout is %s\n", prom_stdout->full_name); + + name = (char *)get_property(prom_stdout, "name", NULL); + if (!name) { + DBG(" stdout package has no name !\n"); + goto not_found; + } + spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); + if (spd) + speed = *spd; + + if (0) + ; +#ifdef CONFIG_SERIAL_8250_CONSOLE + else if (strcmp(name, "serial") == 0) { + int i; + /* Look for it in probed array */ + for (i = 0; i < legacy_serial_count; i++) { + if (prom_stdout != legacy_serial_infos[i].np) + continue; + offset = i; + speed = legacy_serial_infos[i].speed; + break; + } + if (i >= legacy_serial_count) + goto not_found; + } +#endif /* CONFIG_SERIAL_8250_CONSOLE */ +#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE + else if (strcmp(name, "ch-a") == 0) + offset = 0; + else if (strcmp(name, "ch-b") == 0) + offset = 1; +#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ + else + goto not_found; + of_node_put(prom_stdout); + + DBG("Found serial console at ttyS%d\n", offset); + + if (speed) { + static char __initdata opt[16]; + sprintf(opt, "%d", speed); + return add_preferred_console("ttyS", offset, opt); + } else + return add_preferred_console("ttyS", offset, NULL); + + not_found: + DBG("No preferred console found !\n"); + of_node_put(prom_stdout); + return -ENODEV; +} +console_initcall(check_legacy_serial_console); + diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 8b6008ab217d..9a80cdf9efeb 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -1223,6 +1223,7 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, } EXPORT_SYMBOL(pcibios_fixup_device_resources); + static void __devinit do_bus_setup(struct pci_bus *bus) { struct pci_dev *dev; @@ -1306,6 +1307,20 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, *end = rsrc->end + offset; } +struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) +{ + if (!have_of) + return NULL; + while(node) { + struct pci_controller *hose, *tmp; + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + if (hose->arch_data == node) + return hose; + node = node->parent; + } + return NULL; +} + #endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 6088a39edc26..a6d8aebf2bc6 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -294,129 +294,6 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -#ifdef CONFIG_PPC_MULTIPLATFORM -static int __init set_preferred_console(void) -{ - struct device_node *prom_stdout = NULL; - char *name; - u32 *spd; - int offset = 0; - - DBG(" -> set_preferred_console()\n"); - - /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) { - DBG(" console was specified !\n"); - return -EBUSY; - } - - if (!of_chosen) { - DBG(" of_chosen is NULL !\n"); - return -ENODEV; - } - /* We are getting a weird phandle from OF ... */ - /* ... So use the full path instead */ - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) { - DBG(" no linux,stdout-path !\n"); - return -ENODEV; - } - prom_stdout = of_find_node_by_path(name); - if (!prom_stdout) { - DBG(" can't find stdout package %s !\n", name); - return -ENODEV; - } - DBG("stdout is %s\n", prom_stdout->full_name); - - name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) { - DBG(" stdout package has no name !\n"); - goto not_found; - } - spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); - - if (0) - ; -#ifdef CONFIG_SERIAL_8250_CONSOLE - else if (strcmp(name, "serial") == 0) { - int i; - u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); - if (i > 8) { - switch (reg[1]) { - case 0x3f8: - offset = 0; - break; - case 0x2f8: - offset = 1; - break; - case 0x898: - offset = 2; - break; - case 0x890: - offset = 3; - break; - default: - /* We dont recognise the serial port */ - goto not_found; - } - } - } -#endif /* CONFIG_SERIAL_8250_CONSOLE */ -#ifdef CONFIG_PPC_PSERIES - else if (strcmp(name, "vty") == 0) { - u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); - char *compat = (char *)get_property(prom_stdout, "compatible", NULL); - - if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { - /* Host Virtual Serial Interface */ - switch (reg[0]) { - case 0x30000000: - offset = 0; - break; - case 0x30000001: - offset = 1; - break; - default: - goto not_found; - } - of_node_put(prom_stdout); - DBG("Found hvsi console at offset %d\n", offset); - return add_preferred_console("hvsi", offset, NULL); - } else { - /* pSeries LPAR virtual console */ - of_node_put(prom_stdout); - DBG("Found hvc console\n"); - return add_preferred_console("hvc", 0, NULL); - } - } -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - else - goto not_found; - of_node_put(prom_stdout); - - DBG("Found serial console at ttyS%d\n", offset); - - if (spd) { - static char __initdata opt[16]; - sprintf(opt, "%d", *spd); - return add_preferred_console("ttyS", offset, opt); - } else - return add_preferred_console("ttyS", offset, NULL); - - not_found: - DBG("No preferred console found !\n"); - of_node_put(prom_stdout); - return -ENODEV; -} -console_initcall(set_preferred_console); -#endif /* CONFIG_PPC_MULTIPLATFORM */ - void __init check_for_initrd(void) { #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index e5694335bf10..02baacf04366 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "setup.h" @@ -282,6 +283,13 @@ void __init setup_arch(char **cmdline_p) unflatten_device_tree(); check_for_initrd(); + + if (ppc_md.init_early) + ppc_md.init_early(); + +#ifdef CONFIG_PPC_MULTIPLATFORM + find_legacy_serial_ports(); +#endif finish_device_tree(); smp_setup_cpu_maps(); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e3fb78397dc6..0fc442ad1d26 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -459,6 +459,15 @@ void __init setup_system(void) */ ppc_md.init_early(); + /* + * We can discover serial ports now since the above did setup the + * hash table management for us, thus ioremap works. We do that early + * so that further code can be debugged + */ +#ifdef CONFIG_PPC_MULTIPLATFORM + find_legacy_serial_ports(); +#endif + /* * "Finish" the device-tree, that is do the actual parsing of * some of the properties like the interrupt map @@ -657,187 +666,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -#ifndef CONFIG_PPC_ISERIES -/* - * This function can be used by platforms to "find" legacy serial ports. - * It works for "serial" nodes under an "isa" node, and will try to - * respect the "ibm,aix-loc" property if any. It works with up to 8 - * ports. - */ - -#define MAX_LEGACY_SERIAL_PORTS 8 -static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; -static unsigned int old_serial_count; - -void __init generic_find_legacy_serial_ports(u64 *physport, - unsigned int *default_speed) -{ - struct device_node *np; - u32 *sizeprop; - - struct isa_reg_property { - u32 space; - u32 address; - u32 size; - }; - struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; - }; - - DBG(" -> generic_find_legacy_serial_port()\n"); - - *physport = 0; - if (default_speed) - *default_speed = 0; - - np = of_find_node_by_path("/"); - if (!np) - return; - - /* First fill our array */ - for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { - struct device_node *isa, *pci; - struct isa_reg_property *reg; - unsigned long phys_size, addr_size, io_base; - u32 *rangesp; - u32 *interrupts, *clk, *spd; - char *typep; - int index, rlen, rentsize; - - /* Ok, first check if it's under an "isa" parent */ - isa = of_get_parent(np); - if (!isa || strcmp(isa->name, "isa")) { - DBG("%s: no isa parent found\n", np->full_name); - continue; - } - - /* Now look for an "ibm,aix-loc" property that gives us ordering - * if any... - */ - typep = (char *)get_property(np, "ibm,aix-loc", NULL); - - /* Get the ISA port number */ - reg = (struct isa_reg_property *)get_property(np, "reg", NULL); - if (reg == NULL) - goto next_port; - /* We assume the interrupt number isn't translated ... */ - interrupts = (u32 *)get_property(np, "interrupts", NULL); - /* get clock freq. if present */ - clk = (u32 *)get_property(np, "clock-frequency", NULL); - /* get default speed if present */ - spd = (u32 *)get_property(np, "current-speed", NULL); - /* Default to locate at end of array */ - index = old_serial_count; /* end of the array by default */ - - /* If we have a location index, then use it */ - if (typep && *typep == 'S') { - index = simple_strtol(typep+1, NULL, 0) - 1; - /* if index is out of range, use end of array instead */ - if (index >= MAX_LEGACY_SERIAL_PORTS) - index = old_serial_count; - /* if our index is still out of range, that mean that - * array is full, we could scan for a free slot but that - * make little sense to bother, just skip the port - */ - if (index >= MAX_LEGACY_SERIAL_PORTS) - goto next_port; - if (index >= old_serial_count) - old_serial_count = index + 1; - /* Check if there is a port who already claimed our slot */ - if (serial_ports[index].iobase != 0) { - /* if we still have some room, move it, else override */ - if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { - DBG("Moved legacy port %d -> %d\n", index, - old_serial_count); - serial_ports[old_serial_count++] = - serial_ports[index]; - } else { - DBG("Replacing legacy port %d\n", index); - } - } - } - if (index >= MAX_LEGACY_SERIAL_PORTS) - goto next_port; - if (index >= old_serial_count) - old_serial_count = index + 1; - - /* Now fill the entry */ - memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); - serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; - serial_ports[index].iobase = reg->address; - serial_ports[index].irq = interrupts ? interrupts[0] : 0; - serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; - - DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", - index, - serial_ports[index].iobase, - serial_ports[index].irq, - serial_ports[index].uartclk); - - /* Get phys address of IO reg for port 1 */ - if (index != 0) - goto next_port; - - pci = of_get_parent(isa); - if (!pci) { - DBG("%s: no pci parent found\n", np->full_name); - goto next_port; - } - - rangesp = (u32 *)get_property(pci, "ranges", &rlen); - if (rangesp == NULL) { - of_node_put(pci); - goto next_port; - } - rlen /= 4; - - /* we need the #size-cells of the PCI bridge node itself */ - phys_size = 1; - sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); - if (sizeprop != NULL) - phys_size = *sizeprop; - /* we need the parent #addr-cells */ - addr_size = prom_n_addr_cells(pci); - rentsize = 3 + addr_size + phys_size; - io_base = 0; - for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { - if (((rangesp[0] >> 24) & 0x3) != 1) - continue; /* not IO space */ - io_base = rangesp[3]; - if (addr_size == 2) - io_base = (io_base << 32) | rangesp[4]; - } - if (io_base != 0) { - *physport = io_base + reg->address; - if (default_speed && spd) - *default_speed = *spd; - } - of_node_put(pci); - next_port: - of_node_put(isa); - } - - DBG(" <- generic_find_legacy_serial_port()\n"); -} - -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_ports, - }, -}; - -static int __init serial_dev_init(void) -{ - return platform_device_register(&serial_device); -} -arch_initcall(serial_dev_init); - -#endif /* CONFIG_PPC_ISERIES */ - int check_legacy_ioport(unsigned long base_port) { if (ppc_md.check_legacy_ioport == NULL) diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 0d878e72fc44..2e372477d22a 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -99,7 +99,7 @@ static void udbg_console_write(struct console *con, const char *s, static struct console udbg_console = { .name = "udbg", .write = udbg_console_write, - .flags = CON_PRINTBUFFER, + .flags = CON_PRINTBUFFER | CON_ENABLED, .index = -1, }; diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 9313574ab935..50fd376446c9 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -43,6 +43,8 @@ struct NS16550 { #define LSR_TEMT 0x40 /* Xmitter empty */ #define LSR_ERR 0x80 /* Error */ +#define LCR_DLAB 0x80 + static volatile struct NS16550 __iomem *udbg_comport; static void udbg_550_putc(unsigned char c) @@ -77,29 +79,70 @@ static unsigned char udbg_550_getc(void) return 0; } -void udbg_init_uart(void __iomem *comport, unsigned int speed) +void udbg_init_uart(void __iomem *comport, unsigned int speed, + unsigned int clock) { - u16 dll = speed ? (115200 / speed) : 12; + unsigned int dll, base_bauds = clock / 16; + + if (speed == 0) + speed = 9600; + dll = base_bauds / speed; if (comport) { udbg_comport = (struct NS16550 __iomem *)comport; out_8(&udbg_comport->lcr, 0x00); out_8(&udbg_comport->ier, 0xff); out_8(&udbg_comport->ier, 0x00); - out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ - out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, - 3 = 38400, 12 = 9600 baud */ - out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero - for fast rates; */ - out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ - out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ - out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ + out_8(&udbg_comport->lcr, LCR_DLAB); + out_8(&udbg_comport->dll, dll & 0xff); + out_8(&udbg_comport->dlm, dll >> 8); + /* 8 data, 1 stop, no parity */ + out_8(&udbg_comport->lcr, 0x03); + /* RTS/DTR */ + out_8(&udbg_comport->mcr, 0x03); + /* Clear & enable FIFOs */ + out_8(&udbg_comport->fcr ,0x07); udbg_putc = udbg_550_putc; udbg_getc = udbg_550_getc; udbg_getc_poll = udbg_550_getc_poll; } } +unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock) +{ + unsigned int dll, dlm, divisor, prescaler, speed; + u8 old_lcr; + volatile struct NS16550 __iomem *port = comport; + + old_lcr = in_8(&port->lcr); + + /* select divisor latch registers. */ + out_8(&port->lcr, LCR_DLAB); + + /* now, read the divisor */ + dll = in_8(&port->dll); + dlm = in_8(&port->dlm); + divisor = dlm << 8 | dll; + + /* check prescaling */ + if (in_8(&port->mcr) & 0x80) + prescaler = 4; + else + prescaler = 1; + + /* restore the LCR */ + out_8(&port->lcr, old_lcr); + + /* calculate speed */ + speed = (clock / prescaler) / (divisor * 16); + + /* sanity check */ + if (speed < 9600 || speed > 115200) + speed = 9600; + + return speed; +} + #ifdef CONFIG_PPC_MAPLE void udbg_maple_real_putc(unsigned char c) { diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 95b2352655fe..8724e031e965 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -192,20 +192,6 @@ static void __init maple_init_early(void) */ hpte_init_native(); - /* Find the serial port */ - generic_find_legacy_serial_ports(&physport, &default_speed); - - DBG("phys port addr: %lx\n", (long)physport); - - if (physport) { - void *comport; - /* Map the uart for udbg. */ - comport = (void *)ioremap(physport, 16); - udbg_init_uart(comport, default_speed); - - DBG("Hello World !\n"); - } - /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index cf1bc11b3346..cc0939d4cad1 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -191,7 +192,7 @@ static unsigned char udbg_getcLP(void) /* call this from early_init() for a working debug console on * vterm capable LPAR machines */ -void udbg_init_debug_lpar(void) +void __init udbg_init_debug_lpar(void) { vtermno = 0; udbg_putc = udbg_putcLP; @@ -200,63 +201,54 @@ void udbg_init_debug_lpar(void) } /* returns 0 if couldn't find or use /chosen/stdout as console */ -int find_udbg_vterm(void) +void __init find_udbg_vterm(void) { struct device_node *stdout_node; u32 *termno; char *name; - int found = 0; + int add_console; /* find the boot console from /chosen/stdout */ if (!of_chosen) - return 0; + return; name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); if (name == NULL) - return 0; + return; stdout_node = of_find_node_by_path(name); if (!stdout_node) - return 0; - - /* now we have the stdout node; figure out what type of device it is. */ + return; name = (char *)get_property(stdout_node, "name", NULL); if (!name) { printk(KERN_WARNING "stdout node missing 'name' property!\n"); goto out; } + /* The user has requested a console so this is already set up. */ + add_console = !strstr(cmd_line, "console="); - if (strncmp(name, "vty", 3) == 0) { - if (device_is_compatible(stdout_node, "hvterm1")) { - termno = (u32 *)get_property(stdout_node, "reg", NULL); - if (termno) { - vtermno = termno[0]; - udbg_putc = udbg_putcLP; - udbg_getc = udbg_getcLP; - udbg_getc_poll = udbg_getc_pollLP; - found = 1; - } - } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { - termno = (u32 *)get_property(stdout_node, "reg", NULL); - if (termno) { - vtermno = termno[0]; - udbg_putc = udbg_hvsi_putc; - udbg_getc = udbg_hvsi_getc; - udbg_getc_poll = udbg_hvsi_getc_poll; - found = 1; - } - } - } else if (strncmp(name, "serial", 6)) { - /* XXX fix ISA serial console */ - printk(KERN_WARNING "serial stdout on LPAR ('%s')! " - "can't print udbg messages\n", - stdout_node->full_name); - } else { - printk(KERN_WARNING "don't know how to print to stdout '%s'\n", - stdout_node->full_name); + /* Check if it's a virtual terminal */ + if (strncmp(name, "vty", 3) != 0) + goto out; + termno = (u32 *)get_property(stdout_node, "reg", NULL); + if (termno == NULL) + goto out; + vtermno = termno[0]; + + if (device_is_compatible(stdout_node, "hvterm1")) { + udbg_putc = udbg_putcLP; + udbg_getc = udbg_getcLP; + udbg_getc_poll = udbg_getc_pollLP; + if (add_console) + add_preferred_console("hvc", termno[0] & 0xff, NULL); + } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { + vtermno = termno[0]; + udbg_putc = udbg_hvsi_putc; + udbg_getc = udbg_hvsi_getc; + udbg_getc_poll = udbg_hvsi_getc_poll; + if (add_console) + add_preferred_console("hvsi", termno[0] & 0xff, NULL); } - out: of_node_put(stdout_node); - return found; } void vpa_init(int cpu) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 8a4238a3757f..8828dc378c3e 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -79,8 +79,6 @@ extern void find_udbg_vterm(void); extern void system_reset_fwnmi(void); /* from head.S */ extern void machine_check_fwnmi(void); /* from head.S */ -extern void generic_find_legacy_serial_ports(u64 *physport, - unsigned int *default_speed); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -366,10 +364,7 @@ static int pseries_set_xdabr(unsigned long dabr) */ static void __init pSeries_init_early(void) { - void *comport; int iommu_off = 0; - unsigned int default_speed; - u64 physport; DBG(" -> pSeries_init_early()\n"); @@ -383,17 +378,8 @@ static void __init pSeries_init_early(void) get_property(of_chosen, "linux,iommu-off", NULL)); } - generic_find_legacy_serial_ports(&physport, &default_speed); - if (platform_is_lpar()) find_udbg_vterm(); - else if (physport) { - /* Map the uart for udbg. */ - comport = (void *)ioremap(physport, 16); - udbg_init_uart(comport, default_speed); - - DBG("Hello World !\n"); - } if (firmware_has_feature(FW_FEATURE_DABR)) ppc_md.set_dabr = pseries_set_dabr; diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index f7fae5f153b2..0aa184112fb1 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -815,8 +815,7 @@ EXPORT_SYMBOL(pci_device_to_OF_node); * to set pci_assign_all_buses to 1 and still use RTAS for PCI * config cycles. */ -struct pci_controller* -pci_find_hose_for_OF_device(struct device_node* node) +struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) { if (!have_of) return NULL; diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 223ec7bd81da..89e73fcd58bb 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -140,6 +140,9 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) return PCI_DN(busdn)->phb; } +extern struct pci_controller* +pci_find_hose_for_OF_device(struct device_node* node); + extern struct pci_controller * pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); diff --git a/include/asm-powerpc/serial.h b/include/asm-powerpc/serial.h index b273d630b32f..6dc9546d6908 100644 --- a/include/asm-powerpc/serial.h +++ b/include/asm-powerpc/serial.h @@ -15,4 +15,6 @@ /* Default baud base if not found in device-tree */ #define BASE_BAUD ( 1843200 / 16 ) +extern void find_legacy_serial_ports(void); + #endif /* _PPC64_SERIAL_H */ diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index a383383bc4d4..4049a96dc43d 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -24,7 +24,10 @@ extern int udbg_read(char *buf, int buflen); extern void register_early_udbg_console(void); extern void udbg_printf(const char *fmt, ...); -extern void udbg_init_uart(void __iomem *comport, unsigned int speed); +extern void udbg_init_uart(void __iomem *comport, unsigned int speed, + unsigned int clock); +extern unsigned int udbg_probe_uart_speed(void __iomem *comport, + unsigned int clock); struct device_node; extern void udbg_init_scc(struct device_node *np); -- cgit v1.2.3 From 51d3082fe6e55aecfa17113dbe98077c749f724c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 23 Nov 2005 17:57:25 +1100 Subject: [PATCH] powerpc: Unify udbg (#2) This patch unifies udbg for both ppc32 and ppc64 when building the merged achitecture. xmon now has a single "back end". The powermac udbg stuff gets enriched with some ADB capabilities and btext output. In addition, the early_init callback is now called on ppc32 as well, approx. in the same order as ppc64 regarding device-tree manipulations. The init sequences of ppc32 and ppc64 are getting closer, I'll unify them in a later patch. For now, you can force udbg to the scc using "sccdbg" or to btext using "btextdbg" on powermacs. I'll implement a cleaner way of forcing udbg output to something else than the autodetected OF output device in a later patch. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 2 +- arch/powerpc/kernel/Makefile | 7 +- arch/powerpc/kernel/btext.c | 130 ++++++--- arch/powerpc/kernel/head_32.S | 29 ++ arch/powerpc/kernel/setup_32.c | 28 +- arch/powerpc/kernel/setup_64.c | 4 - arch/powerpc/kernel/udbg.c | 8 +- arch/powerpc/kernel/udbg_16550.c | 4 +- arch/powerpc/kernel/udbg_scc.c | 135 --------- arch/powerpc/mm/init_32.c | 5 + arch/powerpc/platforms/powermac/Makefile | 1 + arch/powerpc/platforms/powermac/feature.c | 68 +++-- arch/powerpc/platforms/powermac/low_i2c.c | 27 +- arch/powerpc/platforms/powermac/pic.c | 2 +- arch/powerpc/platforms/powermac/setup.c | 52 ++-- arch/powerpc/platforms/powermac/udbg_adb.c | 218 ++++++++++++++ arch/powerpc/platforms/powermac/udbg_scc.c | 165 +++++++++++ arch/powerpc/platforms/pseries/lpar.c | 8 +- arch/powerpc/xmon/Makefile | 8 +- arch/powerpc/xmon/start.c | 34 +++ arch/powerpc/xmon/start_32.c | 441 ----------------------------- arch/powerpc/xmon/start_64.c | 34 --- arch/powerpc/xmon/start_8xx.c | 44 --- arch/ppc/kernel/setup.c | 3 + drivers/i2c/busses/i2c-keywest.c | 25 +- drivers/macintosh/via-cuda.c | 48 ++-- drivers/macintosh/via-pmu.c | 87 +++--- include/asm-powerpc/btext.h | 19 +- include/asm-powerpc/udbg.h | 9 +- include/asm-ppc/btext.h | 2 +- include/asm-ppc/machdep.h | 4 +- 31 files changed, 779 insertions(+), 872 deletions(-) delete mode 100644 arch/powerpc/kernel/udbg_scc.c create mode 100644 arch/powerpc/platforms/powermac/udbg_adb.c create mode 100644 arch/powerpc/platforms/powermac/udbg_scc.c create mode 100644 arch/powerpc/xmon/start.c delete mode 100644 arch/powerpc/xmon/start_32.c delete mode 100644 arch/powerpc/xmon/start_64.c delete mode 100644 arch/powerpc/xmon/start_8xx.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 39ca7b9da369..0e4617104f8c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -50,7 +50,7 @@ config PPC config EARLY_PRINTK bool - default y if PPC64 + default y config COMPAT bool diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index bf3fd6f02249..89714929f444 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -18,7 +18,7 @@ obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ signal_64.o ptrace32.o systbl.o \ paca.o ioctl32.o cpu_setup_power4.o \ - firmware.o sysfs.o udbg.o idle_64.o + firmware.o sysfs.o idle_64.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o @@ -46,7 +46,7 @@ extra-$(CONFIG_8xx) := head_8xx.o extra-y += vmlinux.lds obj-y += process.o init_task.o time.o \ - prom.o traps.o setup-common.o + prom.o traps.o setup-common.o udbg.o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o obj-$(CONFIG_PPC_OF) += prom_init.o @@ -56,8 +56,7 @@ obj-$(CONFIG_6xx) += idle_6xx.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_MULTIPLATFORM) += legacy_serial.o -obj64-$(CONFIG_PPC_MULTIPLATFORM) += udbg_16550.o -obj64-$(CONFIG_PPC_PMAC) += udbg_scc.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += udbg_16550.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index bdfba92b2b38..893dd24a9f67 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -31,15 +31,18 @@ static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb); static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); -static int g_loc_X; -static int g_loc_Y; -static int g_max_loc_X; -static int g_max_loc_Y; +#define __force_data __attribute__((__section__(".data"))) -static int dispDeviceRowBytes; -static int dispDeviceDepth; -static int dispDeviceRect[4]; -static unsigned char *dispDeviceBase, *logicalDisplayBase; +static int g_loc_X __force_data; +static int g_loc_Y __force_data; +static int g_max_loc_X __force_data; +static int g_max_loc_Y __force_data; + +static int dispDeviceRowBytes __force_data; +static int dispDeviceDepth __force_data; +static int dispDeviceRect[4] __force_data; +static unsigned char *dispDeviceBase __force_data; +static unsigned char *logicalDisplayBase __force_data; unsigned long disp_BAT[2] __initdata = {0, 0}; @@ -47,7 +50,7 @@ unsigned long disp_BAT[2] __initdata = {0, 0}; static unsigned char vga_font[cmapsz]; -int boot_text_mapped; +int boot_text_mapped __force_data = 0; int force_printk_to_btext = 0; #ifdef CONFIG_PPC32 @@ -66,8 +69,7 @@ int force_printk_to_btext = 0; * is really badly aligned, but I didn't encounter this case * yet. */ -void __init -btext_prepare_BAT(void) +void __init btext_prepare_BAT(void) { unsigned long vaddr = KERNELBASE + 0x10000000; unsigned long addr; @@ -95,12 +97,13 @@ btext_prepare_BAT(void) } #endif -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too + +/* This function can be used to enable the early boot text when doing + * OF booting or within bootx init. It must be followed by a btext_unmap() + * call before the logical address becomes unuseable */ -void __init -btext_setup_display(int width, int height, int depth, int pitch, - unsigned long address) +void __init btext_setup_display(int width, int height, int depth, int pitch, + unsigned long address) { g_loc_X = 0; g_loc_Y = 0; @@ -116,6 +119,11 @@ btext_setup_display(int width, int height, int depth, int pitch, boot_text_mapped = 1; } +void __init btext_unmap(void) +{ + boot_text_mapped = 0; +} + /* Here's a small text engine to use during early boot * or for debugging purposes * @@ -127,7 +135,7 @@ btext_setup_display(int width, int height, int depth, int pitch, * changes. */ -void map_boot_text(void) +static void map_boot_text(void) { unsigned long base, offset, size; unsigned char *vbase; @@ -175,8 +183,9 @@ int btext_initialize(struct device_node *np) if (prop) address = *prop; - /* FIXME: Add support for PCI reg properties */ - + /* FIXME: Add support for PCI reg properties. Right now, only + * reliable on macs + */ if (address == 0) return -EINVAL; @@ -184,7 +193,6 @@ int btext_initialize(struct device_node *np) g_loc_Y = 0; g_max_loc_X = width / 8; g_max_loc_Y = height / 16; - logicalDisplayBase = (unsigned char *)address; dispDeviceBase = (unsigned char *)address; dispDeviceRowBytes = pitch; dispDeviceDepth = depth; @@ -197,7 +205,7 @@ int btext_initialize(struct device_node *np) return 0; } -void __init init_boot_display(void) +int __init btext_find_display(int allow_nonstdout) { char *name; struct device_node *np = NULL; @@ -218,8 +226,8 @@ void __init init_boot_display(void) } if (np) rc = btext_initialize(np); - if (rc == 0) - return; + if (rc == 0 || !allow_nonstdout) + return rc; for (np = NULL; (np = of_find_node_by_type(np, "display"));) { if (get_property(np, "linux,opened", NULL)) { @@ -228,8 +236,9 @@ void __init init_boot_display(void) printk("result: %d\n", rc); } if (rc == 0) - return; + break; } + return rc; } /* Calc the base address of a given point (x,y) */ @@ -277,44 +286,83 @@ EXPORT_SYMBOL(btext_update_display); void btext_clearscreen(void) { - unsigned long *base = (unsigned long *)calc_base(0, 0); + unsigned int *base = (unsigned int *)calc_base(0, 0); unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * - (dispDeviceDepth >> 3)) >> 3; + (dispDeviceDepth >> 3)) >> 2; int i,j; for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) { - unsigned long *ptr = base; + unsigned int *ptr = base; for(j=width; j; --j) *(ptr++) = 0; - base += (dispDeviceRowBytes >> 3); + base += (dispDeviceRowBytes >> 2); + } +} + +void btext_flushscreen(void) +{ + unsigned int *base = (unsigned int *)calc_base(0, 0); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++) + { + unsigned int *ptr = base; + for(j = width; j > 0; j -= 8) { + __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr)); + ptr += 8; + } + base += (dispDeviceRowBytes >> 2); } + __asm__ __volatile__ ("sync" ::: "memory"); } +void btext_flushline(void) +{ + unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4); + unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * + (dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i < 16; i++) + { + unsigned int *ptr = base; + for(j = width; j > 0; j -= 8) { + __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr)); + ptr += 8; + } + base += (dispDeviceRowBytes >> 2); + } + __asm__ __volatile__ ("sync" ::: "memory"); +} + + #ifndef NO_SCROLL static void scrollscreen(void) { - unsigned long *src = (unsigned long *)calc_base(0,16); - unsigned long *dst = (unsigned long *)calc_base(0,0); + unsigned int *src = (unsigned int *)calc_base(0,16); + unsigned int *dst = (unsigned int *)calc_base(0,0); unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * - (dispDeviceDepth >> 3)) >> 3; + (dispDeviceDepth >> 3)) >> 2; int i,j; for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) { - unsigned long *src_ptr = src; - unsigned long *dst_ptr = dst; + unsigned int *src_ptr = src; + unsigned int *dst_ptr = dst; for(j=width; j; --j) *(dst_ptr++) = *(src_ptr++); - src += (dispDeviceRowBytes >> 3); - dst += (dispDeviceRowBytes >> 3); + src += (dispDeviceRowBytes >> 2); + dst += (dispDeviceRowBytes >> 2); } for (i=0; i<16; i++) { - unsigned long *dst_ptr = dst; + unsigned int *dst_ptr = dst; for(j=width; j; --j) *(dst_ptr++) = 0; - dst += (dispDeviceRowBytes >> 3); + dst += (dispDeviceRowBytes >> 2); } } #endif /* ndef NO_SCROLL */ @@ -377,6 +425,14 @@ void btext_drawstring(const char *c) btext_drawchar(*c++); } +void btext_drawtext(const char *c, unsigned int len) +{ + if (!boot_text_mapped) + return; + while (len--) + btext_drawchar(*c++); +} + void btext_drawhex(unsigned long v) { char *hex_table = "0123456789abcdef"; diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index ccdf94731e30..fdd34dbd8797 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -153,6 +153,9 @@ __after_mmu_off: bl flush_tlbs bl initial_bats +#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) + bl setup_disp_bat +#endif /* * Call setup_cpu for CPU 0 and initialize 6xx Idle @@ -1306,6 +1309,32 @@ initial_bats: blr +#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) +setup_disp_bat: + /* + * setup the display bat prepared for us in prom.c + */ + mflr r8 + bl reloc_offset + mtlr r8 + addis r8,r3,disp_BAT@ha + addi r8,r8,disp_BAT@l + cmpwi cr0,r8,0 + beqlr + lwz r11,0(r8) + lwz r8,4(r8) + mfspr r9,SPRN_PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpwi 0,r9,1 + beq 1f + mtspr SPRN_DBAT3L,r8 + mtspr SPRN_DBAT3U,r11 + blr +1: mtspr SPRN_IBAT3L,r8 + mtspr SPRN_IBAT3U,r11 + blr +#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ + #ifdef CONFIG_8260 /* Jump into the system reset for the rom. * We first disable the MMU, and then jump to the ROM reset address. diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 02baacf04366..79d434fc14d2 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "setup.h" @@ -173,12 +174,23 @@ void __init platform_init(void) */ void __init machine_init(unsigned long dt_ptr, unsigned long phys) { + /* If btext is enabled, we might have a BAT setup for early display, + * thus we do enable some very basic udbg output + */ +#ifdef CONFIG_BOOTX_TEXT + udbg_putc = btext_drawchar; +#endif + + /* Do some early initialization based on the flat device tree */ early_init_devtree(__va(dt_ptr)); + /* Check default command line */ #ifdef CONFIG_CMDLINE - strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); + if (cmd_line[0] == 0) + strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); #endif /* CONFIG_CMDLINE */ + /* Base init based on machine type */ platform_init(); #ifdef CONFIG_6xx @@ -294,21 +306,11 @@ void __init setup_arch(char **cmdline_p) smp_setup_cpu_maps(); -#ifdef CONFIG_BOOTX_TEXT - init_boot_display(); -#endif - -#ifdef CONFIG_PPC_PMAC - /* This could be called "early setup arch", it must be done - * now because xmon need it - */ - if (_machine == _MACH_Pmac) - pmac_feature_init(); /* New cool way */ -#endif - #ifdef CONFIG_XMON_DEFAULT xmon_init(1); #endif + /* Register early console */ + register_early_udbg_console(); #if defined(CONFIG_KGDB) if (ppc_md.kgdb_map_scc) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 0fc442ad1d26..65603e9af984 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -474,10 +474,6 @@ void __init setup_system(void) */ finish_device_tree(); -#ifdef CONFIG_BOOTX_TEXT - init_boot_display(); -#endif - /* * Initialize xmon */ diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 2e372477d22a..cc2df5e61bb0 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -16,8 +16,8 @@ #include #include -void (*udbg_putc)(unsigned char c); -unsigned char (*udbg_getc)(void); +void (*udbg_putc)(char c); +char (*udbg_getc)(void); int (*udbg_getc_poll)(void); /* udbg library, used by xmon et al */ @@ -78,7 +78,7 @@ int udbg_read(char *buf, int buflen) #define UDBG_BUFSIZE 256 void udbg_printf(const char *fmt, ...) { - unsigned char buf[UDBG_BUFSIZE]; + char buf[UDBG_BUFSIZE]; va_list args; va_start(args, fmt); @@ -116,6 +116,8 @@ void __init disable_early_printk(void) /* called by setup_system */ void register_early_udbg_console(void) { + if (early_console_initialized) + return; early_console_initialized = 1; register_console(&udbg_console); } diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 50fd376446c9..28a58da5592c 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -47,7 +47,7 @@ struct NS16550 { static volatile struct NS16550 __iomem *udbg_comport; -static void udbg_550_putc(unsigned char c) +static void udbg_550_putc(char c) { if (udbg_comport) { while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) @@ -69,7 +69,7 @@ static int udbg_550_getc_poll(void) return -1; } -static unsigned char udbg_550_getc(void) +static char udbg_550_getc(void) { if (udbg_comport) { while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) diff --git a/arch/powerpc/kernel/udbg_scc.c b/arch/powerpc/kernel/udbg_scc.c deleted file mode 100644 index 820c53551507..000000000000 --- a/arch/powerpc/kernel/udbg_scc.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * udbg for for zilog scc ports as found on Apple PowerMacs - * - * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include - -extern u8 real_readb(volatile u8 __iomem *addr); -extern void real_writeb(u8 data, volatile u8 __iomem *addr); - -#define SCC_TXRDY 4 -#define SCC_RXRDY 1 - -static volatile u8 __iomem *sccc; -static volatile u8 __iomem *sccd; - -static void udbg_scc_putc(unsigned char c) -{ - if (sccc) { - while ((in_8(sccc) & SCC_TXRDY) == 0) - ; - out_8(sccd, c); - if (c == '\n') - udbg_scc_putc('\r'); - } -} - -static int udbg_scc_getc_poll(void) -{ - if (sccc) { - if ((in_8(sccc) & SCC_RXRDY) != 0) - return in_8(sccd); - else - return -1; - } - return -1; -} - -static unsigned char udbg_scc_getc(void) -{ - if (sccc) { - while ((in_8(sccc) & SCC_RXRDY) == 0) - ; - return in_8(sccd); - } - return 0; -} - -static unsigned char scc_inittab[] = { - 13, 0, /* set baud rate divisor */ - 12, 0, - 14, 1, /* baud rate gen enable, src=rtxc */ - 11, 0x50, /* clocks = br gen */ - 5, 0xea, /* tx 8 bits, assert DTR & RTS */ - 4, 0x46, /* x16 clock, 1 stop */ - 3, 0xc1, /* rx enable, 8 bits */ -}; - -void udbg_init_scc(struct device_node *np) -{ - u32 *reg; - unsigned long addr; - int i, x; - - if (np == NULL) - np = of_find_node_by_name(NULL, "escc"); - if (np == NULL || np->parent == NULL) - return; - - udbg_printf("found SCC...\n"); - /* Get address within mac-io ASIC */ - reg = (u32 *)get_property(np, "reg", NULL); - if (reg == NULL) - return; - addr = reg[0]; - udbg_printf("local addr: %lx\n", addr); - /* Get address of mac-io PCI itself */ - reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); - if (reg == NULL) - return; - addr += reg[2]; - udbg_printf("final addr: %lx\n", addr); - - /* Setup for 57600 8N1 */ - addr += 0x20; - sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; - sccc += addr & ~PAGE_MASK; - sccd = sccc + 0x10; - - udbg_printf("ioremap result sccc: %p\n", sccc); - mb(); - - for (i = 20000; i != 0; --i) - x = in_8(sccc); - out_8(sccc, 0x09); /* reset A or B side */ - out_8(sccc, 0xc0); - for (i = 0; i < sizeof(scc_inittab); ++i) - out_8(sccc, scc_inittab[i]); - - udbg_putc = udbg_scc_putc; - udbg_getc = udbg_scc_getc; - udbg_getc_poll = udbg_scc_getc_poll; - - udbg_puts("Hello World !\n"); -} - -static void udbg_real_scc_putc(unsigned char c) -{ - while ((real_readb(sccc) & SCC_TXRDY) == 0) - ; - real_writeb(c, sccd); - if (c == '\n') - udbg_real_scc_putc('\r'); -} - -void udbg_init_pmac_realmode(void) -{ - sccc = (volatile u8 __iomem *)0x80013020ul; - sccd = (volatile u8 __iomem *)0x80013030ul; - - udbg_putc = udbg_real_scc_putc; - udbg_getc = NULL; - udbg_getc_poll = NULL; -} diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 7d4b8b5f0606..7d0d75c11848 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -188,6 +188,11 @@ void __init MMU_init(void) if (ppc_md.progress) ppc_md.progress("MMU:exit", 0x211); + + /* From now on, btext is no longer BAT mapped if it was at all */ +#ifdef CONFIG_BOOTX_TEXT + btext_unmap(); +#endif } /* This is only called until mem_init is done. */ diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index c9df44fcf571..3e5370eeb1b7 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_NVRAM) += nvram.o # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff obj-$(CONFIG_PPC64) += nvram.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_PPC_MERGE) += udbg_scc.o udbg_adb.o diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index f6e22da2a5da..52a9d0c1b8b8 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2607,6 +2607,8 @@ found: */ static void __init probe_uninorth(void) { + u32 *addrp; + phys_addr_t address; unsigned long actrl; /* Locate core99 Uni-N */ @@ -2616,20 +2618,23 @@ static void __init probe_uninorth(void) uninorth_node = of_find_node_by_name(NULL, "u3"); uninorth_u3 = 1; } - if (uninorth_node && uninorth_node->n_addrs > 0) { - unsigned long address = uninorth_node->addrs[0].address; - uninorth_base = ioremap(address, 0x40000); - uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); - if (uninorth_u3) - u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); - } else - uninorth_node = NULL; - - if (!uninorth_node) + if (uninorth_node == NULL) return; - printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n", - uninorth_u3 ? "U3" : "UniNorth", uninorth_rev); + addrp = (u32 *)get_property(uninorth_node, "reg", NULL); + if (addrp == NULL) + return; + address = of_translate_address(uninorth_node, addrp); + if (address == 0) + return; + uninorth_base = ioremap(address, 0x40000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + if (uninorth_u3) + u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); + + printk(KERN_INFO "Found %s memory controller & host bridge," + " revision: %d\n", uninorth_u3 ? "U3" : "UniNorth", + uninorth_rev); printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); /* Set the arbitrer QAck delay according to what Apple does @@ -2653,18 +2658,17 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ { struct device_node* node; int i; - volatile u32 __iomem * base; - u32* revp; + volatile u32 __iomem *base; + u32 *addrp, *revp; + phys_addr_t addr; + u64 size; - node = find_devices(name); - if (!node || !node->n_addrs) - return; - if (compat) - do { - if (device_is_compatible(node, compat)) - break; - node = node->next; - } while (node); + for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) { + if (!compat) + break; + if (device_is_compatible(node, compat)) + break; + } if (!node) return; for(i=0; i= MAX_MACIO_CHIPS) { printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); return; } - base = ioremap(node->addrs[0].address, node->addrs[0].size); + addrp = of_get_pci_address(node, 0, &size); + if (addrp == NULL) { + printk(KERN_ERR "pmac_feature: %s: can't find base !\n", + node->full_name); + return; + } + addr = of_translate_address(node, addrp); + if (addr == 0) { + printk(KERN_ERR "pmac_feature: %s, can't translate base !\n", + node->full_name); + return; + } + base = ioremap(addr, (unsigned long)size); if (!base) { - printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); + printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n", + node->full_name); return; } if (type == macio_keylargo) { diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index f3f39e8e337a..606e0ed13731 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -36,7 +36,7 @@ #ifdef DEBUG #define DBG(x...) do {\ - printk(KERN_DEBUG "KW:" x); \ + printk(KERN_DEBUG "low_i2c:" x); \ } while(0) #else #define DBG(x...) @@ -342,7 +342,7 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, static void keywest_low_i2c_add(struct device_node *np) { struct low_i2c_host *host = find_low_i2c_host(NULL); - u32 *psteps, *prate, steps, aoffset = 0; + u32 *psteps, *prate, *addrp, steps; struct device_node *parent; if (host == NULL) { @@ -352,6 +352,16 @@ static void keywest_low_i2c_add(struct device_node *np) } memset(host, 0, sizeof(*host)); + /* Apple is kind enough to provide a valid AAPL,address property + * on all i2c keywest nodes so far ... we would have to fallback + * to macio parsing if that wasn't the case + */ + addrp = (u32 *)get_property(np, "AAPL,address", NULL); + if (addrp == NULL) { + printk(KERN_ERR "low_i2c: Can't find address for %s\n", + np->full_name); + return; + } init_MUTEX(&host->mutex); host->np = of_node_get(np); psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); @@ -360,12 +370,10 @@ static void keywest_low_i2c_add(struct device_node *np) steps >>= 1; parent = of_get_parent(np); host->num_channels = 1; - if (parent && parent->name[0] == 'u') { + if (parent && parent->name[0] == 'u') host->num_channels = 2; - aoffset = 3; - } /* Select interface rate */ - host->speed = KW_I2C_MODE_100KHZ; + host->speed = KW_I2C_MODE_25KHZ; prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); if (prate) switch(*prate) { case 100: @@ -379,9 +387,12 @@ static void keywest_low_i2c_add(struct device_node *np) break; } + printk(KERN_INFO "low_i2c: Bus %s found at 0x%08x, %d channels," + " speed = %d KHz\n", + np->full_name, *addrp, host->num_channels, prate ? *prate : 25); + host->mode = pmac_low_i2c_mode_std; - host->base = ioremap(np->addrs[0].address + aoffset, - np->addrs[0].size); + host->base = ioremap((*addrp), 0x1000); host->func = keywest_low_i2c_func; } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 90040c49494d..ff78eeac10f2 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -459,7 +459,7 @@ void __init pmac_pic_init(void) mpic_setup_cascade(irqctrler2->intrs[0].line, pmac_u3_cascade, mpic2); } -#if defined(CONFIG_XMON) && defined(CONFIG_PPC32) +#ifdef CONFIG_XMON { struct device_node* pswitch; int nmi_irq; diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 3b7a492d9b68..6ee620fe5195 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -77,6 +77,7 @@ #include #include #include +#include #include "pmac.h" @@ -322,16 +323,6 @@ void __init pmac_setup_arch(void) l2cr_init(); #endif /* CONFIG_PPC32 */ -#ifdef CONFIG_PPC64 - /* Probe motherboard chipset */ - /* this is done earlier in setup_arch for 32-bit */ - pmac_feature_init(); - - /* We can NAP */ - powersave_nap = 1; - printk(KERN_INFO "Using native/NAP idle loop\n"); -#endif - #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif @@ -622,13 +613,26 @@ static void __init pmac_init_early(void) * and call ioremap */ hpte_init_native(); +#endif - /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { - sccdbg = 1; - udbg_init_scc(NULL); + /* Enable early btext debug if requested */ + if (strstr(cmd_line, "btextdbg")) { + udbg_adb_init_early(); + register_early_udbg_console(); } + /* Probe motherboard chipset */ + pmac_feature_init(); + + /* We can NAP */ + powersave_nap = 1; + printk(KERN_INFO "Using native/NAP idle loop\n"); + + /* Initialize debug stuff */ + udbg_scc_init(!!strstr(cmd_line, "sccdbg")); + udbg_adb_init(!!strstr(cmd_line, "btextdbg")); + +#ifdef CONFIG_PPC64 /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; @@ -638,19 +642,8 @@ static void __init pmac_init_early(void) static void __init pmac_progress(char *s, unsigned short hex) { -#ifdef CONFIG_PPC64 - if (sccdbg) { - udbg_puts(s); - udbg_puts("\n"); - return; - } -#endif -#ifdef CONFIG_BOOTX_TEXT - if (boot_text_mapped) { - btext_drawstring(s); - btext_drawchar('\n'); - } -#endif /* CONFIG_BOOTX_TEXT */ + udbg_puts(s); + udbg_puts("\n"); } /* @@ -735,7 +728,8 @@ static int __init pmac_probe(int platform) } #ifdef CONFIG_PPC64 -static int pmac_probe_mode(struct pci_bus *bus) +/* Move that to pci.c */ +static int pmac_pci_probe_mode(struct pci_bus *bus) { struct device_node *node = bus->sysdata; @@ -771,7 +765,7 @@ struct machdep_calls __initdata pmac_md = { .check_legacy_ioport = pmac_check_legacy_ioport, .progress = pmac_progress, #ifdef CONFIG_PPC64 - .pci_probe_mode = pmac_probe_mode, + .pci_probe_mode = pmac_pci_probe_mode, .idle_loop = native_idle, .enable_pmcs = power4_enable_pmcs, #ifdef CONFIG_KEXEC diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c new file mode 100644 index 000000000000..e51de55b2d6e --- /dev/null +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This implementation is "special", it can "patch" the current + * udbg implementation and work on top of it. It must thus be + * initialized last + */ + +static void (*udbg_adb_old_putc)(char c); +static char (*udbg_adb_old_getc)(void); +static int (*udbg_adb_old_getc_poll)(void); + +static enum { + input_adb_none, + input_adb_pmu, + input_adb_cuda, +} input_type = input_adb_none; + +static int udbg_adb_use_btext; + +int xmon_wants_key, xmon_adb_keycode; + +static inline void udbg_adb_poll(void) +{ +#ifdef CONFIG_ADB_PMU + if (input_type == input_adb_pmu) + pmu_poll_adb(); +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB_CUDA + if (input_type == input_adb_cuda) + cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ +} + +#ifdef CONFIG_BOOTX_TEXT +static int xmon_adb_shiftstate; + +static unsigned char xmon_keytab[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80]o" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static unsigned char xmon_shift_keytab[128] = + "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ + "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */ + "U{IP\rLJ\"K:|" /* 0x20 - 0x2f */ + "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static char udbg_adb_local_getc(void) +{ + int k, t, on; + + xmon_wants_key = 1; + for (;;) { + xmon_adb_keycode = -1; + t = 0; + on = 0; + k = -1; + do { + if (--t < 0) { + on = 1 - on; + btext_drawchar(on? 0xdb: 0x20); + btext_drawchar('\b'); + t = 200000; + } + udbg_adb_poll(); + if (udbg_adb_old_getc_poll) + k = udbg_adb_old_getc_poll(); + } while (k == -1 && xmon_adb_keycode == -1); + if (on) + btext_drawstring(" \b"); + if (k != -1) + return k; + k = xmon_adb_keycode; + + /* test for shift keys */ + if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { + xmon_adb_shiftstate = (k & 0x80) == 0; + continue; + } + if (k >= 0x80) + continue; /* ignore up transitions */ + k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; + if (k != 0) + break; + } + xmon_wants_key = 0; + return k; +} +#endif /* CONFIG_BOOTX_TEXT */ + +static char udbg_adb_getc(void) +{ +#ifdef CONFIG_BOOTX_TEXT + if (udbg_adb_use_btext && input_type != input_adb_none) + return udbg_adb_local_getc(); +#endif + if (udbg_adb_old_getc) + return udbg_adb_old_getc(); + return -1; +} + +/* getc_poll() is not really used, unless you have the xmon-over modem + * hack that doesn't quite concern us here, thus we just poll the low level + * ADB driver to prevent it from timing out and call back the original poll + * routine. + */ +static int udbg_adb_getc_poll(void) +{ + udbg_adb_poll(); + + if (udbg_adb_old_getc_poll) + return udbg_adb_old_getc_poll(); + return -1; +} + +static void udbg_adb_putc(char c) +{ +#ifdef CONFIG_BOOTX_TEXT + if (udbg_adb_use_btext) + btext_drawchar(c); +#endif + if (udbg_adb_old_putc) + return udbg_adb_old_putc(c); +} + +void udbg_adb_init_early(void) +{ +#ifdef CONFIG_BOOTX_TEXT + if (btext_find_display(1) == 0) { + udbg_adb_use_btext = 1; + udbg_putc = udbg_adb_putc; + } +#endif +} + +int udbg_adb_init(int force_btext) +{ + struct device_node *np; + + /* Capture existing callbacks */ + udbg_adb_old_putc = udbg_putc; + udbg_adb_old_getc = udbg_getc; + udbg_adb_old_getc_poll = udbg_getc_poll; + + /* Check if our early init was already called */ + if (udbg_adb_old_putc == udbg_adb_putc || + udbg_adb_old_putc == btext_drawchar) + udbg_adb_old_putc = NULL; + + /* Set ours as output */ + udbg_putc = udbg_adb_putc; + udbg_getc = udbg_adb_getc; + udbg_getc_poll = udbg_adb_getc_poll; + +#ifdef CONFIG_BOOTX_TEXT + /* Check if we should use btext output */ + if (btext_find_display(force_btext) == 0) + udbg_adb_use_btext = 1; +#endif + + /* See if there is a keyboard in the device tree with a parent + * of type "adb". If not, we return a failure, but we keep the + * bext output set for now + */ + for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) { + struct device_node *parent = of_get_parent(np); + int found = (parent && !strcmp(parent->type, "adb") == 0); + of_node_put(parent); + if (found) + break; + } + if (np == NULL) + return -ENODEV; + of_node_put(np); + +#ifdef CONFIG_ADB_PMU + if (find_via_pmu()) + input_type = input_adb_pmu; +#endif +#ifdef CONFIG_ADB_CUDA + if (find_via_cuda()) + input_type = input_adb_cuda; +#endif + + /* Same as above: nothing found, keep btext set for output */ + if (input_type == input_adb_none) + return -ENODEV; + + return 0; +} diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c new file mode 100644 index 000000000000..df6dec49c4c7 --- /dev/null +++ b/arch/powerpc/platforms/powermac/udbg_scc.c @@ -0,0 +1,165 @@ +/* + * udbg for for zilog scc ports as found on Apple PowerMacs + * + * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include + +extern u8 real_readb(volatile u8 __iomem *addr); +extern void real_writeb(u8 data, volatile u8 __iomem *addr); + +#define SCC_TXRDY 4 +#define SCC_RXRDY 1 + +static volatile u8 __iomem *sccc; +static volatile u8 __iomem *sccd; + +static void udbg_scc_putc(char c) +{ + if (sccc) { + while ((in_8(sccc) & SCC_TXRDY) == 0) + ; + out_8(sccd, c); + if (c == '\n') + udbg_scc_putc('\r'); + } +} + +static int udbg_scc_getc_poll(void) +{ + if (sccc) { + if ((in_8(sccc) & SCC_RXRDY) != 0) + return in_8(sccd); + else + return -1; + } + return -1; +} + +static char udbg_scc_getc(void) +{ + if (sccc) { + while ((in_8(sccc) & SCC_RXRDY) == 0) + ; + return in_8(sccd); + } + return 0; +} + +static unsigned char scc_inittab[] = { + 13, 0, /* set baud rate divisor */ + 12, 0, + 14, 1, /* baud rate gen enable, src=rtxc */ + 11, 0x50, /* clocks = br gen */ + 5, 0xea, /* tx 8 bits, assert DTR & RTS */ + 4, 0x46, /* x16 clock, 1 stop */ + 3, 0xc1, /* rx enable, 8 bits */ +}; + +void udbg_scc_init(int force_scc) +{ + u32 *reg; + unsigned long addr; + struct device_node *stdout = NULL, *escc = NULL, *macio = NULL; + struct device_node *ch, *ch_def = NULL, *ch_a = NULL; + char *path; + int i, x; + + escc = of_find_node_by_name(NULL, "escc"); + if (escc == NULL) + goto bail; + macio = of_get_parent(escc); + if (macio == NULL) + goto bail; + path = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (path != NULL) + stdout = of_find_node_by_path(path); + for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) { + if (ch == stdout) + ch_def = of_node_get(ch); + if (strcmp(ch->name, "ch-a") == 0) + ch_a = of_node_get(ch); + } + if (ch_def == NULL && !force_scc) + goto bail; + + ch = ch_def ? ch_def : ch_a; + + /* Get address within mac-io ASIC */ + reg = (u32 *)get_property(escc, "reg", NULL); + if (reg == NULL) + goto bail; + addr = reg[0]; + + /* Get address of mac-io PCI itself */ + reg = (u32 *)get_property(macio, "assigned-addresses", NULL); + if (reg == NULL) + goto bail; + addr += reg[2]; + + /* Lock the serial port */ + pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch, + PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); + + + /* Setup for 57600 8N1 */ + if (ch == ch_a) + addr += 0x20; + sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; + sccc += addr & ~PAGE_MASK; + sccd = sccc + 0x10; + + mb(); + + for (i = 20000; i != 0; --i) + x = in_8(sccc); + out_8(sccc, 0x09); /* reset A or B side */ + out_8(sccc, 0xc0); + for (i = 0; i < sizeof(scc_inittab); ++i) + out_8(sccc, scc_inittab[i]); + + udbg_putc = udbg_scc_putc; + udbg_getc = udbg_scc_getc; + udbg_getc_poll = udbg_scc_getc_poll; + + udbg_puts("Hello World !\n"); + + bail: + of_node_put(macio); + of_node_put(escc); + of_node_put(stdout); + of_node_put(ch_def); + of_node_put(ch_a); +} + +#ifdef CONFIG_PPC64 +static void udbg_real_scc_putc(char c) +{ + while ((real_readb(sccc) & SCC_TXRDY) == 0) + ; + real_writeb(c, sccd); + if (c == '\n') + udbg_real_scc_putc('\r'); +} + +void udbg_init_pmac_realmode(void) +{ + sccc = (volatile u8 __iomem *)0x80013020ul; + sccd = (volatile u8 __iomem *)0x80013030ul; + + udbg_putc = udbg_real_scc_putc; + udbg_getc = NULL; + udbg_getc_poll = NULL; +} +#endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index cc0939d4cad1..615ffb961059 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -61,7 +61,7 @@ extern void pSeries_find_serial_port(void); int vtermno; /* virtual terminal# for udbg */ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) -static void udbg_hvsi_putc(unsigned char c) +static void udbg_hvsi_putc(char c) { /* packet's seqno isn't used anyways */ uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c }; @@ -112,7 +112,7 @@ static int udbg_hvsi_getc_poll(void) return ch; } -static unsigned char udbg_hvsi_getc(void) +static char udbg_hvsi_getc(void) { int ch; for (;;) { @@ -128,7 +128,7 @@ static unsigned char udbg_hvsi_getc(void) } } -static void udbg_putcLP(unsigned char c) +static void udbg_putcLP(char c) { char buf[16]; unsigned long rc; @@ -173,7 +173,7 @@ static int udbg_getc_pollLP(void) return ch; } -static unsigned char udbg_getcLP(void) +static char udbg_getcLP(void) { int ch; for (;;) { diff --git a/arch/powerpc/xmon/Makefile b/arch/powerpc/xmon/Makefile index b20312e5ed27..109d874ecfbe 100644 --- a/arch/powerpc/xmon/Makefile +++ b/arch/powerpc/xmon/Makefile @@ -3,9 +3,5 @@ ifdef CONFIG_PPC64 EXTRA_CFLAGS += -mno-minimal-toc endif - -obj-$(CONFIG_8xx) += start_8xx.o -obj-$(CONFIG_6xx) += start_32.o -obj-$(CONFIG_4xx) += start_32.o -obj-$(CONFIG_PPC64) += start_64.o -obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o +obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o start.o \ + nonstdio.o diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c new file mode 100644 index 000000000000..712552c4f242 --- /dev/null +++ b/arch/powerpc/xmon/start.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 1996 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include "nonstdio.h" + +void xmon_map_scc(void) +{ +} + +int xmon_write(void *ptr, int nb) +{ + return udbg_write(ptr, nb); +} + +int xmon_readchar(void) +{ + if (udbg_getc) + return udbg_getc(); + return -1; +} + +int xmon_read_poll(void) +{ + if (udbg_getc_poll) + return udbg_getc_poll(); + return -1; +} diff --git a/arch/powerpc/xmon/start_32.c b/arch/powerpc/xmon/start_32.c deleted file mode 100644 index c2464df4217e..000000000000 --- a/arch/powerpc/xmon/start_32.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nonstdio.h" - -static volatile unsigned char __iomem *sccc, *sccd; -unsigned int TXRDY, RXRDY, DLAB; - -static int use_serial; -static int use_screen; -static int via_modem; -static int xmon_use_sccb; -static struct device_node *channel_node; - -void buf_access(void) -{ - if (DLAB) - sccd[3] &= ~DLAB; /* reset DLAB */ -} - -extern int adb_init(void); - -#ifdef CONFIG_PPC_CHRP -/* - * This looks in the "ranges" property for the primary PCI host bridge - * to find the physical address of the start of PCI/ISA I/O space. - * It is basically a cut-down version of pci_process_bridge_OF_ranges. - */ -static unsigned long chrp_find_phys_io_base(void) -{ - struct device_node *node; - unsigned int *ranges; - unsigned long base = CHRP_ISA_IO_BASE; - int rlen = 0; - int np; - - node = find_devices("isa"); - if (node != NULL) { - node = node->parent; - if (node == NULL || node->type == NULL - || strcmp(node->type, "pci") != 0) - node = NULL; - } - if (node == NULL) - node = find_devices("pci"); - if (node == NULL) - return base; - - ranges = (unsigned int *) get_property(node, "ranges", &rlen); - np = prom_n_addr_cells(node) + 5; - while ((rlen -= np * sizeof(unsigned int)) >= 0) { - if ((ranges[0] >> 24) == 1 && ranges[2] == 0) { - /* I/O space starting at 0, grab the phys base */ - base = ranges[np - 3]; - break; - } - ranges += np; - } - return base; -} -#endif /* CONFIG_PPC_CHRP */ - -void xmon_map_scc(void) -{ -#ifdef CONFIG_PPC_MULTIPLATFORM - volatile unsigned char __iomem *base; - - if (_machine == _MACH_Pmac) { - struct device_node *np; - unsigned long addr; -#ifdef CONFIG_BOOTX_TEXT - if (!use_screen && !use_serial - && !machine_is_compatible("iMac")) { - /* see if there is a keyboard in the device tree - with a parent of type "adb" */ - for (np = find_devices("keyboard"); np; np = np->next) - if (np->parent && np->parent->type - && strcmp(np->parent->type, "adb") == 0) - break; - - /* needs to be hacked if xmon_printk is to be used - from within find_via_pmu() */ -#ifdef CONFIG_ADB_PMU - if (np != NULL && boot_text_mapped && find_via_pmu()) - use_screen = 1; -#endif -#ifdef CONFIG_ADB_CUDA - if (np != NULL && boot_text_mapped && find_via_cuda()) - use_screen = 1; -#endif - } - if (!use_screen && (np = find_devices("escc")) != NULL) { - /* - * look for the device node for the serial port - * we're using and see if it says it has a modem - */ - char *name = xmon_use_sccb? "ch-b": "ch-a"; - char *slots; - int l; - - np = np->child; - while (np != NULL && strcmp(np->name, name) != 0) - np = np->sibling; - if (np != NULL) { - /* XXX should parse this properly */ - channel_node = np; - slots = get_property(np, "slot-names", &l); - if (slots != NULL && l >= 10 - && strcmp(slots+4, "Modem") == 0) - via_modem = 1; - } - } - btext_drawstring("xmon uses "); - if (use_screen) - btext_drawstring("screen and keyboard\n"); - else { - if (via_modem) - btext_drawstring("modem on "); - btext_drawstring(xmon_use_sccb? "printer": "modem"); - btext_drawstring(" port\n"); - } - -#endif /* CONFIG_BOOTX_TEXT */ - -#ifdef CHRP_ESCC - addr = 0xc1013020; -#else - addr = 0xf3013020; -#endif - TXRDY = 4; - RXRDY = 1; - - np = find_devices("mac-io"); - if (np && np->n_addrs) - addr = np->addrs[0].address + 0x13020; - base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); - sccc = base + (addr & ~PAGE_MASK); - sccd = sccc + 0x10; - - } else { - base = (volatile unsigned char *) isa_io_base; - -#ifdef CONFIG_PPC_CHRP - if (_machine == _MACH_chrp) - base = (volatile unsigned char __iomem *) - ioremap(chrp_find_phys_io_base(), 0x1000); -#endif - - sccc = base + 0x3fd; - sccd = base + 0x3f8; - if (xmon_use_sccb) { - sccc -= 0x100; - sccd -= 0x100; - } - TXRDY = 0x20; - RXRDY = 1; - DLAB = 0x80; - } -#elif defined(CONFIG_GEMINI) - /* should already be mapped by the kernel boot */ - sccc = (volatile unsigned char __iomem *) 0xffeffb0d; - sccd = (volatile unsigned char __iomem *) 0xffeffb08; - TXRDY = 0x20; - RXRDY = 1; - DLAB = 0x80; -#elif defined(CONFIG_405GP) - sccc = (volatile unsigned char __iomem *)0xef600305; - sccd = (volatile unsigned char __iomem *)0xef600300; - TXRDY = 0x20; - RXRDY = 1; - DLAB = 0x80; -#endif /* platform */ -} - -static int scc_initialized = 0; - -void xmon_init_scc(void); -extern void cuda_poll(void); - -static inline void do_poll_adb(void) -{ -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll_adb(); -#endif /* CONFIG_ADB_PMU */ -#ifdef CONFIG_ADB_CUDA - if (sys_ctrler == SYS_CTRLER_CUDA) - cuda_poll(); -#endif /* CONFIG_ADB_CUDA */ -} - -int xmon_write(void *ptr, int nb) -{ - char *p = ptr; - int i, c, ct; - -#ifdef CONFIG_SMP - static unsigned long xmon_write_lock; - int lock_wait = 1000000; - int locked; - - while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0) - if (--lock_wait == 0) - break; -#endif - -#ifdef CONFIG_BOOTX_TEXT - if (use_screen) { - /* write it on the screen */ - for (i = 0; i < nb; ++i) - btext_drawchar(*p++); - goto out; - } -#endif - if (!scc_initialized) - xmon_init_scc(); - ct = 0; - for (i = 0; i < nb; ++i) { - while ((*sccc & TXRDY) == 0) - do_poll_adb(); - c = p[i]; - if (c == '\n' && !ct) { - c = '\r'; - ct = 1; - --i; - } else { - ct = 0; - } - buf_access(); - *sccd = c; - eieio(); - } - - out: -#ifdef CONFIG_SMP - if (!locked) - clear_bit(0, &xmon_write_lock); -#endif - return nb; -} - -int xmon_wants_key; -int xmon_adb_keycode; - -#ifdef CONFIG_BOOTX_TEXT -static int xmon_adb_shiftstate; - -static unsigned char xmon_keytab[128] = - "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ - "yt123465=97-80]o" /* 0x10 - 0x1f */ - "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ - "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ - "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ - "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ - -static unsigned char xmon_shift_keytab[128] = - "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ - "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */ - "U{IP\rLJ\"K:|" /* 0x20 - 0x2f */ - "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ - "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ - "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ - -static int xmon_get_adb_key(void) -{ - int k, t, on; - - xmon_wants_key = 1; - for (;;) { - xmon_adb_keycode = -1; - t = 0; - on = 0; - do { - if (--t < 0) { - on = 1 - on; - btext_drawchar(on? 0xdb: 0x20); - btext_drawchar('\b'); - t = 200000; - } - do_poll_adb(); - } while (xmon_adb_keycode == -1); - k = xmon_adb_keycode; - if (on) - btext_drawstring(" \b"); - - /* test for shift keys */ - if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { - xmon_adb_shiftstate = (k & 0x80) == 0; - continue; - } - if (k >= 0x80) - continue; /* ignore up transitions */ - k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; - if (k != 0) - break; - } - xmon_wants_key = 0; - return k; -} -#endif /* CONFIG_BOOTX_TEXT */ - -int xmon_readchar(void) -{ -#ifdef CONFIG_BOOTX_TEXT - if (use_screen) - return xmon_get_adb_key(); -#endif - if (!scc_initialized) - xmon_init_scc(); - while ((*sccc & RXRDY) == 0) - do_poll_adb(); - buf_access(); - return *sccd; -} - -int xmon_read_poll(void) -{ - if ((*sccc & RXRDY) == 0) { - do_poll_adb(); - return -1; - } - buf_access(); - return *sccd; -} - -static unsigned char scc_inittab[] = { - 13, 0, /* set baud rate divisor */ - 12, 1, - 14, 1, /* baud rate gen enable, src=rtxc */ - 11, 0x50, /* clocks = br gen */ - 5, 0xea, /* tx 8 bits, assert DTR & RTS */ - 4, 0x46, /* x16 clock, 1 stop */ - 3, 0xc1, /* rx enable, 8 bits */ -}; - -void xmon_init_scc(void) -{ - if ( _machine == _MACH_chrp ) - { - sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ - sccd[0] = 12; eieio(); /* DLL = 9600 baud */ - sccd[1] = 0; eieio(); - sccd[2] = 0; eieio(); /* FCR = 0 */ - sccd[3] = 3; eieio(); /* LCR = 8N1 */ - sccd[1] = 0; eieio(); /* IER = 0 */ - } - else if ( _machine == _MACH_Pmac ) - { - int i, x; - unsigned long timeout; - - if (channel_node != 0) - pmac_call_feature( - PMAC_FTR_SCC_ENABLE, - channel_node, - PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); - printk(KERN_INFO "Serial port locked ON by debugger !\n"); - if (via_modem && channel_node != 0) { - unsigned int t0; - - pmac_call_feature( - PMAC_FTR_MODEM_ENABLE, - channel_node, 0, 1); - printk(KERN_INFO "Modem powered up by debugger !\n"); - t0 = get_tbl(); - timeout = 3 * tb_ticks_per_sec; - if (timeout == 0) - /* assume 25MHz if tb_ticks_per_sec not set */ - timeout = 75000000; - while (get_tbl() - t0 < timeout) - eieio(); - } - /* use the B channel if requested */ - if (xmon_use_sccb) { - sccc = (volatile unsigned char *) - ((unsigned long)sccc & ~0x20); - sccd = sccc + 0x10; - } - for (i = 20000; i != 0; --i) { - x = *sccc; eieio(); - } - *sccc = 9; eieio(); /* reset A or B side */ - *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio(); - for (i = 0; i < sizeof(scc_inittab); ++i) { - *sccc = scc_inittab[i]; - eieio(); - } - } - scc_initialized = 1; - if (via_modem) { - for (;;) { - xmon_write("ATE1V1\r", 7); - if (xmon_expect("OK", 5)) { - xmon_write("ATA\r", 4); - if (xmon_expect("CONNECT", 40)) - break; - } - xmon_write("+++", 3); - xmon_expect("OK", 3); - } - } -} - -void xmon_enter(void) -{ -#ifdef CONFIG_ADB_PMU - if (_machine == _MACH_Pmac) { - pmu_suspend(); - } -#endif -} - -void xmon_leave(void) -{ -#ifdef CONFIG_ADB_PMU - if (_machine == _MACH_Pmac) { - pmu_resume(); - } -#endif -} diff --git a/arch/powerpc/xmon/start_64.c b/arch/powerpc/xmon/start_64.c deleted file mode 100644 index 712552c4f242..000000000000 --- a/arch/powerpc/xmon/start_64.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include "nonstdio.h" - -void xmon_map_scc(void) -{ -} - -int xmon_write(void *ptr, int nb) -{ - return udbg_write(ptr, nb); -} - -int xmon_readchar(void) -{ - if (udbg_getc) - return udbg_getc(); - return -1; -} - -int xmon_read_poll(void) -{ - if (udbg_getc_poll) - return udbg_getc_poll(); - return -1; -} diff --git a/arch/powerpc/xmon/start_8xx.c b/arch/powerpc/xmon/start_8xx.c deleted file mode 100644 index 4c17b0486ad5..000000000000 --- a/arch/powerpc/xmon/start_8xx.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 1996 Paul Mackerras. - * Copyright (C) 2000 Dan Malek. - * Quick hack of Paul's code to make XMON work on 8xx processors. Lots - * of assumptions, like the SMC1 is used, it has been initialized by the - * loader at some point, and we can just stuff and suck bytes. - * We rely upon the 8xx uart driver to support us, as the interface - * changes between boot up and operational phases of the kernel. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "nonstdio.h" - -extern int xmon_8xx_write(char *str, int nb); -extern int xmon_8xx_read_poll(void); -extern int xmon_8xx_read_char(void); - -void xmon_map_scc(void) -{ - cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); -} - -void xmon_init_scc(void); - -int xmon_write(void *ptr, int nb) -{ - return(xmon_8xx_write(ptr, nb)); -} - -int xmon_readchar(void) -{ - return xmon_8xx_read_char(); -} - -int xmon_read_poll(void) -{ - return(xmon_8xx_read_poll()); -} diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 0eb0b7085e6a..e707c6f6e61b 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -744,6 +744,9 @@ void __init setup_arch(char **cmdline_p) /* so udelay does something sensible, assume <= 1000 bogomips */ loops_per_jiffy = 500000000 / HZ; + if (ppc_md.init_early) + ppc_md.init_early(); + #ifdef CONFIG_PPC_MULTIPLATFORM /* This could be called "early setup arch", it must be done * now because xmon need it diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index d61f748278fc..93e7080e3bc5 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -505,16 +505,23 @@ static int create_iface(struct device_node *np, struct device *dev) { unsigned long steps; - unsigned bsteps, tsize, i, nchan, addroffset; + unsigned bsteps, tsize, i, nchan; struct keywest_iface* iface; - u32 *psteps, *prate; + u32 *psteps, *prate, *addrp; int rc; - if (np->n_intrs < 1 || np->n_addrs < 1) { - printk(KERN_ERR "%s: Missing interrupt or address !\n", + if (np->n_intrs < 1) { + printk(KERN_ERR "%s: Missing interrupt !\n", np->full_name); return -ENODEV; } + addrp = (u32 *)get_property(np, "AAPL,address", NULL); + if (addrp == NULL) { + printk(KERN_ERR "%s: Can't find address !\n", + np->full_name); + return -ENODEV; + } + if (pmac_low_i2c_lock(np)) return -ENODEV; @@ -525,13 +532,10 @@ create_iface(struct device_node *np, struct device *dev) for (bsteps = 0; (steps & 0x01) == 0; bsteps++) steps >>= 1; - if (np->parent->name[0] == 'u') { + if (np->parent->name[0] == 'u') nchan = 2; - addroffset = 3; - } else { - addroffset = 0; + else nchan = 1; - } tsize = sizeof(struct keywest_iface) + (sizeof(struct keywest_chan) + 4) * nchan; @@ -550,8 +554,7 @@ create_iface(struct device_node *np, struct device *dev) iface->irq = np->intrs[0].line; iface->channels = (struct keywest_chan *) (((unsigned long)(iface + 1) + 3UL) & ~3UL); - iface->base = ioremap(np->addrs[0].address + addroffset, - np->addrs[0].size); + iface->base = ioremap(*addrp, 0x1000); if (!iface->base) { printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); kfree(iface); diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index d843a6c9c6df..18ff770ea668 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -127,39 +127,34 @@ struct adb_driver via_cuda_driver = { #endif /* CONFIG_ADB */ #ifdef CONFIG_PPC -int __init -find_via_cuda(void) +int __init find_via_cuda(void) { - int err; struct adb_request req; + phys_addr_t taddr; + u32 *reg; + int err; if (vias != 0) return 1; - vias = find_devices("via-cuda"); + vias = of_find_node_by_name(NULL, "via-cuda"); if (vias == 0) return 0; - if (vias->next != 0) - printk(KERN_WARNING "Warning: only using 1st via-cuda\n"); - -#if 0 - { int i; - - printk("find_via_cuda: node = %p, addrs =", vias->node); - for (i = 0; i < vias->n_addrs; ++i) - printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size); - printk(", intrs ="); - for (i = 0; i < vias->n_intrs; ++i) - printk(" %x", vias->intrs[i].line); - printk("\n"); } -#endif - if (vias->n_addrs != 1 || vias->n_intrs != 1) { - printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n", - vias->n_addrs, vias->n_intrs); - if (vias->n_addrs < 1 || vias->n_intrs < 1) - return 0; + reg = (u32 *)get_property(vias, "reg", NULL); + if (reg == NULL) { + printk(KERN_ERR "via-cuda: No \"reg\" property !\n"); + goto fail; + } + taddr = of_translate_address(vias, reg); + if (taddr == 0) { + printk(KERN_ERR "via-cuda: Can't translate address !\n"); + goto fail; + } + via = ioremap(taddr, 0x2000); + if (via == NULL) { + printk(KERN_ERR "via-cuda: Can't map address !\n"); + goto fail; } - via = ioremap(vias->addrs->address, 0x2000); cuda_state = idle; sys_ctrler = SYS_CTRLER_CUDA; @@ -185,6 +180,11 @@ find_via_cuda(void) cuda_poll(); return 1; + + fail: + of_node_put(vias); + vias = NULL; + return 0; } #endif /* CONFIG_PPC */ diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 564043508569..13881f199607 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -147,6 +147,7 @@ static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; static int pmu_has_adb; +static struct device_node *gpio_node; static unsigned char __iomem *gpio_reg = NULL; static int gpio_irq = -1; static int gpio_irq_enabled = -1; @@ -295,22 +296,26 @@ static struct backlight_controller pmu_backlight_controller = { }; #endif /* CONFIG_PMAC_BACKLIGHT */ -int -find_via_pmu(void) +int __init find_via_pmu(void) { + phys_addr_t taddr; + u32 *reg; + if (via != 0) return 1; - vias = find_devices("via-pmu"); - if (vias == 0) + vias = of_find_node_by_name(NULL, "via-pmu"); + if (vias == NULL) return 0; - if (vias->next != 0) - printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); - if (vias->n_addrs < 1 || vias->n_intrs < 1) { - printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n", - vias->n_addrs, vias->n_intrs); - if (vias->n_addrs < 1 || vias->n_intrs < 1) - return 0; + reg = (u32 *)get_property(vias, "reg", NULL); + if (reg == NULL) { + printk(KERN_ERR "via-pmu: No \"reg\" property !\n"); + goto fail; + } + taddr = of_translate_address(vias, reg); + if (taddr == 0) { + printk(KERN_ERR "via-pmu: Can't translate address !\n"); + goto fail; } spin_lock_init(&pmu_lock); @@ -331,7 +336,8 @@ find_via_pmu(void) pmu_kind = PMU_HEATHROW_BASED; else if (device_is_compatible(vias->parent, "Keylargo") || device_is_compatible(vias->parent, "K2-Keylargo")) { - struct device_node *gpio, *gpiop; + struct device_node *gpiop; + phys_addr_t gaddr = 0; pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); @@ -341,19 +347,24 @@ find_via_pmu(void) PMU_INT_TICK | PMU_INT_ENVIRONMENT; - gpiop = find_devices("gpio"); - if (gpiop && gpiop->n_addrs) { - gpio_reg = ioremap(gpiop->addrs->address, 0x10); - gpio = find_devices("extint-gpio1"); - if (gpio == NULL) - gpio = find_devices("pmu-interrupt"); - if (gpio && gpio->parent == gpiop && gpio->n_intrs) - gpio_irq = gpio->intrs[0].line; + gpiop = of_find_node_by_name(NULL, "gpio"); + if (gpiop) { + reg = (u32 *)get_property(gpiop, "reg", NULL); + if (reg) + gaddr = of_translate_address(gpiop, reg); + if (gaddr != 0) + gpio_reg = ioremap(gaddr, 0x10); } + if (gpio_reg == NULL) + printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n"); } else pmu_kind = PMU_UNKNOWN; - via = ioremap(vias->addrs->address, 0x2000); + via = ioremap(taddr, 0x2000); + if (via == NULL) { + printk(KERN_ERR "via-pmu: Can't map address !\n"); + goto fail; + } out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ out_8(&via[IFR], 0x7f); /* clear IFR */ @@ -371,17 +382,19 @@ find_via_pmu(void) sys_ctrler = SYS_CTRLER_PMU; return 1; + fail: + of_node_put(vias); + vias = NULL; + return 0; } #ifdef CONFIG_ADB -static int -pmu_probe(void) +static int pmu_probe(void) { return vias == NULL? -ENODEV: 0; } -static int __init -pmu_init(void) +static int __init pmu_init(void) { if (vias == NULL) return -ENODEV; @@ -405,7 +418,7 @@ static int __init via_pmu_start(void) bright_req_2.complete = 1; batt_req.complete = 1; -#if defined(CONFIG_PPC32) && !defined(CONFIG_PPC_MERGE) +#ifndef CONFIG_PPC_MERGE if (pmu_kind == PMU_KEYLARGO_BASED) openpic_set_irq_priority(vias->intrs[0].line, OPENPIC_PRIORITY_DEFAULT + 1); @@ -418,10 +431,22 @@ static int __init via_pmu_start(void) return -EAGAIN; } - if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) { - if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1 ADB", (void *)0)) - printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq); - gpio_irq_enabled = 1; + if (pmu_kind == PMU_KEYLARGO_BASED) { + gpio_node = of_find_node_by_name(NULL, "extint-gpio1"); + if (gpio_node == NULL) + gpio_node = of_find_node_by_name(NULL, + "pmu-interrupt"); + if (gpio_node && gpio_node->n_intrs > 0) + gpio_irq = gpio_node->intrs[0].line; + + if (gpio_irq != -1) { + if (request_irq(gpio_irq, gpio1_interrupt, 0, + "GPIO1 ADB", (void *)0)) + printk(KERN_ERR "pmu: can't get irq %d" + " (GPIO1)\n", gpio_irq); + else + gpio_irq_enabled = 1; + } } /* Enable interrupts */ @@ -1371,7 +1396,6 @@ next: } pmu_done(req); } else { -#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64) if (len == 4 && data[1] == 0x2c) { extern int xmon_wants_key, xmon_adb_keycode; if (xmon_wants_key) { @@ -1379,7 +1403,6 @@ next: return; } } -#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */ #ifdef CONFIG_ADB /* * XXX On the [23]400 the PMU gives us an up diff --git a/include/asm-powerpc/btext.h b/include/asm-powerpc/btext.h index 71cce36bc630..906f46e31006 100644 --- a/include/asm-powerpc/btext.h +++ b/include/asm-powerpc/btext.h @@ -7,21 +7,22 @@ #define __PPC_BTEXT_H #ifdef __KERNEL__ -extern void btext_clearscreen(void); -extern void btext_flushscreen(void); - -extern int boot_text_mapped; - -extern int btext_initialize(struct device_node *np); - -extern void map_boot_text(void); -extern void init_boot_display(void); +extern int btext_find_display(int allow_nonstdout); extern void btext_update_display(unsigned long phys, int width, int height, int depth, int pitch); +extern void btext_setup_display(int width, int height, int depth, int pitch, + unsigned long address); +extern void btext_prepare_BAT(void); +extern void btext_unmap(void); extern void btext_drawchar(char c); extern void btext_drawstring(const char *str); extern void btext_drawhex(unsigned long v); +extern void btext_drawtext(const char *c, unsigned int len); + +extern void btext_clearscreen(void); +extern void btext_flushscreen(void); +extern void btext_flushline(void); #endif /* __KERNEL__ */ #endif /* __PPC_BTEXT_H */ diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index 4049a96dc43d..8d6b44c8f35d 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -13,8 +13,8 @@ #include #include -extern void (*udbg_putc)(unsigned char c); -extern unsigned char (*udbg_getc)(void); +extern void (*udbg_putc)(char c); +extern char (*udbg_getc)(void); extern int (*udbg_getc_poll)(void); extern void udbg_puts(const char *s); @@ -30,5 +30,8 @@ extern unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock); struct device_node; -extern void udbg_init_scc(struct device_node *np); +extern void udbg_scc_init(int force_scc); +extern int udbg_adb_init(int force_btext); +extern void udbg_adb_init_early(void); + #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h index ccaefabe0bf5..ed3630251b3b 100644 --- a/include/asm-ppc/btext.h +++ b/include/asm-ppc/btext.h @@ -17,7 +17,7 @@ extern unsigned long disp_BAT[2]; extern boot_infos_t disp_bi; extern int boot_text_mapped; -extern void init_boot_display(void); +extern void btext_init(boot_infos_t *bi); extern void btext_welcome(void); extern void btext_prepare_BAT(void); extern void btext_setup_display(int width, int height, int depth, int pitch, diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index f01255bd1dc3..39200def8d11 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -35,8 +35,10 @@ struct machdep_calls { int (*get_irq)(struct pt_regs *); /* A general init function, called by ppc_init in init/main.c. - May be NULL. */ + May be NULL. DEPRECATED ! */ void (*init)(void); + /* For compatibility with merged platforms */ + void (*init_early)(void); void (*restart)(char *cmd); void (*power_off)(void); -- cgit v1.2.3 From d7f3945420b5d8114f2d4d85e90abe5063cc196a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 23 Nov 2005 17:58:13 +1100 Subject: [PATCH] powerpc: Add back support for booting from BootX (#2) ARCH=powerpc couldn't boot from BootX as it uses a "different" way of getting in the kernel. This patch adds the necessary trampolines, creating a flattened device-tree from the tree passed from MacOS, and initializing the btext engine early for really-early debugging. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_32.S | 13 + arch/powerpc/platforms/powermac/Makefile | 3 + arch/powerpc/platforms/powermac/bootx_init.c | 547 +++++++++++++++++++++++++++ include/asm-powerpc/bootx.h | 166 ++++++++ 4 files changed, 729 insertions(+) create mode 100644 arch/powerpc/platforms/powermac/bootx_init.c create mode 100644 include/asm-powerpc/bootx.h diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index fdd34dbd8797..6359e364fe66 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -125,6 +125,19 @@ __start: bl prom_init trap +/* + * Check for BootX signature when supporting PowerMac and branch to + * appropriate trampoline if it's present + */ +#ifdef CONFIG_PPC_PMAC +1: lis r31,0x426f + ori r31,r31,0x6f58 + cmpw 0,r3,r31 + bne 1f + bl bootx_init + trap +#endif /* CONFIG_PPC_PMAC */ + 1: mr r31,r3 /* save parameters */ mr r30,r4 li r24,0 /* cpu # */ diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 3e5370eeb1b7..faa1a2c82bcf 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,3 +1,5 @@ +CFLAGS_bootx_init.o += -fPIC + obj-y += pic.o setup.o time.o feature.o pci.o \ sleep.o low_i2c.o cache.o obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o @@ -6,5 +8,6 @@ obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o obj-$(CONFIG_NVRAM) += nvram.o # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff obj-$(CONFIG_PPC64) += nvram.o +obj-$(CONFIG_PPC32) += bootx_init.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_MERGE) += udbg_scc.o udbg_adb.o diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c new file mode 100644 index 000000000000..fa8b4d7b5ded --- /dev/null +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -0,0 +1,547 @@ +/* + * Early boot support code for BootX bootloader + * + * Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#define SET_BOOT_BAT + +#ifdef DEBUG +#define DBG(fmt...) do { bootx_printf(fmt); } while(0) +#else +#define DBG(fmt...) do { } while(0) +#endif + +extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); + +static unsigned long __initdata bootx_dt_strbase; +static unsigned long __initdata bootx_dt_strend; +static unsigned long __initdata bootx_node_chosen; +static boot_infos_t * __initdata bootx_info; +static char __initdata bootx_disp_path[256]; + +/* Is boot-info compatible ? */ +#define BOOT_INFO_IS_COMPATIBLE(bi) \ + ((bi)->compatible_version <= BOOT_INFO_VERSION) +#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) +#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) + +#ifdef CONFIG_BOOTX_TEXT +static void __init bootx_printf(const char *format, ...) +{ + const char *p, *q, *s; + va_list args; + unsigned long v; + + va_start(args, format); + for (p = format; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) + ; + if (q > p) + btext_drawtext(p, q - p); + if (*q == 0) + break; + if (*q == '\n') { + ++q; + btext_flushline(); + btext_drawstring("\r\n"); + btext_flushline(); + continue; + } + ++q; + if (*q == 0) + break; + switch (*q) { + case 's': + ++q; + s = va_arg(args, const char *); + if (s == NULL) + s = ""; + btext_drawstring(s); + break; + case 'x': + ++q; + v = va_arg(args, unsigned long); + btext_drawhex(v); + break; + } + } +} +#else /* CONFIG_BOOTX_TEXT */ +static void __init bootx_printf(const char *format, ...) {} +#endif /* CONFIG_BOOTX_TEXT */ + +static void * __init bootx_early_getprop(unsigned long base, + unsigned long node, + char *prop) +{ + struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node); + u32 *ppp = &np->properties; + + while(*ppp) { + struct bootx_dt_prop *pp = + (struct bootx_dt_prop *)(base + *ppp); + + if (strcmp((char *)((unsigned long)pp->name + base), + prop) == 0) { + return (void *)((unsigned long)pp->value + base); + } + ppp = &pp->next; + } + return NULL; +} + +#define dt_push_token(token, mem) \ + do { \ + *(mem) = _ALIGN_UP(*(mem),4); \ + *((u32 *)*(mem)) = token; \ + *(mem) += 4; \ + } while(0) + +static unsigned long __init bootx_dt_find_string(char *str) +{ + char *s, *os; + + s = os = (char *)bootx_dt_strbase; + s += 4; + while (s < (char *)bootx_dt_strend) { + if (strcmp(s, str) == 0) + return s - os; + s += strlen(s) + 1; + } + return 0; +} + +static void __init bootx_dt_add_prop(char *name, void *data, int size, + unsigned long *mem_end) +{ + unsigned long soff = bootx_dt_find_string(name); + if (data == NULL) + size = 0; + if (soff == 0) { + bootx_printf("WARNING: Can't find string index for <%s>\n", + name); + return; + } + if (size > 0x20000) { + bootx_printf("WARNING: ignoring large property "); + bootx_printf("%s length 0x%x\n", name, size); + return; + } + dt_push_token(OF_DT_PROP, mem_end); + dt_push_token(size, mem_end); + dt_push_token(soff, mem_end); + + /* push property content */ + if (size && data) { + memcpy((void *)*mem_end, data, size); + *mem_end = _ALIGN_UP(*mem_end + size, 4); + } +} + +static void __init bootx_add_chosen_props(unsigned long base, + unsigned long *mem_end) +{ + u32 val = _MACH_Pmac; + + bootx_dt_add_prop("linux,platform", &val, 4, mem_end); + + if (bootx_info->kernelParamsOffset) { + char *args = (char *)((unsigned long)bootx_info) + + bootx_info->kernelParamsOffset; + bootx_dt_add_prop("bootargs", args, strlen(args) + 1, mem_end); + } + if (bootx_info->ramDisk) { + val = ((unsigned long)bootx_info) + bootx_info->ramDisk; + bootx_dt_add_prop("linux,initrd-start", &val, 4, mem_end); + val += bootx_info->ramDiskSize; + bootx_dt_add_prop("linux,initrd-end", &val, 4, mem_end); + } + if (strlen(bootx_disp_path)) + bootx_dt_add_prop("linux,stdout-path", bootx_disp_path, + strlen(bootx_disp_path) + 1, mem_end); +} + +static void __init bootx_add_display_props(unsigned long base, + unsigned long *mem_end) +{ + bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end); + bootx_dt_add_prop("linux,opened", NULL, 0, mem_end); +} + +static void __init bootx_dt_add_string(char *s, unsigned long *mem_end) +{ + unsigned int l = strlen(s) + 1; + memcpy((void *)*mem_end, s, l); + bootx_dt_strend = *mem_end = *mem_end + l; +} + +static void __init bootx_scan_dt_build_strings(unsigned long base, + unsigned long node, + unsigned long *mem_end) +{ + struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node); + u32 *cpp, *ppp = &np->properties; + unsigned long soff; + char *namep; + + /* Keep refs to known nodes */ + namep = np->full_name ? (char *)(base + np->full_name) : NULL; + if (namep == NULL) { + bootx_printf("Node without a full name !\n"); + namep = ""; + } + DBG("* strings: %s\n", namep); + + if (!strcmp(namep, "/chosen")) { + DBG(" detected /chosen ! adding properties names !\n"); + bootx_dt_add_string("linux,platform", mem_end); + bootx_dt_add_string("linux,stdout-path", mem_end); + bootx_dt_add_string("linux,initrd-start", mem_end); + bootx_dt_add_string("linux,initrd-end", mem_end); + bootx_dt_add_string("bootargs", mem_end); + bootx_node_chosen = node; + } + if (node == bootx_info->dispDeviceRegEntryOffset) { + DBG(" detected display ! adding properties names !\n"); + bootx_dt_add_string("linux,boot-display", mem_end); + bootx_dt_add_string("linux,opened", mem_end); + strncpy(bootx_disp_path, namep, 255); + } + + /* get and store all property names */ + while (*ppp) { + struct bootx_dt_prop *pp = + (struct bootx_dt_prop *)(base + *ppp); + + namep = pp->name ? (char *)(base + pp->name) : NULL; + if (namep == NULL || strcmp(namep, "name") == 0) + goto next; + /* get/create string entry */ + soff = bootx_dt_find_string(namep); + if (soff == 0) + bootx_dt_add_string(namep, mem_end); + next: + ppp = &pp->next; + } + + /* do all our children */ + cpp = &np->child; + while(*cpp) { + np = (struct bootx_dt_node *)(base + *cpp); + bootx_scan_dt_build_strings(base, *cpp, mem_end); + cpp = &np->sibling; + } +} + +static void __init bootx_scan_dt_build_struct(unsigned long base, + unsigned long node, + unsigned long *mem_end) +{ + struct bootx_dt_node *np = (struct bootx_dt_node *)(base + node); + u32 *cpp, *ppp = &np->properties; + char *namep, *p, *ep, *lp; + int l; + + dt_push_token(OF_DT_BEGIN_NODE, mem_end); + + /* get the node's full name */ + namep = np->full_name ? (char *)(base + np->full_name) : NULL; + if (namep == NULL) + namep = ""; + l = strlen(namep); + + DBG("* struct: %s\n", namep); + + /* Fixup an Apple bug where they have bogus \0 chars in the + * middle of the path in some properties, and extract + * the unit name (everything after the last '/'). + */ + memcpy((void *)*mem_end, namep, l + 1); + namep = (char *)*mem_end; + for (lp = p = namep, ep = namep + l; p < ep; p++) { + if (*p == '/') + lp = namep; + else if (*p != 0) + *lp++ = *p; + } + *lp = 0; + *mem_end = _ALIGN_UP((unsigned long)lp + 1, 4); + + /* get and store all properties */ + while (*ppp) { + struct bootx_dt_prop *pp = + (struct bootx_dt_prop *)(base + *ppp); + + namep = pp->name ? (char *)(base + pp->name) : NULL; + /* Skip "name" */ + if (namep == NULL || !strcmp(namep, "name")) + goto next; + /* Skip "bootargs" in /chosen too as we replace it */ + if (node == bootx_node_chosen && !strcmp(namep, "bootargs")) + goto next; + + /* push property head */ + bootx_dt_add_prop(namep, + pp->value ? (void *)(base + pp->value): NULL, + pp->length, mem_end); + next: + ppp = &pp->next; + } + + if (node == bootx_node_chosen) + bootx_add_chosen_props(base, mem_end); + if (node == bootx_info->dispDeviceRegEntryOffset) + bootx_add_display_props(base, mem_end); + + /* do all our children */ + cpp = &np->child; + while(*cpp) { + np = (struct bootx_dt_node *)(base + *cpp); + bootx_scan_dt_build_struct(base, *cpp, mem_end); + cpp = &np->sibling; + } + + dt_push_token(OF_DT_END_NODE, mem_end); +} + +static unsigned long __init bootx_flatten_dt(unsigned long start) +{ + boot_infos_t *bi = bootx_info; + unsigned long mem_start, mem_end; + struct boot_param_header *hdr; + unsigned long base; + u64 *rsvmap; + + /* Start using memory after the big blob passed by BootX, get + * some space for the header + */ + mem_start = mem_end = _ALIGN_UP(((unsigned long)bi) + start, 4); + DBG("Boot params header at: %x\n", mem_start); + hdr = (struct boot_param_header *)mem_start; + mem_end += sizeof(struct boot_param_header); + rsvmap = (u64 *)(_ALIGN_UP(mem_end, 8)); + hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - mem_start; + mem_end = ((unsigned long)rsvmap) + 8 * sizeof(u64); + + /* Get base of tree */ + base = ((unsigned long)bi) + bi->deviceTreeOffset; + + /* Build string array */ + DBG("Building string array at: %x\n", mem_end); + DBG("Device Tree Base=%x\n", base); + bootx_dt_strbase = mem_end; + mem_end += 4; + bootx_dt_strend = mem_end; + bootx_scan_dt_build_strings(base, 4, &mem_end); + hdr->off_dt_strings = bootx_dt_strbase - mem_start; + hdr->dt_strings_size = bootx_dt_strend - bootx_dt_strbase; + + /* Build structure */ + mem_end = _ALIGN(mem_end, 16); + DBG("Building device tree structure at: %x\n", mem_end); + hdr->off_dt_struct = mem_end - mem_start; + bootx_scan_dt_build_struct(base, 4, &mem_end); + dt_push_token(OF_DT_END, &mem_end); + + /* Finish header */ + hdr->boot_cpuid_phys = 0; + hdr->magic = OF_DT_HEADER; + hdr->totalsize = mem_end - mem_start; + hdr->version = OF_DT_VERSION; + /* Version 16 is not backward compatible */ + hdr->last_comp_version = 0x10; + + /* Reserve the whole thing and copy the reserve map in, we + * also bump mem_reserve_cnt to cause further reservations to + * fail since it's too late. + */ + mem_end = _ALIGN(mem_end, PAGE_SIZE); + DBG("End of boot params: %x\n", mem_end); + rsvmap[0] = mem_start; + rsvmap[1] = mem_end; + rsvmap[2] = 0; + rsvmap[3] = 0; + + return (unsigned long)hdr; +} + + +#ifdef CONFIG_BOOTX_TEXT +static void __init btext_welcome(boot_infos_t *bi) +{ + unsigned long flags; + unsigned long pvr; + + bootx_printf("Welcome to Linux, kernel " UTS_RELEASE "\n"); + bootx_printf("\nlinked at : 0x%x", KERNELBASE); + bootx_printf("\nframe buffer at : 0x%x", bi->dispDeviceBase); + bootx_printf(" (phys), 0x%x", bi->logicalDisplayBase); + bootx_printf(" (log)"); + bootx_printf("\nklimit : 0x%x",(unsigned long)klimit); + bootx_printf("\nboot_info at : 0x%x", bi); + __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); + bootx_printf("\nMSR : 0x%x", flags); + __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); + bootx_printf("\nPVR : 0x%x", pvr); + pvr >>= 16; + if (pvr > 1) { + __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); + bootx_printf("\nHID0 : 0x%x", flags); + } + if (pvr == 8 || pvr == 12 || pvr == 0x800c) { + __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); + bootx_printf("\nICTC : 0x%x", flags); + } +#ifdef DEBUG + bootx_printf("\n\n"); + bootx_printf("bi->deviceTreeOffset : 0x%x\n", + bi->deviceTreeOffset); + bootx_printf("bi->deviceTreeSize : 0x%x\n", + bi->deviceTreeSize); +#endif + bootx_printf("\n\n"); +} +#endif /* CONFIG_BOOTX_TEXT */ + +void __init bootx_init(unsigned long r3, unsigned long r4) +{ + boot_infos_t *bi = (boot_infos_t *) r4; + unsigned long hdr; + unsigned long space; + unsigned long ptr, x; + char *model; + unsigned long offset = reloc_offset(); + + reloc_got2(offset); + + bootx_info = bi; + + /* We haven't cleared any bss at this point, make sure + * what we need is initialized + */ + bootx_dt_strbase = bootx_dt_strend = 0; + bootx_node_chosen = 0; + bootx_disp_path[0] = 0; + + if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) + bi->logicalDisplayBase = bi->dispDeviceBase; + +#ifdef CONFIG_BOOTX_TEXT + btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0], + bi->dispDeviceRect[3] - bi->dispDeviceRect[1], + bi->dispDeviceDepth, bi->dispDeviceRowBytes, + (unsigned long)bi->logicalDisplayBase); + btext_clearscreen(); + btext_flushscreen(); +#endif /* CONFIG_BOOTX_TEXT */ + + /* + * Test if boot-info is compatible. Done only in config + * CONFIG_BOOTX_TEXT since there is nothing much we can do + * with an incompatible version, except display a message + * and eventually hang the processor... + * + * I'll try to keep enough of boot-info compatible in the + * future to always allow display of this message; + */ + if (!BOOT_INFO_IS_COMPATIBLE(bi)) { + bootx_printf(" !!! WARNING - Incompatible version" + " of BootX !!!\n\n\n"); + for (;;) + ; + } + if (bi->architecture != BOOT_ARCH_PCI) { + bootx_printf(" !!! WARNING - Usupported machine" + " architecture !\n"); + for (;;) + ; + } + +#ifdef CONFIG_BOOTX_TEXT + btext_welcome(bi); +#endif + /* New BootX enters kernel with MMU off, i/os are not allowed + * here. This hack will have been done by the boostrap anyway. + */ + if (bi->version < 4) { + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) bootx_early_getprop(r4 + bi->deviceTreeOffset, + 4, "model"); + if (model + && (strcmp(model, "iMac,1") == 0 + || strcmp(model, "PowerMac1,1") == 0)) { + bootx_printf("iMac,1 detected, shutting down USB \n"); + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } + } + + /* Get a pointer that points above the device tree, args, ramdisk, + * etc... to use for generating the flattened tree + */ + if (bi->version < 5) { + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + } else + space = bi->totalParamsSize; + + bootx_printf("Total space used by parameters & ramdisk: %x \n", space); + + /* New BootX will have flushed all TLBs and enters kernel with + * MMU switched OFF, so this should not be useful anymore. + */ + if (bi->version < 4) { + bootx_printf("Touching pages...\n"); + + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = ((unsigned long) &_stext) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; + } + + /* Ok, now we need to generate a flattened device-tree to pass + * to the kernel + */ + bootx_printf("Preparing boot params...\n"); + + hdr = bootx_flatten_dt(space); + +#ifdef CONFIG_BOOTX_TEXT +#ifdef SET_BOOT_BAT + bootx_printf("Preparing BAT...\n"); + btext_prepare_BAT(); +#else + btext_unmap(); +#endif +#endif + + reloc_got2(-offset); + + __start(hdr, KERNELBASE + offset, 0); +} diff --git a/include/asm-powerpc/bootx.h b/include/asm-powerpc/bootx.h new file mode 100644 index 000000000000..ed626b7cbf22 --- /dev/null +++ b/include/asm-powerpc/bootx.h @@ -0,0 +1,166 @@ +/* + * This file describes the structure passed from the BootX application + * (for MacOS) when it is used to boot Linux. + * + * Written by Benjamin Herrenschmidt. + */ + + +#ifndef __ASM_BOOTX_H__ +#define __ASM_BOOTX_H__ + +#ifdef macintosh +#include +#include "linux_type_defs.h" +#endif + +#ifdef macintosh +/* All this requires PowerPC alignment */ +#pragma options align=power +#endif + +/* On kernel entry: + * + * r3 = 0x426f6f58 ('BooX') + * r4 = pointer to boot_infos + * r5 = NULL + * + * Data and instruction translation disabled, interrupts + * disabled, kernel loaded at physical 0x00000000 on PCI + * machines (will be different on NuBus). + */ + +#define BOOT_INFO_VERSION 5 +#define BOOT_INFO_COMPATIBLE_VERSION 1 + +/* Bit in the architecture flag mask. More to be defined in + future versions. Note that either BOOT_ARCH_PCI or + BOOT_ARCH_NUBUS is set. The other BOOT_ARCH_NUBUS_xxx are + set additionally when BOOT_ARCH_NUBUS is set. + */ +#define BOOT_ARCH_PCI 0x00000001UL +#define BOOT_ARCH_NUBUS 0x00000002UL +#define BOOT_ARCH_NUBUS_PDM 0x00000010UL +#define BOOT_ARCH_NUBUS_PERFORMA 0x00000020UL +#define BOOT_ARCH_NUBUS_POWERBOOK 0x00000040UL + +/* Maximum number of ranges in phys memory map */ +#define MAX_MEM_MAP_SIZE 26 + +/* This is the format of an element in the physical memory map. Note that + the map is optional and current BootX will only build it for pre-PCI + machines */ +typedef struct boot_info_map_entry +{ + __u32 physAddr; /* Physical starting address */ + __u32 size; /* Size in bytes */ +} boot_info_map_entry_t; + + +/* Here are the boot informations that are passed to the bootstrap + * Note that the kernel arguments and the device tree are appended + * at the end of this structure. */ +typedef struct boot_infos +{ + /* Version of this structure */ + __u32 version; + /* backward compatible down to version: */ + __u32 compatible_version; + + /* NEW (vers. 2) this holds the current _logical_ base addr of + the frame buffer (for use by early boot message) */ + __u8* logicalDisplayBase; + + /* NEW (vers. 4) Apple's machine identification */ + __u32 machineID; + + /* NEW (vers. 4) Detected hw architecture */ + __u32 architecture; + + /* The device tree (internal addresses relative to the beginning of the tree, + * device tree offset relative to the beginning of this structure). + * On pre-PCI macintosh (BOOT_ARCH_PCI bit set to 0 in architecture), this + * field is 0. + */ + __u32 deviceTreeOffset; /* Device tree offset */ + __u32 deviceTreeSize; /* Size of the device tree */ + + /* Some infos about the current MacOS display */ + __u32 dispDeviceRect[4]; /* left,top,right,bottom */ + __u32 dispDeviceDepth; /* (8, 16 or 32) */ + __u8* dispDeviceBase; /* base address (physical) */ + __u32 dispDeviceRowBytes; /* rowbytes (in bytes) */ + __u32 dispDeviceColorsOffset; /* Colormap (8 bits only) or 0 (*) */ + /* Optional offset in the registry to the current + * MacOS display. (Can be 0 when not detected) */ + __u32 dispDeviceRegEntryOffset; + + /* Optional pointer to boot ramdisk (offset from this structure) */ + __u32 ramDisk; + __u32 ramDiskSize; /* size of ramdisk image */ + + /* Kernel command line arguments (offset from this structure) */ + __u32 kernelParamsOffset; + + /* ALL BELOW NEW (vers. 4) */ + + /* This defines the physical memory. Valid with BOOT_ARCH_NUBUS flag + (non-PCI) only. On PCI, memory is contiguous and it's size is in the + device-tree. */ + boot_info_map_entry_t + physMemoryMap[MAX_MEM_MAP_SIZE]; /* Where the phys memory is */ + __u32 physMemoryMapSize; /* How many entries in map */ + + + /* The framebuffer size (optional, currently 0) */ + __u32 frameBufferSize; /* Represents a max size, can be 0. */ + + /* NEW (vers. 5) */ + + /* Total params size (args + colormap + device tree + ramdisk) */ + __u32 totalParamsSize; + +} boot_infos_t; + +/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index + * is represented by 3 short words containing a 16 bits (unsigned) color + * component. Later versions may contain the gamma table for direct-color + * devices here. + */ +#define BOOTX_COLORTABLE_SIZE (256UL*3UL*2UL) + +/* BootX passes the device-tree using a format that comes from earlier + * ppc32 kernels. This used to match what is in prom.h, but not anymore + * so we now define it here + */ +struct bootx_dt_prop { + u32 name; + int length; + u32 value; + u32 next; +}; + +struct bootx_dt_node { + u32 unused0; + u32 unused1; + u32 phandle; /* not really available */ + u32 unused2; + u32 unused3; + u32 unused4; + u32 unused5; + u32 full_name; + u32 properties; + u32 parent; + u32 child; + u32 sibling; + u32 next; + u32 allnext; +}; + +extern void bootx_init(unsigned long r4, unsigned long phys); + +#ifdef macintosh +#pragma options align=reset +#endif + +#endif -- cgit v1.2.3 From 2c5bd01f8f5d7c655d9d1aa60b696d980947e3be Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 23 Nov 2005 17:59:04 +1100 Subject: [PATCH] powerpc: convert macio_asic to use prom_parse Converts the macio_asic core to use the new OF parsing routines instead of relying on the pre-parsed values in struct device_node. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/macintosh/macio_asic.c | 234 ++++++++++++++++++++++++----------------- 1 file changed, 140 insertions(+), 94 deletions(-) diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 228e1852a836..f14c744a94ef 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -3,6 +3,13 @@ * a MacIO ASIC. Interface to new driver model mostly * stolen from the PCI version. * + * Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * * TODO: * * - Don't probe below media bay by default, but instead provide @@ -218,12 +225,14 @@ postcore_initcall(macio_bus_driver_init); /** - * macio_release_dev - free a macio device structure when all users of it are finished. + * macio_release_dev - free a macio device structure when all users of it are + * finished. * @dev: device that's been disconnected * - * Will be called only by the device core when all users of this macio device are - * done. This currently means never as we don't hot remove any macio device yet, - * though that will happen with mediabay based devices in a later implementation. + * Will be called only by the device core when all users of this macio device + * are done. This currently means never as we don't hot remove any macio + * device yet, though that will happen with mediabay based devices in a later + * implementation. */ static void macio_release_dev(struct device *dev) { @@ -242,7 +251,8 @@ static void macio_release_dev(struct device *dev) * If this routine returns non-null, then the resource is completely * skipped. */ -static int macio_resource_quirks(struct device_node *np, struct resource *res, int index) +static int macio_resource_quirks(struct device_node *np, struct resource *res, + int index) { if (res->flags & IORESOURCE_MEM) { /* Grand Central has too large resource 0 on some machines */ @@ -258,12 +268,15 @@ static int macio_resource_quirks(struct device_node *np, struct resource *res, i np->addrs[index].size = 0x100; res->end = res->start + 0xff; } - /* ESCC parent eats child resources. We could have added a level of hierarchy, - * but I don't really feel the need for it */ + /* ESCC parent eats child resources. We could have added a + * level of hierarchy, but I don't really feel the need + * for it + */ if (!strcmp(np->name, "escc")) return 1; /* ESCC has bogus resources >= 3 */ - if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b"))) + if (index >= 3 && !(strcmp(np->name, "ch-a") && + strcmp(np->name, "ch-b"))) return 1; /* Media bay has too many resources, keep only first one */ if (index > 0 && !strcmp(np->name, "media-bay")) @@ -285,6 +298,71 @@ static int macio_resource_quirks(struct device_node *np, struct resource *res, i } +static void macio_setup_interrupts(struct macio_dev *dev) +{ + struct device_node *np = dev->ofdev.node; + int i,j; + + /* For now, we use pre-parsed entries in the device-tree for + * interrupt routing and addresses, but we should change that + * to dynamically parsed entries and so get rid of most of the + * clutter in struct device_node + */ + for (i = j = 0; i < np->n_intrs; i++) { + struct resource *res = &dev->interrupt[j]; + + if (j >= MACIO_DEV_COUNT_IRQS) + break; + res->start = np->intrs[i].line; + res->flags = IORESOURCE_IO; + if (np->intrs[j].sense) + res->flags |= IORESOURCE_IRQ_LOWLEVEL; + else + res->flags |= IORESOURCE_IRQ_HIGHEDGE; + res->name = dev->ofdev.dev.bus_id; + if (macio_resource_quirks(np, res, i)) + memset(res, 0, sizeof(struct resource)); + else + j++; + } + dev->n_interrupts = j; +} + +static void macio_setup_resources(struct macio_dev *dev, + struct resource *parent_res) +{ + struct device_node *np = dev->ofdev.node; + u32 *addr; + u64 size; + int index; + + for (index = 0; (addr = of_get_address(np, index, &size)) != NULL; + index++) { + struct resource *res = &dev->resource[index]; + if (index >= MACIO_DEV_COUNT_RESOURCES) + break; + res->start = of_translate_address(np, addr); + res->end = res->start + (unsigned long)size - 1; + res->flags = IORESOURCE_MEM; + res->name = dev->ofdev.dev.bus_id; + + if (macio_resource_quirks(np, res, index)) { + memset(res, 0, sizeof(struct resource)); + continue; + } + /* Currently, we consider failure as harmless, this may + * change in the future, once I've found all the device + * tree bugs in older machines & worked around them + */ + if (insert_resource(parent_res, res)) { + printk(KERN_WARNING "Can't request resource " + "%d for MacIO device %s\n", + index, dev->ofdev.dev.bus_id); + } + } + dev->n_resources = index; +} + /** * macio_add_one_device - Add one device from OF node to the device tree * @chip: pointer to the macio_chip holding the device @@ -294,12 +372,13 @@ static int macio_resource_quirks(struct device_node *np, struct resource *res, i * When media-bay is changed to hotswap drivers, this function will * be exposed to the bay driver some way... */ -static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent, - struct device_node *np, struct macio_dev *in_bay, +static struct macio_dev * macio_add_one_device(struct macio_chip *chip, + struct device *parent, + struct device_node *np, + struct macio_dev *in_bay, struct resource *parent_res) { struct macio_dev *dev; - int i, j; u32 *reg; if (np == NULL) @@ -326,7 +405,8 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d /* MacIO itself has a different reg, we use it's PCI base */ if (np == chip->of_node) { - sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index, + sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", + chip->lbus.index, #ifdef CONFIG_PCI pci_resource_start(chip->lbus.pdev, 0), #else @@ -335,57 +415,16 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d MAX_NODE_NAME_SIZE, np->name); } else { reg = (u32 *)get_property(np, "reg", NULL); - sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index, + sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", + chip->lbus.index, reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name); } - /* For now, we use pre-parsed entries in the device-tree for - * interrupt routing and addresses, but we should change that - * to dynamically parsed entries and so get rid of most of the - * clutter in struct device_node - */ - for (i = j = 0; i < np->n_intrs; i++) { - struct resource *res = &dev->interrupt[j]; - - if (j >= MACIO_DEV_COUNT_IRQS) - break; - res->start = np->intrs[i].line; - res->flags = IORESOURCE_IO; - if (np->intrs[j].sense) - res->flags |= IORESOURCE_IRQ_LOWLEVEL; - else - res->flags |= IORESOURCE_IRQ_HIGHEDGE; - res->name = dev->ofdev.dev.bus_id; - if (macio_resource_quirks(np, res, i)) - memset(res, 0, sizeof(struct resource)); - else - j++; - } - dev->n_interrupts = j; - for (i = j = 0; i < np->n_addrs; i++) { - struct resource *res = &dev->resource[j]; - - if (j >= MACIO_DEV_COUNT_RESOURCES) - break; - res->start = np->addrs[i].address; - res->end = np->addrs[i].address + np->addrs[i].size - 1; - res->flags = IORESOURCE_MEM; - res->name = dev->ofdev.dev.bus_id; - if (macio_resource_quirks(np, res, i)) - memset(res, 0, sizeof(struct resource)); - else { - j++; - /* Currently, we consider failure as harmless, this may - * change in the future, once I've found all the device - * tree bugs in older machines & worked around them - */ - if (insert_resource(parent_res, res)) - printk(KERN_WARNING "Can't request resource %d for MacIO" - " device %s\n", i, dev->ofdev.dev.bus_id); - } - } - dev->n_resources = j; + /* Setup interrupts & resources */ + macio_setup_interrupts(dev); + macio_setup_resources(dev, parent_res); + /* Register with core */ if (of_device_register(&dev->ofdev) != 0) { printk(KERN_DEBUG"macio: device registration error for %s!\n", dev->ofdev.dev.bus_id); @@ -442,36 +481,42 @@ static void macio_pci_add_devices(struct macio_chip *chip) /* First scan 1st level */ for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { - if (!macio_skip_device(np)) { - of_node_get(np); - mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, root_res); - if (mdev == NULL) - of_node_put(np); - else if (strncmp(np->name, "media-bay", 9) == 0) - mbdev = mdev; - else if (strncmp(np->name, "escc", 4) == 0) - sdev = mdev; - } + if (macio_skip_device(np)) + continue; + of_node_get(np); + mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, + root_res); + if (mdev == NULL) + of_node_put(np); + else if (strncmp(np->name, "media-bay", 9) == 0) + mbdev = mdev; + else if (strncmp(np->name, "escc", 4) == 0) + sdev = mdev; } /* Add media bay devices if any */ if (mbdev) - for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;) - if (!macio_skip_device(np)) { - of_node_get(np); - if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev, - root_res) == NULL) - of_node_put(np); - } + for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) + != NULL;) { + if (macio_skip_device(np)) + continue; + of_node_get(np); + if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, + mbdev, root_res) == NULL) + of_node_put(np); + } + /* Add serial ports if any */ if (sdev) { - for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;) - if (!macio_skip_device(np)) { - of_node_get(np); - if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL, - root_res) == NULL) - of_node_put(np); - } + for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) + != NULL;) { + if (macio_skip_device(np)) + continue; + of_node_get(np); + if (macio_add_one_device(chip, &sdev->ofdev.dev, np, + NULL, root_res) == NULL) + of_node_put(np); + } } } @@ -519,7 +564,8 @@ void macio_unregister_driver(struct macio_driver *drv) * Returns 0 on success, or %EBUSY on error. A warning * message is also printed on failure. */ -int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name) +int macio_request_resource(struct macio_dev *dev, int resource_no, + const char *name) { if (macio_resource_len(dev, resource_no) == 0) return 0; @@ -606,20 +652,20 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi if (ent->vendor != PCI_VENDOR_ID_APPLE) return -ENODEV; - /* Note regarding refcounting: We assume pci_device_to_OF_node() is ported - * to new OF APIs and returns a node with refcount incremented. This isn't - * the case today, but on the other hand ppc32 doesn't do refcounting. This - * will have to be fixed when going to ppc64. --BenH. + /* Note regarding refcounting: We assume pci_device_to_OF_node() is + * ported to new OF APIs and returns a node with refcount incremented. */ np = pci_device_to_OF_node(pdev); if (np == NULL) return -ENODEV; - /* This assumption is wrong, fix that here for now until I fix the arch */ + /* The above assumption is wrong !!! + * fix that here for now until I fix the arch code + */ of_node_get(np); - /* We also assume that pmac_feature will have done a get() on nodes stored - * in the macio chips array + /* We also assume that pmac_feature will have done a get() on nodes + * stored in the macio chips array */ chip = macio_find(np, macio_unknown); of_node_put(np); @@ -639,9 +685,9 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi /* * HACK ALERT: The WallStreet PowerBook and some OHare based machines - * have 2 macio ASICs. I must probe the "main" one first or IDE ordering - * will be incorrect. So I put on "hold" the second one since it seem to - * appear first on PCI + * have 2 macio ASICs. I must probe the "main" one first or IDE + * ordering will be incorrect. So I put on "hold" the second one since + * it seem to appear first on PCI */ if (chip->type == macio_gatwick || chip->type == macio_ohareII) if (macio_chips[0].lbus.pdev == NULL) { -- cgit v1.2.3 From 60798c6a27b4e9827bdf641259409ada674c2868 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 16 Nov 2005 17:47:43 +1100 Subject: powerpc: cleanup iseries irq.c Remove two useless counters. DeStropify. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/irq.c | 260 ++++++++++++++++------------------- 1 file changed, 118 insertions(+), 142 deletions(-) diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index a58daa153686..cc6a266e7662 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -42,69 +42,50 @@ #include "irq.h" #include "call_pci.h" -static long Pci_Interrupt_Count; -static long Pci_Event_Count; - -enum XmPciLpEvent_Subtype { - XmPciLpEvent_BusCreated = 0, // PHB has been created - XmPciLpEvent_BusError = 1, // PHB has failed - XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus - XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed - XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered - XmPciLpEvent_BusRecovered = 12, // PHB has been recovered - XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing - XmPciLpEvent_BridgeError = 21, // Bridge Error - XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt +enum pci_event_type { + pe_bus_created = 0, /* PHB has been created */ + pe_bus_error = 1, /* PHB has failed */ + pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */ + pe_node_failed = 4, /* Multi-adapter bridge has failed */ + pe_node_recovered = 5, /* Multi-adapter bridge has recovered */ + pe_bus_recovered = 12, /* PHB has been recovered */ + pe_unquiese_bus = 18, /* Secondary bus unqiescing */ + pe_bridge_error = 21, /* Bridge Error */ + pe_slot_interrupt = 22 /* Slot interrupt */ }; -struct XmPciLpEvent_BusInterrupt { - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; -}; - -struct XmPciLpEvent_NodeInterrupt { - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; - HvAgentId deviceId; -}; - -struct XmPciLpEvent { - struct HvLpEvent hvLpEvent; - +struct pci_event { + struct HvLpEvent event; union { - u64 alignData; // Align on an 8-byte boundary - + u64 __align; /* Align on an 8-byte boundary */ struct { u32 fisr; - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; - HvAgentId deviceId; - } slotInterrupt; - - struct XmPciLpEvent_BusInterrupt busFailed; - struct XmPciLpEvent_BusInterrupt busRecovered; - struct XmPciLpEvent_BusInterrupt busCreated; - - struct XmPciLpEvent_NodeInterrupt nodeFailed; - struct XmPciLpEvent_NodeInterrupt nodeRecovered; - - } eventData; - + HvBusNumber bus_number; + HvSubBusNumber sub_bus_number; + HvAgentId dev_id; + } slot; + struct { + HvBusNumber bus_number; + HvSubBusNumber sub_bus_number; + } bus; + struct { + HvBusNumber bus_number; + HvSubBusNumber sub_bus_number; + HvAgentId dev_id; + } node; + } data; }; -static void intReceived(struct XmPciLpEvent *eventParm, - struct pt_regs *regsParm) +static void int_received(struct pci_event *event, struct pt_regs *regs) { int irq; #ifdef CONFIG_IRQSTACKS struct thread_info *curtp, *irqtp; #endif - ++Pci_Interrupt_Count; - - switch (eventParm->hvLpEvent.xSubtype) { - case XmPciLpEvent_SlotInterrupt: - irq = eventParm->hvLpEvent.xCorrelationToken; + switch (event->event.xSubtype) { + case pe_slot_interrupt: + irq = event->event.xCorrelationToken; /* Dispatch the interrupt handlers for this irq */ #ifdef CONFIG_IRQSTACKS /* Switch to the irq stack to handle this */ @@ -113,83 +94,78 @@ static void intReceived(struct XmPciLpEvent *eventParm, if (curtp != irqtp) { irqtp->task = curtp->task; irqtp->flags = 0; - call___do_IRQ(irq, regsParm, irqtp); + call___do_IRQ(irq, regs, irqtp); irqtp->task = NULL; if (irqtp->flags) set_bits(irqtp->flags, &curtp->flags); } else #endif - __do_IRQ(irq, regsParm); - HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, - eventParm->eventData.slotInterrupt.subBusNumber, - eventParm->eventData.slotInterrupt.deviceId); + __do_IRQ(irq, regs); + HvCallPci_eoi(event->data.slot.bus_number, + event->data.slot.sub_bus_number, + event->data.slot.dev_id); break; /* Ignore error recovery events for now */ - case XmPciLpEvent_BusCreated: - printk(KERN_INFO "intReceived: system bus %d created\n", - eventParm->eventData.busCreated.busNumber); + case pe_bus_created: + printk(KERN_INFO "int_received: system bus %d created\n", + event->data.bus.bus_number); break; - case XmPciLpEvent_BusError: - case XmPciLpEvent_BusFailed: - printk(KERN_INFO "intReceived: system bus %d failed\n", - eventParm->eventData.busFailed.busNumber); + case pe_bus_error: + case pe_bus_failed: + printk(KERN_INFO "int_received: system bus %d failed\n", + event->data.bus.bus_number); break; - case XmPciLpEvent_BusRecovered: - case XmPciLpEvent_UnQuiesceBus: - printk(KERN_INFO "intReceived: system bus %d recovered\n", - eventParm->eventData.busRecovered.busNumber); + case pe_bus_recovered: + case pe_unquiese_bus: + printk(KERN_INFO "int_received: system bus %d recovered\n", + event->data.bus.bus_number); break; - case XmPciLpEvent_NodeFailed: - case XmPciLpEvent_BridgeError: + case pe_node_failed: + case pe_bridge_error: printk(KERN_INFO - "intReceived: multi-adapter bridge %d/%d/%d failed\n", - eventParm->eventData.nodeFailed.busNumber, - eventParm->eventData.nodeFailed.subBusNumber, - eventParm->eventData.nodeFailed.deviceId); + "int_received: multi-adapter bridge %d/%d/%d failed\n", + event->data.node.bus_number, + event->data.node.sub_bus_number, + event->data.node.dev_id); break; - case XmPciLpEvent_NodeRecovered: + case pe_node_recovered: printk(KERN_INFO - "intReceived: multi-adapter bridge %d/%d/%d recovered\n", - eventParm->eventData.nodeRecovered.busNumber, - eventParm->eventData.nodeRecovered.subBusNumber, - eventParm->eventData.nodeRecovered.deviceId); + "int_received: multi-adapter bridge %d/%d/%d recovered\n", + event->data.node.bus_number, + event->data.node.sub_bus_number, + event->data.node.dev_id); break; default: printk(KERN_ERR - "intReceived: unrecognized event subtype 0x%x\n", - eventParm->hvLpEvent.xSubtype); + "int_received: unrecognized event subtype 0x%x\n", + event->event.xSubtype); break; } } -static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, - struct pt_regs *regsParm) +static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs) { -#ifdef CONFIG_PCI - ++Pci_Event_Count; - - if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { - switch (eventParm->xFlags.xFunction) { + if (event && (event->xType == HvLpEvent_Type_PciIo)) { + switch (event->xFlags.xFunction) { case HvLpEvent_Function_Int: - intReceived((struct XmPciLpEvent *)eventParm, regsParm); + int_received((struct pci_event *)event, regs); break; case HvLpEvent_Function_Ack: printk(KERN_ERR - "XmPciLpEvent_handler: unexpected ack received\n"); + "pci_event_handler: unexpected ack received\n"); break; default: printk(KERN_ERR - "XmPciLpEvent_handler: unexpected event function %d\n", - (int)eventParm->xFlags.xFunction); + "pci_event_handler: unexpected event function %d\n", + (int)event->xFlags.xFunction); break; } - } else if (eventParm) + } else if (event) printk(KERN_ERR - "XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n", - (int)eventParm->xType); + "pci_event_handler: Unrecognized PCI event type 0x%x\n", + (int)event->xType); else - printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n"); -#endif + printk(KERN_ERR "pci_event_handler: NULL event received\n"); } /* @@ -199,18 +175,18 @@ static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, void __init iSeries_init_IRQ(void) { /* Register PCI event handler and open an event path */ - int xRc; - - xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, - &XmPciLpEvent_handler); - if (xRc == 0) { - xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); - if (xRc != 0) - printk(KERN_ERR "iSeries_init_IRQ: open event path " - "failed with rc 0x%x\n", xRc); + int ret; + + ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, + &pci_event_handler); + if (ret == 0) { + ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); + if (ret != 0) + printk(KERN_ERR "iseries_init_IRQ: open event path " + "failed with rc 0x%x\n", ret); } else - printk(KERN_ERR "iSeries_init_IRQ: register handler " - "failed with rc 0x%x\n", xRc); + printk(KERN_ERR "iseries_init_IRQ: register handler " + "failed with rc 0x%x\n", ret); } #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) @@ -221,40 +197,40 @@ void __init iSeries_init_IRQ(void) * This will be called by device drivers (via enable_IRQ) * to enable INTA in the bridge interrupt status register. */ -static void iSeries_enable_IRQ(unsigned int irq) +static void iseries_enable_IRQ(unsigned int irq) { - u32 bus, deviceId, function, mask; - const u32 subBus = 0; + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; unsigned int rirq = virt_irq_to_real_map[irq]; /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; /* Unmask secondary INTA */ mask = 0x80000000; - HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); + HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask); } -/* This is called by iSeries_activate_IRQs */ -static unsigned int iSeries_startup_IRQ(unsigned int irq) +/* This is called by iseries_activate_IRQs */ +static unsigned int iseries_startup_IRQ(unsigned int irq) { - u32 bus, deviceId, function, mask; - const u32 subBus = 0; + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; unsigned int rirq = virt_irq_to_real_map[irq]; bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; /* Link the IRQ number to the bridge */ - HvCallXm_connectBusUnit(bus, subBus, deviceId, irq); + HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq); /* Unmask bridge interrupts in the FISR */ mask = 0x01010000 << function; - HvCallPci_unmaskFisr(bus, subBus, deviceId, mask); - iSeries_enable_IRQ(irq); + HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); + iseries_enable_IRQ(irq); return 0; } @@ -279,76 +255,76 @@ void __init iSeries_activate_IRQs() } /* this is not called anywhere currently */ -static void iSeries_shutdown_IRQ(unsigned int irq) +static void iseries_shutdown_IRQ(unsigned int irq) { - u32 bus, deviceId, function, mask; - const u32 subBus = 0; + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; unsigned int rirq = virt_irq_to_real_map[irq]; /* irq should be locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; /* Invalidate the IRQ number in the bridge */ - HvCallXm_connectBusUnit(bus, subBus, deviceId, 0); + HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0); /* Mask bridge interrupts in the FISR */ mask = 0x01010000 << function; - HvCallPci_maskFisr(bus, subBus, deviceId, mask); + HvCallPci_maskFisr(bus, sub_bus, dev_id, mask); } /* * This will be called by device drivers (via disable_IRQ) * to disable INTA in the bridge interrupt status register. */ -static void iSeries_disable_IRQ(unsigned int irq) +static void iseries_disable_IRQ(unsigned int irq) { - u32 bus, deviceId, function, mask; - const u32 subBus = 0; + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; unsigned int rirq = virt_irq_to_real_map[irq]; /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; /* Mask secondary INTA */ mask = 0x80000000; - HvCallPci_maskInterrupts(bus, subBus, deviceId, mask); + HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); } /* * This does nothing because there is not enough information * provided to do the EOI HvCall. This is done by XmPciLpEvent.c */ -static void iSeries_end_IRQ(unsigned int irq) +static void iseries_end_IRQ(unsigned int irq) { } static hw_irq_controller iSeries_IRQ_handler = { .typename = "iSeries irq controller", - .startup = iSeries_startup_IRQ, - .shutdown = iSeries_shutdown_IRQ, - .enable = iSeries_enable_IRQ, - .disable = iSeries_disable_IRQ, - .end = iSeries_end_IRQ + .startup = iseries_startup_IRQ, + .shutdown = iseries_shutdown_IRQ, + .enable = iseries_enable_IRQ, + .disable = iseries_disable_IRQ, + .end = iseries_end_IRQ }; /* * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot * It calculates the irq value for the slot. - * Note that subBusNumber is always 0 (at the moment at least). + * Note that sub_bus_number is always 0 (at the moment at least). */ -int __init iSeries_allocate_IRQ(HvBusNumber busNumber, - HvSubBusNumber subBusNumber, HvAgentId deviceId) +int __init iSeries_allocate_IRQ(HvBusNumber bus_number, + HvSubBusNumber sub_bus_number, HvAgentId dev_id) { int virtirq; unsigned int realirq; - u8 idsel = (deviceId >> 4); - u8 function = deviceId & 7; + u8 idsel = (dev_id >> 4); + u8 function = dev_id & 7; - realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function; + realirq = ((bus_number - 1) << 6) + ((idsel - 1) << 3) + function; virtirq = virt_irq_create_mapping(realirq); irq_desc[virtirq].handler = &iSeries_IRQ_handler; -- cgit v1.2.3 From 853f828cfd29d3d486d9f4b4df91d99ce509e3b5 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 16 Nov 2005 18:10:40 +1100 Subject: powerpc: use end_IRQ for iseries irqs Encode the sub bus number into the real irq number (even though it is always zero for now) so that we have enough information to do the EOI in iseries_end_IRQ. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/irq.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index cc6a266e7662..3bd576ecb288 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -101,9 +101,6 @@ static void int_received(struct pci_event *event, struct pt_regs *regs) } else #endif __do_IRQ(irq, regs); - HvCallPci_eoi(event->data.slot.bus_number, - event->data.slot.sub_bus_number, - event->data.slot.dev_id); break; /* Ignore error recovery events for now */ case pe_bus_created: @@ -189,6 +186,7 @@ void __init iSeries_init_IRQ(void) "failed with rc 0x%x\n", ret); } +#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) #define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) @@ -294,12 +292,12 @@ static void iseries_disable_IRQ(unsigned int irq) HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); } -/* - * This does nothing because there is not enough information - * provided to do the EOI HvCall. This is done by XmPciLpEvent.c - */ static void iseries_end_IRQ(unsigned int irq) { + unsigned int rirq = virt_irq_to_real_map[irq]; + + HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), + (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); } static hw_irq_controller iSeries_IRQ_handler = { @@ -314,17 +312,18 @@ static hw_irq_controller iSeries_IRQ_handler = { /* * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot * It calculates the irq value for the slot. - * Note that sub_bus_number is always 0 (at the moment at least). + * Note that sub_bus is always 0 (at the moment at least). */ -int __init iSeries_allocate_IRQ(HvBusNumber bus_number, - HvSubBusNumber sub_bus_number, HvAgentId dev_id) +int __init iSeries_allocate_IRQ(HvBusNumber bus, + HvSubBusNumber sub_bus, HvAgentId dev_id) { int virtirq; unsigned int realirq; u8 idsel = (dev_id >> 4); u8 function = dev_id & 7; - realirq = ((bus_number - 1) << 6) + ((idsel - 1) << 3) + function; + realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) + + function; virtirq = virt_irq_create_mapping(realirq); irq_desc[virtirq].handler = &iSeries_IRQ_handler; -- cgit v1.2.3 From e199500c6280aadf98c185db99fd24ab61ebe0c7 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 16 Nov 2005 18:53:29 +1100 Subject: powerpc: partly merge iseries do_IRQ Hide some of the iseries details in iSeries_get_irq. Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/irq.c | 71 ++++++++-------------------------- arch/powerpc/platforms/iseries/irq.c | 27 +++++++++++++ arch/powerpc/platforms/iseries/irq.h | 1 + arch/powerpc/platforms/iseries/setup.c | 10 ----- 4 files changed, 44 insertions(+), 65 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5a71ed9612fe..9540c454ff02 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -78,10 +78,6 @@ EXPORT_SYMBOL(__irq_offset_value); static int ppc_spurious_interrupts; -#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP) -extern void iSeries_smp_message_recv(struct pt_regs *); -#endif - #ifdef CONFIG_PPC32 #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) @@ -195,49 +191,6 @@ void fixup_irqs(cpumask_t map) } #endif -#ifdef CONFIG_PPC_ISERIES -void do_IRQ(struct pt_regs *regs) -{ - struct paca_struct *lpaca; - - irq_enter(); - -#ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 2KB free? */ - { - long sp; - - sp = __get_SP() & (THREAD_SIZE-1); - - if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { - printk("do_IRQ: stack overflow: %ld\n", - sp - sizeof(struct thread_info)); - dump_stack(); - } - } -#endif - - lpaca = get_paca(); -#ifdef CONFIG_SMP - if (lpaca->lppaca.int_dword.fields.ipi_cnt) { - lpaca->lppaca.int_dword.fields.ipi_cnt = 0; - iSeries_smp_message_recv(regs); - } -#endif /* CONFIG_SMP */ - if (hvlpevent_is_pending()) - process_hvlpevents(regs); - - irq_exit(); - - if (lpaca->lppaca.int_dword.fields.decr_int) { - lpaca->lppaca.int_dword.fields.decr_int = 0; - /* Signal a fake decrementer interrupt */ - timer_interrupt(regs); - } -} - -#else /* CONFIG_PPC_ISERIES */ - void do_IRQ(struct pt_regs *regs) { int irq; @@ -286,16 +239,24 @@ void do_IRQ(struct pt_regs *regs) } else #endif __do_IRQ(irq, regs); - } else -#ifdef CONFIG_PPC32 - if (irq != -2) -#endif - /* That's not SMP safe ... but who cares ? */ - ppc_spurious_interrupts++; + } else if (irq != -2) + /* That's not SMP safe ... but who cares ? */ + ppc_spurious_interrupts++; + irq_exit(); -} -#endif /* CONFIG_PPC_ISERIES */ +#ifdef CONFIG_PPC_ISERIES + { + struct paca_struct *lpaca = get_paca(); + + if (lpaca->lppaca.int_dword.fields.decr_int) { + lpaca->lppaca.int_dword.fields.decr_int = 0; + /* Signal a fake decrementer interrupt */ + timer_interrupt(regs); + } + } +#endif +} void __init init_IRQ(void) { diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 3bd576ecb288..5e92149b9b96 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -35,13 +35,19 @@ #include #include +#include #include #include #include +#include #include "irq.h" #include "call_pci.h" +#if defined(CONFIG_SMP) +extern void iSeries_smp_message_recv(struct pt_regs *); +#endif + enum pci_event_type { pe_bus_created = 0, /* PHB has been created */ pe_bus_error = 1, /* PHB has failed */ @@ -329,3 +335,24 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus, irq_desc[virtirq].handler = &iSeries_IRQ_handler; return virtirq; } + +/* + * Get the next pending IRQ. + */ +int iSeries_get_irq(struct pt_regs *regs) +{ + struct paca_struct *lpaca; + + lpaca = get_paca(); +#ifdef CONFIG_SMP + if (lpaca->lppaca.int_dword.fields.ipi_cnt) { + lpaca->lppaca.int_dword.fields.ipi_cnt = 0; + iSeries_smp_message_recv(regs); + } +#endif /* CONFIG_SMP */ + if (hvlpevent_is_pending()) + process_hvlpevents(regs); + + /* -2 means ignore this interrupt */ + return -2; +} diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h index 5f643f16ecc0..b9c801ba5a47 100644 --- a/arch/powerpc/platforms/iseries/irq.h +++ b/arch/powerpc/platforms/iseries/irq.h @@ -4,5 +4,6 @@ extern void iSeries_init_IRQ(void); extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId); extern void iSeries_activate_IRQs(void); +extern int iSeries_get_irq(struct pt_regs *); #endif /* _ISERIES_IRQ_H */ diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index da26639190db..ad5ef80500ce 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -569,16 +569,6 @@ static void iSeries_show_cpuinfo(struct seq_file *m) seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); } -/* - * Document me. - * and Implement me. - */ -static int iSeries_get_irq(struct pt_regs *regs) -{ - /* -2 means ignore this interrupt */ - return -2; -} - /* * Document me. */ -- cgit v1.2.3 From a50b56d24c59db33792b421af4016a9c958a906f Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 17 Nov 2005 16:14:17 +1100 Subject: powerpc: reduce include in irq.c Signed-off-by: Stephen Rothwell --- arch/powerpc/kernel/irq.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 9540c454ff02..5651032d8706 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -31,7 +31,6 @@ * to reduce code space and undefined function references. */ -#include #include #include #include @@ -44,18 +43,12 @@ #include #include #include -#include #include #include -#include -#include #include #include #include #include -#ifdef CONFIG_PPC64 -#include -#endif #include #include @@ -66,8 +59,7 @@ #include #include #include -#ifdef CONFIG_PPC64 -#include +#ifdef CONFIG_PPC_ISERIES #include #endif -- cgit v1.2.3 From 1d7a6b97f3c30087e307655116ff2ed492a37ad0 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 17 Nov 2005 18:04:37 +1100 Subject: powerpc: more iseries irq work Make get_IRQ return a pending irq number so it can be handled in the powerpc geeneric code. Signed-off-by: Stephen Rothwell --- arch/powerpc/platforms/iseries/irq.c | 53 ++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 5e92149b9b96..42e978e4897a 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -82,31 +82,29 @@ struct pci_event { } data; }; +static DEFINE_SPINLOCK(pending_irqs_lock); +static int num_pending_irqs; +static int pending_irqs[NR_IRQS]; + static void int_received(struct pci_event *event, struct pt_regs *regs) { int irq; -#ifdef CONFIG_IRQSTACKS - struct thread_info *curtp, *irqtp; -#endif switch (event->event.xSubtype) { case pe_slot_interrupt: irq = event->event.xCorrelationToken; - /* Dispatch the interrupt handlers for this irq */ -#ifdef CONFIG_IRQSTACKS - /* Switch to the irq stack to handle this */ - curtp = current_thread_info(); - irqtp = hardirq_ctx[smp_processor_id()]; - if (curtp != irqtp) { - irqtp->task = curtp->task; - irqtp->flags = 0; - call___do_IRQ(irq, regs, irqtp); - irqtp->task = NULL; - if (irqtp->flags) - set_bits(irqtp->flags, &curtp->flags); - } else -#endif - __do_IRQ(irq, regs); + if (irq < NR_IRQS) { + spin_lock(&pending_irqs_lock); + pending_irqs[irq]++; + num_pending_irqs++; + spin_unlock(&pending_irqs_lock); + } else { + printk(KERN_WARNING "int_received: bad irq number %d\n", + irq); + HvCallPci_eoi(event->data.slot.bus_number, + event->data.slot.sub_bus_number, + event->data.slot.dev_id); + } break; /* Ignore error recovery events for now */ case pe_bus_created: @@ -342,6 +340,8 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus, int iSeries_get_irq(struct pt_regs *regs) { struct paca_struct *lpaca; + /* -2 means ignore this interrupt */ + int irq = -2; lpaca = get_paca(); #ifdef CONFIG_SMP @@ -353,6 +353,19 @@ int iSeries_get_irq(struct pt_regs *regs) if (hvlpevent_is_pending()) process_hvlpevents(regs); - /* -2 means ignore this interrupt */ - return -2; + if (num_pending_irqs) { + spin_lock(&pending_irqs_lock); + for (irq = 0; irq < NR_IRQS; irq++) { + if (pending_irqs[irq]) { + pending_irqs[irq]--; + num_pending_irqs--; + break; + } + } + spin_unlock(&pending_irqs_lock); + if (irq >= NR_IRQS) + irq = -2; + } + + return irq; } -- cgit v1.2.3 From 8c441a57d789e59ba9cc7f652a028b4a7e5471f7 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 23 Nov 2005 12:43:15 -0600 Subject: [PATCH] powerpc: Add support for building uImages powerpc: Add support for building uImages Add support to build a kernel image bootable by u-boot. Most of the makefile foo is taken from arch/ppc/boot/images/Makefile Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/Makefile | 2 +- arch/powerpc/boot/Makefile | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index a13eb575f834..5f80e58e5cb3 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -151,7 +151,7 @@ CPPFLAGS_vmlinux.lds := -Upowerpc # All the instructions talk about "make bzImage". bzImage: zImage -BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm +BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage .PHONY: $(BOOT_TARGETS) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 9770f587af73..dfc7eacd9bdb 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -143,6 +143,36 @@ $(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote @cp -f $< $@ $(call if_changed,addnote) +#----------------------------------------------------------- +# build u-boot images +#----------------------------------------------------------- +quiet_cmd_mygzip = GZIP $@ +cmd_mygzip = gzip -f -9 < $< > $@.$$$$ && mv $@.$$$$ $@ + +quiet_cmd_objbin = OBJCOPY $@ + cmd_objbin = $(OBJCOPY) -O binary $< $@ + +quiet_cmd_uimage = UIMAGE $@ + cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \ + -C gzip -a 00000000 -e 00000000 -n 'Linux-$(KERNELRELEASE)' \ + -d $< $@ + +MKIMAGE := $(srctree)/scripts/mkuboot.sh +targets += uImage +extra-y += vmlinux.bin vmlinux.gz + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objbin) + +$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,mygzip) + +$(obj)/uImage: $(obj)/vmlinux.gz + $(Q)rm -f $@ + $(call if_changed,uimage) + @echo -n ' Image: $@ ' + @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi + install: $(CONFIGURE) $(BOOTIMAGE) sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)" -- cgit v1.2.3 From 706e6b2caf285d3eb056c2847b7c53ae823e8a87 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 23 Nov 2005 13:03:37 -0600 Subject: [PATCH] powerpc: Fix suboptimal uImage target Sam Ravnborg pointed out that calling if_changed was redundant in the rule since a prerequisite had to have changed for us to get there. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/boot/Makefile | 2 +- arch/ppc/boot/images/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index dfc7eacd9bdb..22726aefc8ea 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -169,7 +169,7 @@ $(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE $(obj)/uImage: $(obj)/vmlinux.gz $(Q)rm -f $@ - $(call if_changed,uimage) + $(call cmd,uimage) @echo -n ' Image: $@ ' @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile index 532e7ef1edb6..58415d5718e3 100644 --- a/arch/ppc/boot/images/Makefile +++ b/arch/ppc/boot/images/Makefile @@ -26,7 +26,7 @@ quiet_cmd_uimage = UIMAGE $@ targets += uImage $(obj)/uImage: $(obj)/vmlinux.gz $(Q)rm -f $@ - $(call if_changed,uimage) + $(call cmd,uimage) @echo -n ' Image: $@ ' @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi -- cgit v1.2.3 From 456752f7505ef8f580ffd157558e661da2767d99 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 24 Nov 2005 14:16:15 +1100 Subject: [PATCH] powerpc: Make hugepage mappings respect hint addresses Currently, the powerpc version of hugetlb_get_unmapped_area() entirely ignores the hint address. The only way to get a hugepage mapping at a specified address is with MAP_FIXED, in which case there's no way (short of parsing /proc/self/maps) for userspace to tell if it will clobber an existing mapping. This is inconvenient, so the patch below makes hugepage mappings use the given hint address if possible. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/mm/hugetlbpage.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 54131b877da3..f6fe3eaf87a3 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -549,6 +549,17 @@ fail: return addr; } +static int htlb_check_hinted_area(unsigned long addr, unsigned long len) +{ + struct vm_area_struct *vma; + + vma = find_vma(current->mm, addr); + if (!vma || ((addr + len) <= vma->vm_start)) + return 0; + + return -ENOMEM; +} + static unsigned long htlb_get_low_area(unsigned long len, u16 segmask) { unsigned long addr = 0; @@ -609,6 +620,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, { int lastshift; u16 areamask, curareas; + struct vm_area_struct *vma; if (HPAGE_SHIFT == 0) return -EINVAL; @@ -618,15 +630,28 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, if (!cpu_has_feature(CPU_FTR_16M_PAGE)) return -EINVAL; + /* Paranoia, caller should have dealt with this */ + BUG_ON((addr + len) < addr); + if (test_thread_flag(TIF_32BIT)) { + /* Paranoia, caller should have dealt with this */ + BUG_ON((addr + len) > 0x100000000UL); + curareas = current->mm->context.low_htlb_areas; - /* First see if we can do the mapping in the existing - * low areas */ + /* First see if we can use the hint address */ + if (addr && (htlb_check_hinted_area(addr, len) == 0)) { + areamask = LOW_ESID_MASK(addr, len); + if (open_low_hpage_areas(current->mm, areamask) == 0) + return addr; + } + + /* Next see if we can map in the existing low areas */ addr = htlb_get_low_area(len, curareas); if (addr != -ENOMEM) return addr; + /* Finally go looking for areas to open */ lastshift = 0; for (areamask = LOW_ESID_MASK(0x100000000UL-len, len); ! lastshift; areamask >>=1) { @@ -641,12 +666,22 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, } else { curareas = current->mm->context.high_htlb_areas; - /* First see if we can do the mapping in the existing - * high areas */ + /* First see if we can use the hint address */ + /* We discourage 64-bit processes from doing hugepage + * mappings below 4GB (must use MAP_FIXED) */ + if ((addr >= 0x100000000UL) + && (htlb_check_hinted_area(addr, len) == 0)) { + areamask = HTLB_AREA_MASK(addr, len); + if (open_high_hpage_areas(current->mm, areamask) == 0) + return addr; + } + + /* Next see if we can map in the existing high areas */ addr = htlb_get_high_area(len, curareas); if (addr != -ENOMEM) return addr; + /* Finally go looking for areas to open */ lastshift = 0; for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len); ! lastshift; areamask >>=1) { -- cgit v1.2.3 From 1888e7b51c0cb5db49911b59cb758ad2c7a530f2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 24 Nov 2005 16:34:45 +1100 Subject: [PATCH] powerpc: Remove ItLpRegSave area from the paca On iSeries, the paca contains, amongst other things an ItLpRegSave structure used by the hypervisor to save registers. The hypervisor locates this area through a pointer at the beginning of the paca, so the structure itself can be located elsewhere. This patch moves the reg_save area out into its own array. This reduces the amount of iSeries specific gunk which is visible to general powerpc code via paca.h Built and booted on POWER5 LPAR and iSeries RS64. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/paca.c | 10 +++------- arch/powerpc/platforms/iseries/lpardata.c | 7 +++++++ include/asm-powerpc/iseries/it_lp_reg_save.h | 2 ++ include/asm-powerpc/paca.h | 14 ++++++-------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index a7b68f911eb1..25420406c8c0 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -26,8 +27,7 @@ extern unsigned long __toc_start; /* The Paca is an array with one entry per processor. Each contains an * lppaca, which contains the information shared between the - * hypervisor and Linux. Each also contains an ItLpRegSave area which - * is used by the hypervisor to save registers. + * hypervisor and Linux. * On systems with hardware multi-threading, there are two threads * per processor. The Paca array must contain an entry for each thread. * The VPD Areas will give a max logical processors = 2 * max physical @@ -57,11 +57,7 @@ extern unsigned long __toc_start; #ifdef CONFIG_PPC_ISERIES #define PACA_INIT_ISERIES(number) \ .lppaca_ptr = &paca[number].lppaca, \ - .reg_save_ptr = &paca[number].reg_save, \ - .reg_save = { \ - .xDesc = 0xd397d9e2, /* "LpRS" */ \ - .xSize = sizeof(struct ItLpRegSave) \ - } + .reg_save_ptr = &iseries_reg_save[number], #define PACA_INIT(number) \ { \ diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c index bb8c91537f35..ea72385aaf0a 100644 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ b/arch/powerpc/platforms/iseries/lpardata.c @@ -225,3 +225,10 @@ struct ItVpdAreas itVpdAreas = { 0,0 } }; + +struct ItLpRegSave iseries_reg_save[] = { + [0 ... (NR_CPUS-1)] = { + .xDesc = 0xd397d9e2, /* "LpRS" */ + .xSize = sizeof(struct ItLpRegSave), + }, +}; diff --git a/include/asm-powerpc/iseries/it_lp_reg_save.h b/include/asm-powerpc/iseries/it_lp_reg_save.h index 288044b702de..81824e1bb767 100644 --- a/include/asm-powerpc/iseries/it_lp_reg_save.h +++ b/include/asm-powerpc/iseries/it_lp_reg_save.h @@ -81,4 +81,6 @@ struct ItLpRegSave { u8 xRsvd3[176]; // Reserved 350-3FF }; +extern struct ItLpRegSave iseries_reg_save[]; + #endif /* _ITLPREGSAVE_H */ diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index 92c765c35bd0..73693db546b3 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -18,7 +18,6 @@ #include #include #include -#include #include register struct paca_struct *local_paca asm("r13"); @@ -31,9 +30,9 @@ struct task_struct; * * This structure is not directly accessed by firmware or the service * processor except for the first two pointers that point to the - * lppaca area and the ItLpRegSave area for this CPU. Both the - * lppaca and ItLpRegSave objects are currently contained within the - * PACA but they do not need to be. + * lppaca area and the ItLpRegSave area for this CPU. The lppaca + * object is currently contained within the PACA but it doesn't need + * to be. */ struct paca_struct { /* @@ -48,7 +47,9 @@ struct paca_struct { * accessed by the firmware */ struct lppaca *lppaca_ptr; /* Pointer to LpPaca for PLIC */ - struct ItLpRegSave *reg_save_ptr; /* Pointer to LpRegSave for PLIC */ +#ifdef CONFIG_PPC_ISERIES + void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */ +#endif /* CONFIG_PPC_ISERIES */ /* * MAGIC: the spinlock functions in arch/ppc64/lib/locks.c @@ -110,9 +111,6 @@ struct paca_struct { * cross a page boundary. */ struct lppaca lppaca __attribute__((__aligned__(0x400))); -#ifdef CONFIG_PPC_ISERIES - struct ItLpRegSave reg_save; -#endif }; extern struct paca_struct paca[]; -- cgit v1.2.3 From 404849bbd2bfd62e05b36f4753f6e1af6050a824 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 24 Nov 2005 16:51:31 +1100 Subject: [PATCH] powerpc: Remove some unneeded fields from the paca This patch removes several unnecessary fields from the paca: - next_jiffy_update_tb was simply unused. Remove trivially. - The exdsi exception save area was not used. There were plans to use it, but they never seem to have gone anywhere. If they ever do, we can put it back. Remove from the paca, and from asm-offsets.c - The default_decr field was used from asm, but was only ever assigned the value of tb_ticks_per_jiffy. Just access tb_ticks_per_jiffy from asm directly instead. Built and booted on POWER5 LPAR and iSeries RS64. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 2 -- arch/powerpc/kernel/head_64.S | 3 ++- arch/powerpc/kernel/paca.c | 1 - arch/powerpc/kernel/smp.c | 4 ---- arch/powerpc/kernel/time.c | 4 ---- include/asm-powerpc/paca.h | 5 ----- 6 files changed, 2 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 3bf89d1a2de6..56399c5c931a 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -131,11 +131,9 @@ int main(void) DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); #endif /* CONFIG_HUGETLB_PAGE */ - DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); - DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 8a8bf79ef044..881e18e8ef59 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -726,7 +726,8 @@ iSeries_secondary_smp_loop: decrementer_iSeries_masked: li r11,1 stb r11,PACALPPACA+LPPACADECRINT(r13) - lwz r12,PACADEFAULTDECR(r13) + LOADBASE(r12,tb_ticks_per_jiffy) + lwz r12,OFF(tb_ticks_per_jiffy)(r13) mtspr SPRN_DEC,r12 /* fall through */ diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 25420406c8c0..999bdd816769 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -37,7 +37,6 @@ extern unsigned long __toc_start; #define PACA_INIT_COMMON(number, start, asrr, asrv) \ .lock_token = 0x8000, \ .paca_index = (number), /* Paca Index */ \ - .default_decr = 0x00ff0000, /* Initial Decr */ \ .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ .stab_real = (asrr), /* Real pointer to segment table */ \ .stab_addr = (asrv), /* Virt pointer to segment table */ \ diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 30374d2f88e5..a90df6bf0940 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -452,10 +452,6 @@ int __devinit __cpu_up(unsigned int cpu) if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)) return -EINVAL; -#ifdef CONFIG_PPC64 - paca[cpu].default_decr = tb_ticks_per_jiffy; -#endif - /* Make sure callin-map entry is 0 (can be leftover a CPU * hotplug */ diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index de8479769bb7..56f50e91bddb 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -699,10 +699,6 @@ void __init time_init(void) div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res); tb_to_xs = res.result_low; -#ifdef CONFIG_PPC64 - get_paca()->default_decr = tb_ticks_per_jiffy; -#endif - /* * Compute scale factor for sched_clock. * The calibrate_decr() function has set tb_ticks_per_sec, diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index 73693db546b3..59a41dbbf73c 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -60,7 +60,6 @@ struct paca_struct { u16 lock_token; /* Constant 0x8000, used in locks */ u16 paca_index; /* Logical processor number */ - u32 default_decr; /* Default decrementer value */ u64 kernel_toc; /* Kernel TOC address */ u64 stab_real; /* Absolute address of segment table */ u64 stab_addr; /* Virtual address of segment table */ @@ -91,14 +90,10 @@ struct paca_struct { struct task_struct *__current; /* Pointer to current */ u64 kstack; /* Saved Kernel stack addr */ u64 stab_rr; /* stab/slb round-robin counter */ - u64 next_jiffy_update_tb; /* TB value for next jiffy update */ u64 saved_r1; /* r1 save for RTAS calls */ u64 saved_msr; /* MSR saved here by enter_rtas */ u8 proc_enabled; /* irq soft-enable flag */ - /* not yet used */ - u64 exdsi[8]; /* used for linear mapping hash table misses */ - /* * iSeries structure which the hypervisor knows about - * this structure should not cross a page boundary. -- cgit v1.2.3 From 9177ae4378add0126104e2966aa6150258610d59 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 24 Nov 2005 17:34:03 +1100 Subject: [PATCH] powerpc: Fix g5 build with xmon My previous patches inadvertently broke building a G5 kernel with CONFIG_XMON enabled. This fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index ff78eeac10f2..a36527c98133 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -459,7 +459,7 @@ void __init pmac_pic_init(void) mpic_setup_cascade(irqctrler2->intrs[0].line, pmac_u3_cascade, mpic2); } -#ifdef CONFIG_XMON +#if defined(CONFIG_XMON) && defined(CONFIG_PPC32) { struct device_node* pswitch; int nmi_irq; @@ -471,7 +471,7 @@ void __init pmac_pic_init(void) setup_irq(nmi_irq, &xmon_action); } } -#endif /* CONFIG_XMON */ +#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */ return; } irqctrler = NULL; -- cgit v1.2.3 From 31df1678d7732b94178a6e457ed6666e4431212f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 24 Nov 2005 17:08:56 +0000 Subject: [PATCH] powerpc: serial port discovery: cope with broken firmware On Tue, 2005-11-22 at 15:49 +1100, Benjamin Herrenschmidt wrote: > This moves the discovery of legacy serial ports to a separate file, > makes it common to ppc32 and ppc64, and reworks it to use the new OF > address translators to get to the ports early. This new version can also > detect some PCI serial cards using legacy chips and will probably match > those discovered port with the default console choice. This makes it deal with the fact that the Pegasos firmware reports that its clock frequency is zero... Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 28ad50e424a9..7a685cae81ed 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -43,7 +43,10 @@ static int __init add_legacy_port(struct device_node *np, int want_index, /* get clock freq. if present */ clk = (u32 *)get_property(np, "clock-frequency", NULL); - clock = clk ? *clk : BASE_BAUD * 16; + if (clk && *clk) + clock = *clk; + else + clock = BASE_BAUD * 16; /* get default speed if present */ spd = (u32 *)get_property(np, "current-speed", NULL); -- cgit v1.2.3 From 9687c587596b54a77f08620595f5686ea35eed97 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 24 Nov 2005 12:51:40 +0000 Subject: [PATCH] Save NVGPRS in 32-bit signal frame Somehow this one slipped through the cracks; when we ended up in do_signal() on a 32-bit kernel but without having the caller-saved registers into the regs, we didn't set the TIF_SAVE_NVGPRS flag to ensure they got saved later. Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/signal_32.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index c9d02751127f..d3f0b6d452fb 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -219,6 +219,15 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka, static inline int save_general_regs(struct pt_regs *regs, struct mcontext __user *frame) { + if (!FULL_REGS(regs)) { + /* Zero out the unsaved GPRs to avoid information + leak, and set TIF_SAVE_NVGPRS to ensure that the + registers do actually get saved later. */ + memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); + current_thread_info()->nvgprs_frame = &frame->mc_gregs; + set_thread_flag(TIF_SAVE_NVGPRS); + } + return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); } -- cgit v1.2.3 From 623703f620453c798b6fa3eb79ad8ea27bfd302a Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 24 Nov 2005 17:36:20 +0000 Subject: [PATCH] Fix code that saves NVGPRS in 32-bit signal frame On Thu, 2005-11-24 at 12:51 +0000, David Woodhouse wrote: > Somehow this one slipped through the cracks; when we ended up in > do_signal() on a 32-bit kernel but without having the caller-saved > registers into the regs, we didn't set the TIF_SAVE_NVGPRS flag to > ensure they got saved later. Oh, and if we actually set the flag, then we fairly quickly find out that I was a bit overzealous in copying code from entry_64.S ... :) Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/entry_32.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 8fed9538f188..036b71d2adfc 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -368,7 +368,7 @@ save_user_nvgprs_cont: b 6b save_user_nvgprs: - ld r8,TI_SIGFRAME(r12) + lwz r8,TI_SIGFRAME(r12) .macro savewords start, end 1: stw \start,4*(\start)(r8) @@ -386,11 +386,11 @@ save_user_nvgprs: save_user_nvgprs_fault: li r3,11 /* SIGSEGV */ - ld r4,TI_TASK(r12) + lwz r4,TI_TASK(r12) bl force_sigsegv rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ - ld r9,TI_FLAGS(r12) + lwz r9,TI_FLAGS(r12) b save_user_nvgprs_cont #ifdef SHOW_SYSCALLS -- cgit v1.2.3 From fb64c2446b20bf0206a690e9e1df88b25ac421e6 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Thu, 24 Nov 2005 11:32:09 -0200 Subject: [PATCH] ppc32: m8xx watchdog update This updates m8xx_wdt as follows: 1) Remove now obsolete fpos check in the write() function. The driver is currently non functional due to this bug. 2) Use in/out macros for register access. 3) Allows m8xx_wdt to use a kernel timer instead of the builtin RTC/PIT for keep-alive trigger (which is responsible for servicing the watchdog until an userspace application takes over). For instance Cyclades PRxK boards (MPC 855T based) have a non-functional internal RTC/PIT unit. Behaviour for boards with RTC/PIT is unchaged. 4) The last change required moving the RTCSC register setting code to a weak function which can be overriden by board specific files. Otherwise the timer init code trashes the register making it impossible for m8xx_wdt to detect the situation. Signed-off-by: Marcelo Tosatti Signed-off-by: Paul Mackerras --- arch/ppc/syslib/m8xx_setup.c | 15 +++++-- arch/ppc/syslib/m8xx_wdt.c | 92 +++++++++++++++++++++++++++----------- arch/ppc/syslib/m8xx_wdt.h | 4 ++ drivers/char/watchdog/mpc8xx_wdt.c | 13 +++--- 4 files changed, 90 insertions(+), 34 deletions(-) diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index 1cc3abe6fa43..688616de3cde 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -135,6 +135,16 @@ static struct irqaction tbint_irqaction = { .name = "tbint", }; +/* per-board overridable init_internal_rtc() function. */ +void __init __attribute__ ((weak)) +init_internal_rtc(void) +{ + /* Disable the RTC one second and alarm interrupts. */ + out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE)); + /* Enable the RTC */ + out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE)); +} + /* The decrementer counts at the system (internal) clock frequency divided by * sixteen, or external oscillator divided by four. We force the processor * to use system clock divided by sixteen. @@ -183,10 +193,7 @@ void __init m8xx_calibrate_decr(void) out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck, KAPWR_KEY); out_be32(&((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk, KAPWR_KEY); - /* Disable the RTC one second and alarm interrupts. */ - out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) & ~(RTCSC_SIE | RTCSC_ALE)); - /* Enable the RTC */ - out_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc, in_be16(&((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc) | (RTCSC_RTF | RTCSC_RTE)); + init_internal_rtc(); /* Enabling the decrementer also enables the timebase interrupts * (or from the other point of view, to get decrementer interrupts diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c index a21632d37e5a..df6c9557b86a 100644 --- a/arch/ppc/syslib/m8xx_wdt.c +++ b/arch/ppc/syslib/m8xx_wdt.c @@ -19,6 +19,7 @@ #include static int wdt_timeout; +int m8xx_has_internal_rtc = 0; static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *); static struct irqaction m8xx_wdt_irqaction = { @@ -45,35 +46,15 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) return IRQ_HANDLED; } -void __init m8xx_wdt_handler_install(bd_t * binfo) +#define SYPCR_SWP 0x1 +#define SYPCR_SWE 0x4 + + +void __init m8xx_wdt_install_irq(volatile immap_t *imap, bd_t *binfo) { - volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; u32 pitc; - u32 sypcr; u32 pitrtclk; - sypcr = in_be32(&imap->im_siu_conf.sc_sypcr); - - if (!(sypcr & 0x04)) { - printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n", - sypcr); - return; - } - - m8xx_wdt_reset(); - - printk(KERN_NOTICE - "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n", - (sypcr >> 16), sypcr & 0x01); - - wdt_timeout = (sypcr >> 16) & 0xFFFF; - - if (!wdt_timeout) - wdt_timeout = 0xFFFF; - - if (sypcr & 0x01) - wdt_timeout *= 2048; - /* * Fire trigger if half of the wdt ticked down */ @@ -98,6 +79,67 @@ void __init m8xx_wdt_handler_install(bd_t * binfo) printk(KERN_NOTICE "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc); +} + +static void m8xx_wdt_timer_func(unsigned long data); + +static struct timer_list m8xx_wdt_timer = + TIMER_INITIALIZER(m8xx_wdt_timer_func, 0, 0); + +void m8xx_wdt_stop_timer(void) +{ + del_timer(&m8xx_wdt_timer); +} + +void m8xx_wdt_install_timer(void) +{ + m8xx_wdt_timer.expires = jiffies + (HZ/2); + add_timer(&m8xx_wdt_timer); +} + +static void m8xx_wdt_timer_func(unsigned long data) +{ + m8xx_wdt_reset(); + m8xx_wdt_install_timer(); +} + +void __init m8xx_wdt_handler_install(bd_t * binfo) +{ + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + u32 sypcr; + + sypcr = in_be32(&imap->im_siu_conf.sc_sypcr); + + if (!(sypcr & SYPCR_SWE)) { + printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n", + sypcr); + return; + } + + m8xx_wdt_reset(); + + printk(KERN_NOTICE + "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n", + (sypcr >> 16), sypcr & SYPCR_SWP); + + wdt_timeout = (sypcr >> 16) & 0xFFFF; + + if (!wdt_timeout) + wdt_timeout = 0xFFFF; + + if (sypcr & SYPCR_SWP) + wdt_timeout *= 2048; + + m8xx_has_internal_rtc = in_be16(&imap->im_sit.sit_rtcsc) & RTCSC_RTE; + + /* if the internal RTC is off use a kernel timer */ + if (!m8xx_has_internal_rtc) { + if (wdt_timeout < (binfo->bi_intfreq/HZ)) + printk(KERN_ERR "m8xx_wdt: timeout too short for ktimer!\n"); + m8xx_wdt_install_timer(); + } else + m8xx_wdt_install_irq(imap, binfo); + wdt_timeout /= binfo->bi_intfreq; } diff --git a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h index 0d81a9f8155f..e75835f0012b 100644 --- a/arch/ppc/syslib/m8xx_wdt.h +++ b/arch/ppc/syslib/m8xx_wdt.h @@ -9,8 +9,12 @@ #ifndef _PPC_SYSLIB_M8XX_WDT_H #define _PPC_SYSLIB_M8XX_WDT_H +extern int m8xx_has_internal_rtc; + extern void m8xx_wdt_handler_install(bd_t * binfo); extern int m8xx_wdt_get_timeout(void); extern void m8xx_wdt_reset(void); +extern void m8xx_wdt_install_timer(void); +extern void m8xx_wdt_stop_timer(void); #endif /* _PPC_SYSLIB_M8XX_WDT_H */ diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c index 56d62ba7c6ce..ac6fbace4724 100644 --- a/drivers/char/watchdog/mpc8xx_wdt.c +++ b/drivers/char/watchdog/mpc8xx_wdt.c @@ -27,7 +27,10 @@ static void mpc8xx_wdt_handler_disable(void) { volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; - imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE); + if (!m8xx_has_internal_rtc) + m8xx_wdt_stop_timer(); + else + out_be32(imap->im_sit.sit_piscr, in_be32(&imap->im_sit.sit_piscr) & ~(PISCR_PIE | PISCR_PTE)); printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n"); } @@ -36,7 +39,10 @@ static void mpc8xx_wdt_handler_enable(void) { volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; - imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE; + if (!m8xx_has_internal_rtc) + m8xx_wdt_install_timer(); + else + out_be32(&imap->im_sit.sit_piscr, in_be32(&imap->im_sit.sit_piscr) | PISCR_PIE | PISCR_PTE); printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n"); } @@ -68,9 +74,6 @@ static int mpc8xx_wdt_release(struct inode *inode, struct file *file) static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos) { - if (ppos != &file->f_pos) - return -ESPIPE; - if (len) m8xx_wdt_reset(); -- cgit v1.2.3 From 1c3eb629102bd4e327cc8b08fb9cdae4a985e841 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 26 Nov 2005 14:44:47 +0000 Subject: [PATCH] ppc: Make ARCH=ppc build again with new syscall path This makes ARCH=ppc build in your powerpc tree again, with the new syscall entry/exit path. Still doesn't actually boot on my Pegasos; the last thing I see is 'MMU:exit'. But at least it builds -- I'll look at why it doesn't boot later, so that I can see if the mv643xx_eth actually works with ARCH=ppc (it doesn't with ARCH=powerpc; two in every three packets I receive are offset by 4 bytes). Signed-off-by: David Woodhouse Signed-off-by: Paul Mackerras --- arch/ppc/kernel/asm-offsets.c | 2 +- arch/ppc/kernel/entry.S | 167 ++++++++++++++++++++++++------------------ arch/ppc/kernel/misc.S | 6 +- 3 files changed, 100 insertions(+), 75 deletions(-) diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index fe0e767fb94e..7964bf660e92 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c @@ -131,7 +131,7 @@ main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); - DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); + DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame)); DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index f044edbb454f..a48b950722a1 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -200,8 +200,6 @@ _GLOBAL(DoSyscall) bl do_show_syscall #endif /* SHOW_SYSCALLS */ rlwinm r10,r1,0,0,18 /* current_thread_info() */ - li r11,0 - stb r11,TI_SC_NOERR(r10) lwz r11,TI_FLAGS(r10) andi. r11,r11,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace @@ -222,25 +220,21 @@ ret_from_syscall: bl do_show_syscall_exit #endif mr r6,r3 - li r11,-_LAST_ERRNO - cmplw 0,r3,r11 rlwinm r12,r1,0,0,18 /* current_thread_info() */ - blt+ 30f - lbz r11,TI_SC_NOERR(r12) - cmpwi r11,0 - bne 30f - neg r3,r3 - lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) - /* disable interrupts so current_thread_info()->flags can't change */ -30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ + LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ SYNC MTMSRD(r10) lwz r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + li r8,-_LAST_ERRNO + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) bne- syscall_exit_work + cmplw 0,r3,r8 + blt+ syscall_exit_cont + lwz r11,_CCR(r1) /* Load CR */ + neg r3,r3 + oris r11,r11,0x1000 /* Set SO bit in CR */ + stw r11,_CCR(r1) syscall_exit_cont: #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) /* If the process has its own DBCR0 value, load it up. The single @@ -292,46 +286,113 @@ syscall_dotrace: b syscall_dotrace_cont syscall_exit_work: - stw r6,RESULT(r1) /* Save result */ + andi. r0,r9,_TIF_RESTOREALL + bne- 2f + cmplw 0,r3,r8 + blt+ 1f + andi. r0,r9,_TIF_NOERROR + bne- 1f + lwz r11,_CCR(r1) /* Load CR */ + neg r3,r3 + oris r11,r11,0x1000 /* Set SO bit in CR */ + stw r11,_CCR(r1) + +1: stw r6,RESULT(r1) /* Save result */ stw r3,GPR3(r1) /* Update return value */ - andi. r0,r9,_TIF_SYSCALL_T_OR_A - beq 5f - ori r10,r10,MSR_EE - SYNC - MTMSRD(r10) /* re-enable interrupts */ +2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) + beq 4f + + /* Clear per-syscall TIF flags if any are set, but _leave_ + _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that + yet. */ + + li r11,_TIF_PERSYSCALL_MASK + addi r12,r12,TI_FLAGS +3: lwarx r8,0,r12 + andc r8,r8,r11 +#ifdef CONFIG_IBM405_ERR77 + dcbt 0,r12 +#endif + stwcx. r8,0,r12 + bne- 3b + subi r12,r12,TI_FLAGS + +4: /* Anything which requires enabling interrupts? */ + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) + beq 7f + + /* Save NVGPRS if they're not saved already */ lwz r4,TRAP(r1) andi. r4,r4,1 - beq 4f + beq 5f SAVE_NVGPRS(r1) li r4,0xc00 stw r4,TRAP(r1) -4: + + /* Re-enable interrupts */ +5: ori r10,r10,MSR_EE + SYNC + MTMSRD(r10) + + andi. r0,r9,_TIF_SAVE_NVGPRS + bne save_user_nvgprs + +save_user_nvgprs_cont: + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + beq 7f + addi r3,r1,STACK_FRAME_OVERHEAD bl do_syscall_trace_leave REST_NVGPRS(r1) -2: - lwz r3,GPR3(r1) + +6: lwz r3,GPR3(r1) LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ SYNC MTMSRD(r10) /* disable interrupts again */ rlwinm r12,r1,0,0,18 /* current_thread_info() */ lwz r9,TI_FLAGS(r12) -5: +7: andi. r0,r9,_TIF_NEED_RESCHED - bne 1f + bne 8f lwz r5,_MSR(r1) andi. r5,r5,MSR_PR - beq syscall_exit_cont + beq ret_from_except andi. r0,r9,_TIF_SIGPENDING - beq syscall_exit_cont + beq ret_from_except b do_user_signal -1: +8: ori r10,r10,MSR_EE SYNC MTMSRD(r10) /* re-enable interrupts */ bl schedule - b 2b + b 6b + +save_user_nvgprs: + lwz r8,TI_SIGFRAME(r12) + +.macro savewords start, end + 1: stw \start,4*(\start)(r8) + .section __ex_table,"a" + .align 2 + .long 1b,save_user_nvgprs_fault + .previous + .if \end - \start + savewords "(\start+1)",\end + .endif +.endm + savewords 14,31 + b save_user_nvgprs_cont + + +save_user_nvgprs_fault: + li r3,11 /* SIGSEGV */ + lwz r4,TI_TASK(r12) + bl force_sigsegv + rlwinm r12,r1,0,0,18 /* current_thread_info() */ + lwz r9,TI_FLAGS(r12) + b save_user_nvgprs_cont + #ifdef SHOW_SYSCALLS do_show_syscall: #ifdef SHOW_SYSCALLS_TASK @@ -401,28 +462,10 @@ show_syscalls_task: #endif /* SHOW_SYSCALLS */ /* - * The sigsuspend and rt_sigsuspend system calls can call do_signal - * and thus put the process into the stopped state where we might - * want to examine its user state with ptrace. Therefore we need - * to save all the nonvolatile registers (r13 - r31) before calling - * the C code. + * The fork/clone functions need to copy the full register set into + * the child process. Therefore we need to save all the nonvolatile + * registers (r13 - r31) before calling the C code. */ - .globl ppc_sigsuspend -ppc_sigsuspend: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ - b sys_sigsuspend - - .globl ppc_rt_sigsuspend -ppc_rt_sigsuspend: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 - stw r0,TRAP(r1) - b sys_rt_sigsuspend - .globl ppc_fork ppc_fork: SAVE_NVGPRS(r1) @@ -447,14 +490,6 @@ ppc_clone: stw r0,TRAP(r1) /* register set saved */ b sys_clone - .globl ppc_swapcontext -ppc_swapcontext: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ - b sys_swapcontext - /* * Top-level page fault handling. * This is in assembler because if do_page_fault tells us that @@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) .long ret_from_except #endif - .globl sigreturn_exit -sigreturn_exit: - subi r1,r3,STACK_FRAME_OVERHEAD - rlwinm r12,r1,0,0,18 /* current_thread_info() */ - lwz r9,TI_FLAGS(r12) - andi. r0,r9,_TIF_SYSCALL_T_OR_A - beq+ ret_from_except_full - bl do_syscall_trace_leave - /* fall through */ - .globl ret_from_except_full ret_from_except_full: REST_NVGPRS(r1) @@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ /* Check current_thread_info()->flags */ rlwinm r9,r1,0,0,18 lwz r9,TI_FLAGS(r9) - andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED) + andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) bne do_work restore_user: diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 5e61124581d0..fb5658bba285 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -1197,7 +1197,7 @@ _GLOBAL(sys_call_table) .long sys_ssetmask .long sys_setreuid /* 70 */ .long sys_setregid - .long ppc_sigsuspend + .long sys_sigsuspend .long sys_sigpending .long sys_sethostname .long sys_setrlimit /* 75 */ @@ -1303,7 +1303,7 @@ _GLOBAL(sys_call_table) .long sys_rt_sigpending /* 175 */ .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo - .long ppc_rt_sigsuspend + .long sys_rt_sigsuspend .long sys_pread64 .long sys_pwrite64 /* 180 */ .long sys_chown @@ -1374,7 +1374,7 @@ _GLOBAL(sys_call_table) .long sys_clock_gettime .long sys_clock_getres .long sys_clock_nanosleep - .long ppc_swapcontext + .long sys_swapcontext .long sys_tgkill /* 250 */ .long sys_utimes .long sys_statfs64 -- cgit v1.2.3 From 8dacaedf04467e32c50148751a96150e73323cdc Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 29 Nov 2005 11:21:59 +1100 Subject: [PATCH] powerpc: More serial probe fixes (#2) This fixes the new serial probe code with some PCI MMIO UARTs, and fixes CHRP build with ARCH=powerpc. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 45 ++++++++++++++++++++++++++++--------- arch/powerpc/platforms/chrp/setup.c | 16 ------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 7a685cae81ed..83023bb59ad9 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -38,15 +38,13 @@ static int __init add_legacy_port(struct device_node *np, int want_index, int iotype, phys_addr_t base, phys_addr_t taddr, unsigned long irq) { - u32 *clk, *spd, clock; + u32 *clk, *spd, clock = BASE_BAUD * 16; int index; /* get clock freq. if present */ clk = (u32 *)get_property(np, "clock-frequency", NULL); if (clk && *clk) clock = *clk; - else - clock = BASE_BAUD * 16; /* get default speed if present */ spd = (u32 *)get_property(np, "current-speed", NULL); @@ -88,7 +86,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, if (iotype == UPIO_PORT) legacy_serial_ports[index].iobase = base; else - legacy_serial_ports[index].membase = (void __iomem *)base; + legacy_serial_ports[index].mapbase = base; legacy_serial_ports[index].iotype = iotype; legacy_serial_ports[index].uartclk = clock; legacy_serial_ports[index].irq = irq; @@ -148,17 +146,17 @@ static int __init add_legacy_pci_port(struct device_node *np, { phys_addr_t addr, base; u32 *addrp; - int iotype, index = -1; + int iotype, index = -1, lindex = 0; -#if 0 /* We only support ports that have a clock frequency properly * encoded in the device-tree (that is have an fcode). Anything * else can't be used that early and will be normally probed by - * the generic 8250_pci driver later on. + * the generic 8250_pci driver later on. The reason is that 8250 + * compatible UARTs on PCI need all sort of quirks (port offsets + * etc...) that this code doesn't know about */ if (get_property(np, "clock-frequency", NULL) == NULL) return -1; -#endif /* Get the PCI address. Assume BAR 0 */ addrp = of_get_pci_address(pci_dev, 0, NULL); @@ -183,7 +181,23 @@ static int __init add_legacy_pci_port(struct device_node *np, if (np != pci_dev) { u32 *reg = (u32 *)get_property(np, "reg", NULL); if (reg && (*reg < 4)) - index = legacy_serial_count + *reg; + index = lindex = *reg; + } + + /* Local index means it's the Nth port in the PCI chip. Unfortunately + * the offset to add here is device specific. We know about those + * EXAR ports and we default to the most common case. If your UART + * doesn't work for these settings, you'll have to add your own special + * cases here + */ + if (device_is_compatible(pci_dev, "pci13a8,152") || + device_is_compatible(pci_dev, "pci13a8,154") || + device_is_compatible(pci_dev, "pci13a8,158")) { + addr += 0x200 * lindex; + base += 0x200 * lindex; + } else { + addr += 8 * lindex; + base += 8 * lindex; } /* Add port, irq will be dealt with later. We passed a translated @@ -264,7 +278,6 @@ void __init find_legacy_serial_ports(void) DBG("legacy_serial_console = %d\n", legacy_serial_console); /* udbg is 64 bits only for now, that will change soon though ... */ -#ifdef CONFIG_PPC64 while (legacy_serial_console >= 0) { struct legacy_serial_info *info = &legacy_serial_infos[legacy_serial_console]; @@ -281,7 +294,6 @@ void __init find_legacy_serial_ports(void) udbg_init_uart(addr, info->speed, info->clock); break; } -#endif /* CONFIG_PPC64 */ DBG(" <- find_legacy_serial_port()\n"); } @@ -343,6 +355,15 @@ static void __init fixup_port_pio(int index, } } +static void __init fixup_port_mmio(int index, + struct device_node *np, + struct plat_serial8250_port *port) +{ + DBG("fixup_port_mmio(%d)\n", index); + + port->membase = ioremap(port->mapbase, 0x100); +} + /* * This is called as an arch initcall, hopefully before the PCI bus is * probed and/or the 8250 driver loaded since we need to register our @@ -377,6 +398,8 @@ static int __init serial_dev_init(void) fixup_port_irq(i, np, port); if (port->iotype == UPIO_PORT) fixup_port_pio(i, np, port); + if (port->iotype == UPIO_MEM) + fixup_port_mmio(i, np, port); } DBG("Registering platform serial ports\n"); diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index dda5f2c72c25..4ec8ba737e7d 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -58,7 +57,6 @@ #include "chrp.h" void rtas_indicator_progress(char *, unsigned short); -void btext_progress(char *, unsigned short); int _chrp_type; EXPORT_SYMBOL(_chrp_type); @@ -264,11 +262,6 @@ void __init chrp_setup_arch(void) ppc_md.set_rtc_time = rtas_set_rtc_time; } -#ifdef CONFIG_BOOTX_TEXT - if (ppc_md.progress == NULL && boot_text_mapped) - ppc_md.progress = btext_progress; -#endif - #ifdef CONFIG_BLK_DEV_INITRD /* this is fine for chrp */ initrd_below_start_ok = 1; @@ -522,12 +515,3 @@ void __init chrp_init(void) smp_ops = &chrp_smp_ops; #endif /* CONFIG_SMP */ } - -#ifdef CONFIG_BOOTX_TEXT -void -btext_progress(char *s, unsigned short hex) -{ - btext_drawstring(s); - btext_drawstring("\n"); -} -#endif /* CONFIG_BOOTX_TEXT */ -- cgit v1.2.3 From 74761bb53df1e2d603937b6abbd8437b03840e38 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Mon, 28 Nov 2005 16:33:24 -0800 Subject: [PATCH] powerpc: Minor numa memory code cleanup I started to add missing of_node_put() calls to the routines that determine the number of cells for memory. Decided to combine the routines instead of making separate node lookups. Changed variable names to help with some confusion as to meaning. Signed-off-by: Mike Kravetz Signed-off-by: Paul Mackerras --- arch/powerpc/mm/numa.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index ba7a3055a9fc..30b5d6a1d838 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -254,29 +254,17 @@ static int __init find_min_common_depth(void) return depth; } -static int __init get_mem_addr_cells(void) +static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) { struct device_node *memory = NULL; - int rc; memory = of_find_node_by_type(memory, "memory"); - if (!memory) - return 0; /* it won't matter */ - - rc = prom_n_addr_cells(memory); - return rc; -} - -static int __init get_mem_size_cells(void) -{ - struct device_node *memory = NULL; - int rc; - - memory = of_find_node_by_type(memory, "memory"); - if (!memory) - return 0; /* it won't matter */ - rc = prom_n_size_cells(memory); - return rc; + if (memory) { + *n_addr_cells = prom_n_addr_cells(memory); + *n_size_cells = prom_n_size_cells(memory); + of_node_put(memory); + } + /* if (!memory) we are in trouble, let other code error out */ } static unsigned long __init read_n_cells(int n, unsigned int **buf) @@ -386,7 +374,7 @@ static int __init parse_numa_properties(void) { struct device_node *cpu = NULL; struct device_node *memory = NULL; - int addr_cells, size_cells; + int n_addr_cells, n_size_cells; int max_domain; unsigned long i; @@ -425,8 +413,7 @@ static int __init parse_numa_properties(void) } } - addr_cells = get_mem_addr_cells(); - size_cells = get_mem_size_cells(); + get_n_mem_cells(&n_addr_cells, &n_size_cells); memory = NULL; while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { unsigned long start; @@ -443,8 +430,8 @@ static int __init parse_numa_properties(void) ranges = memory->n_addrs; new_range: /* these are order-sensitive, and modify the buffer pointer */ - start = read_n_cells(addr_cells, &memcell_buf); - size = read_n_cells(size_cells, &memcell_buf); + start = read_n_cells(n_addr_cells, &memcell_buf); + size = read_n_cells(n_size_cells, &memcell_buf); numa_domain = of_node_numa_domain(memory); -- cgit v1.2.3 From e2a296eeaa344450196e910a136ab14119d7ae48 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 3 Nov 2005 18:51:31 -0600 Subject: [PATCH] powerpc: PCI hotplug common code elimination 20-rpaphp-eeh-cleanup.patch This patch move some code from the rpaphp directory, to the powerpc directory, where it should have been all along (Among other things, I need it in the powerpc directory for the PCI error recovery.) Please note that patch affects TWO maintainers: Paul, after applying the powerpc part, please ask that GregKH appli the PCI part. It is safe to have the powerpc part go in first. It would be bad to have the PCI part go in first. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 26 ++++++++++++++++++++++++++ include/asm-powerpc/eeh.h | 10 ++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index c8d2a40dc5b4..7fbfd16d72b7 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1093,6 +1093,15 @@ void eeh_add_device_early(struct device_node *dn) } EXPORT_SYMBOL_GPL(eeh_add_device_early); +void eeh_add_device_tree_early(struct device_node *dn) +{ + struct device_node *sib; + for (sib = dn->child; sib; sib = sib->sibling) + eeh_add_device_tree_early(sib); + eeh_add_device_early(dn); +} +EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); + /** * eeh_add_device_late - perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH @@ -1147,6 +1156,23 @@ void eeh_remove_device(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(eeh_remove_device); +void eeh_remove_bus_device(struct pci_dev *dev) +{ + eeh_remove_device(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + struct pci_bus *bus = dev->subordinate; + struct list_head *ln; + if (!bus) + return; + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { + struct pci_dev *pdev = pci_dev_b(ln); + if (pdev) + eeh_remove_bus_device(pdev); + } + } +} +EXPORT_SYMBOL_GPL(eeh_remove_bus_device); + static int proc_eeh_show(struct seq_file *m, void *v) { unsigned int cpu; diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h index f8633aafe4ba..e4ca35ad3338 100644 --- a/include/asm-powerpc/eeh.h +++ b/include/asm-powerpc/eeh.h @@ -57,6 +57,7 @@ void __init pci_addr_cache_build(void); * to finish the eeh setup for this device. */ void eeh_add_device_early(struct device_node *); +void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_late(struct pci_dev *); /** @@ -71,6 +72,15 @@ void eeh_add_device_late(struct pci_dev *); */ void eeh_remove_device(struct pci_dev *); +/** + * eeh_remove_device_recursive - undo EEH for device & children. + * @dev: pci device to be removed + * + * As above, this removes the device; it also removes child + * pci devices as well. + */ +void eeh_remove_bus_device(struct pci_dev *); + /** * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. * -- cgit v1.2.3 From facf07870b6103b8f9b6c872e3cb1032c5185d0b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 3 Nov 2005 18:52:01 -0600 Subject: [PATCH] powerpc: make pcibios_claim_one_bus available to other code 22-rpaphp-eliminate-dupe-code.patch (parts) The RPAPHP code contains two routines that appear to be gratuitous copies of very similar pci code. In particular, rpaphp_claim_resource ~~ pci_claim_resource rpadlpar_claim_one_bus == pcibios_claim_one_bus This makes pcibios_claim_one_bus from arch/powerpc/kernel/pci_64.c available to the RPAPHP code. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_64.c | 2 +- include/asm-powerpc/pci.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 9a80cdf9efeb..5f241fcd88e8 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -251,7 +251,7 @@ void pcibios_free_controller(struct pci_controller *phb) kfree(phb); } -static void __init pcibios_claim_one_bus(struct pci_bus *b) +void __devinit pcibios_claim_one_bus(struct pci_bus *b) { struct pci_dev *dev; struct pci_bus *child_bus; diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h index d5934a076bd0..5d2c9e6c4be2 100644 --- a/include/asm-powerpc/pci.h +++ b/include/asm-powerpc/pci.h @@ -216,6 +216,8 @@ extern int remap_bus_range(struct pci_bus *bus); extern void pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus); +extern void pcibios_claim_one_bus(struct pci_bus *b); + extern struct pci_controller *init_phb_dynamic(struct device_node *dn); extern struct pci_dev *of_create_pci_dev(struct device_node *node, -- cgit v1.2.3 From 2bf6a8fa21570f37fd1789610da30f70a05ac5e3 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 3 Nov 2005 18:52:16 -0600 Subject: [PATCH] powerpc: migrate common PCI hotplug code 23-rpaphp-migrate.patch (parts) This patch moves some pci device add & remove code from the PCI hotplug directory to the arch/powerpc/kernel directory, and cleans it up a tad. The primary reason for this is that the code performs some fairly generic operations that are shared with the PCI error recovery code (living in the arch/powerpc/kernel directory). Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/pci_dlpar.c | 174 +++++++++++++++++++++++++++++ include/asm-powerpc/pci-bridge.h | 9 ++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/pseries/pci_dlpar.c diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 06d5ef501218..6accdd155505 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -1,5 +1,5 @@ obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ - setup.o iommu.o ras.o rtasd.o + setup.o iommu.o ras.o rtasd.o pci_dlpar.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_XICS) += xics.o diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c new file mode 100644 index 000000000000..283377a536bd --- /dev/null +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -0,0 +1,174 @@ +/* + * PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code + * for RPA-compliant PPC64 platform. + * Copyright (C) 2003 Linda Xie + * Copyright (C) 2005 International Business Machines + * + * Updates, 2005, John Rose + * Updates, 2005, Linas Vepstas + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +static struct pci_bus * +find_bus_among_children(struct pci_bus *bus, + struct device_node *dn) +{ + struct pci_bus *child = NULL; + struct list_head *tmp; + struct device_node *busdn; + + busdn = pci_bus_to_OF_node(bus); + if (busdn == dn) + return bus; + + list_for_each(tmp, &bus->children) { + child = find_bus_among_children(pci_bus_b(tmp), dn); + if (child) + break; + }; + return child; +} + +struct pci_bus * +pcibios_find_pci_bus(struct device_node *dn) +{ + struct pci_dn *pdn = dn->data; + + if (!pdn || !pdn->phb || !pdn->phb->bus) + return NULL; + + return find_bus_among_children(pdn->phb->bus, dn); +} + +/** + * pcibios_remove_pci_devices - remove all devices under this bus + * + * Remove all of the PCI devices under this bus both from the + * linux pci device tree, and from the powerpc EEH address cache. + */ +void +pcibios_remove_pci_devices(struct pci_bus *bus) +{ + struct pci_dev *dev, *tmp; + + list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { + eeh_remove_bus_device(dev); + pci_remove_bus_device(dev); + } +} + +/* Must be called before pci_bus_add_devices */ +static void +pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + /* + * Skip already-present devices (which are on the + * global device list.) + */ + if (list_empty(&dev->global_list)) { + int i; + + /* Need to setup IOMMU tables */ + ppc_md.iommu_dev_setup(dev); + + if(fix_bus) + pcibios_fixup_device_resources(dev, bus); + pci_read_irq_line(dev); + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + + if (r->parent || !r->start || !r->flags) + continue; + pci_claim_resource(dev, i); + } + } + } +} + +static int +pcibios_pci_config_bridge(struct pci_dev *dev) +{ + u8 sec_busno; + struct pci_bus *child_bus; + struct pci_dev *child_dev; + + /* Get busno of downstream bus */ + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); + + /* Add to children of PCI bridge dev->bus */ + child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); + if (!child_bus) { + printk (KERN_ERR "%s: could not add second bus\n", __FUNCTION__); + return -EIO; + } + sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); + + pci_scan_child_bus(child_bus); + + list_for_each_entry(child_dev, &child_bus->devices, bus_list) { + eeh_add_device_late(child_dev); + } + + /* Fixup new pci devices without touching bus struct */ + pcibios_fixup_new_pci_devices(child_bus, 0); + + /* Make the discovered devices available */ + pci_bus_add_devices(child_bus); + return 0; +} + +/** + * pcibios_add_pci_devices - adds new pci devices to bus + * + * This routine will find and fixup new pci devices under + * the indicated bus. This routine presumes that there + * might already be some devices under this bridge, so + * it carefully tries to add only new devices. (And that + * is how this routine differs from other, similar pcibios + * routines.) + */ +void +pcibios_add_pci_devices(struct pci_bus * bus) +{ + int slotno, num; + struct pci_dev *dev; + struct device_node *dn = pci_bus_to_OF_node(bus); + + eeh_add_device_tree_early(dn); + + /* pci_scan_slot should find all children */ + slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); + num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); + if (num) { + pcibios_fixup_new_pci_devices(bus, 1); + pci_bus_add_devices(bus); + } + + list_for_each_entry(dev, &bus->devices, bus_list) { + eeh_add_device_late (dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + pcibios_pci_config_bridge(dev); + } +} diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 89e73fcd58bb..00d21513d009 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -125,9 +125,18 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus) return bus->sysdata; /* Must be root bus (PHB) */ } +/** Find the bus corresponding to the indicated device node */ +struct pci_bus * pcibios_find_pci_bus(struct device_node *dn); + extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, struct device_node *dev, int primary); +/** Remove all of the PCI devices under this bus */ +void pcibios_remove_pci_devices(struct pci_bus *bus); + +/** Discover new pci devices under this bus, and add them */ +void pcibios_add_pci_devices(struct pci_bus * bus); + extern int pcibios_remove_root_bus(struct pci_controller *phb); extern void phbs_remap_io(void); -- cgit v1.2.3 From 52020d2bda9fe447bb50674a2e39e4064b6a10b5 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 30 Nov 2005 17:34:50 +0000 Subject: [PATCH] powerpc: powermac adb fix dependency on btext_drawchar udbg_adb_init() has become dependent on btext_drawchar, even when BOOTX_TEXT support is not selected. This leads to the error below. Make the check dependant on BOOTX_TEXT. LD .tmp_vmlinux1 arch/powerpc/platforms/built-in.o(.toc1+0xa40): undefined reference to `btext_drawchar' Signed-off-by: Andy Whitcroft Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/udbg_adb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c index e51de55b2d6e..d1c40e27e37d 100644 --- a/arch/powerpc/platforms/powermac/udbg_adb.c +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -171,9 +171,12 @@ int udbg_adb_init(int force_btext) udbg_adb_old_getc_poll = udbg_getc_poll; /* Check if our early init was already called */ - if (udbg_adb_old_putc == udbg_adb_putc || - udbg_adb_old_putc == btext_drawchar) + if (udbg_adb_old_putc == udbg_adb_putc) udbg_adb_old_putc = NULL; +#ifdef CONFIG_BOOTX_TEXT + if (udbg_adb_old_putc == btext_drawchar) + udbg_adb_old_putc = NULL; +#endif /* Set ours as output */ udbg_putc = udbg_adb_putc; -- cgit v1.2.3 From 54b9a9aedc990dd2aefc45ab16d84f245cb7d8d0 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 30 Nov 2005 17:35:01 +0000 Subject: [PATCH] powerpc: powermac adb fix udbg_adb_use_btext warning When compiling without BOOTX_TEXT the following warning is emitted. Fix up the definition to only be made when required. CC arch/powerpc/platforms/powermac/udbg_adb.o .../arch/powerpc/platforms/powermac/udbg_adb.c:41: warning: `udbg_adb_use_btext' defined but not used Signed-off-by: Andy Whitcroft Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/udbg_adb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c index d1c40e27e37d..3d5ed23bf0e0 100644 --- a/arch/powerpc/platforms/powermac/udbg_adb.c +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -38,8 +38,6 @@ static enum { input_adb_cuda, } input_type = input_adb_none; -static int udbg_adb_use_btext; - int xmon_wants_key, xmon_adb_keycode; static inline void udbg_adb_poll(void) @@ -55,6 +53,8 @@ static inline void udbg_adb_poll(void) } #ifdef CONFIG_BOOTX_TEXT + +static int udbg_adb_use_btext; static int xmon_adb_shiftstate; static unsigned char xmon_keytab[128] = -- cgit v1.2.3 From bb6b9b28d6847bc71f910e2e82c9040ff4b97ec0 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 30 Nov 2005 16:54:12 +1100 Subject: [PATCH] powerpc: udbg updates The udbg low level io layer has an issue with udbg_getc() returning a char (unsigned on ppc) instead of an int, thus the -1 if you had no available input device could end up turned into 0xff, filling your display with bogus characters. This fixes it, along with adding a little blob to xmon to do a delay before exiting when getting an EOF and fixing the detection of ADB keyboards in udbg_adb.c Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_parse.c | 2 +- arch/powerpc/kernel/udbg.c | 11 +++++++---- arch/powerpc/kernel/udbg_16550.c | 4 ++-- arch/powerpc/platforms/powermac/udbg_adb.c | 8 ++++---- arch/powerpc/platforms/powermac/udbg_scc.c | 4 ++-- arch/powerpc/platforms/pseries/lpar.c | 4 ++-- arch/powerpc/xmon/xmon.c | 4 +++- drivers/macintosh/via-pmu.c | 4 ++-- include/asm-powerpc/udbg.h | 2 +- 9 files changed, 24 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 9c2a5be7a56a..23c85af53d47 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -276,7 +276,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, finish: of_dump_addr("OF: parent translation for:", addr, pna); - DBG("OF: with offset: %lx\n", offset); + DBG("OF: with offset: "PRu64"\n", offset); /* Translate it into parent bus space */ return pbus->translate(addr, offset, pna); diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index cc2df5e61bb0..a058285a70e7 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -17,7 +17,7 @@ #include void (*udbg_putc)(char c); -char (*udbg_getc)(void); +int (*udbg_getc)(void); int (*udbg_getc_poll)(void); /* udbg library, used by xmon et al */ @@ -57,8 +57,8 @@ int udbg_write(const char *s, int n) int udbg_read(char *buf, int buflen) { - char c, *p = buf; - int i; + char *p = buf; + int i, c; if (!udbg_getc) return 0; @@ -66,8 +66,11 @@ int udbg_read(char *buf, int buflen) for (i = 0; i < buflen; ++i) { do { c = udbg_getc(); + if (c == -1 && i == 0) + return -1; + } while (c == 0x11 || c == 0x13); - if (c == 0) + if (c == 0 || c == -1) break; *p++ = c; } diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 28a58da5592c..e58c048a7b19 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -69,14 +69,14 @@ static int udbg_550_getc_poll(void) return -1; } -static char udbg_550_getc(void) +static int udbg_550_getc(void) { if (udbg_comport) { while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) /* wait for char */; return in_8(&udbg_comport->rbr); } - return 0; + return -1; } void udbg_init_uart(void __iomem *comport, unsigned int speed, diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c index 3d5ed23bf0e0..06c8265c2baf 100644 --- a/arch/powerpc/platforms/powermac/udbg_adb.c +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -29,7 +29,7 @@ */ static void (*udbg_adb_old_putc)(char c); -static char (*udbg_adb_old_getc)(void); +static int (*udbg_adb_old_getc)(void); static int (*udbg_adb_old_getc_poll)(void); static enum { @@ -73,7 +73,7 @@ static unsigned char xmon_shift_keytab[128] = "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ -static char udbg_adb_local_getc(void) +static int udbg_adb_local_getc(void) { int k, t, on; @@ -116,7 +116,7 @@ static char udbg_adb_local_getc(void) } #endif /* CONFIG_BOOTX_TEXT */ -static char udbg_adb_getc(void) +static int udbg_adb_getc(void) { #ifdef CONFIG_BOOTX_TEXT if (udbg_adb_use_btext && input_type != input_adb_none) @@ -195,7 +195,7 @@ int udbg_adb_init(int force_btext) */ for (np = NULL; (np = of_find_node_by_name(np, "keyboard")) != NULL;) { struct device_node *parent = of_get_parent(np); - int found = (parent && !strcmp(parent->type, "adb") == 0); + int found = (parent && strcmp(parent->type, "adb") == 0); of_node_put(parent); if (found) break; diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c index df6dec49c4c7..e87d53acfb61 100644 --- a/arch/powerpc/platforms/powermac/udbg_scc.c +++ b/arch/powerpc/platforms/powermac/udbg_scc.c @@ -47,14 +47,14 @@ static int udbg_scc_getc_poll(void) return -1; } -static char udbg_scc_getc(void) +static int udbg_scc_getc(void) { if (sccc) { while ((in_8(sccc) & SCC_RXRDY) == 0) ; return in_8(sccd); } - return 0; + return -1; } static unsigned char scc_inittab[] = { diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 615ffb961059..1fe445ab78a6 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -112,7 +112,7 @@ static int udbg_hvsi_getc_poll(void) return ch; } -static char udbg_hvsi_getc(void) +static int udbg_hvsi_getc(void) { int ch; for (;;) { @@ -173,7 +173,7 @@ static int udbg_getc_pollLP(void) return ch; } -static char udbg_getcLP(void) +static int udbg_getcLP(void) { int ch; for (;;) { diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index c45a6ad5f3b7..465b75c5647e 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -450,7 +450,6 @@ int xmon_core(struct pt_regs *regs, int fromipi) leave: cpu_clear(cpu, cpus_in_xmon); xmon_fault_jmp[cpu] = NULL; - #else /* UP is simple... */ if (in_xmon) { @@ -805,7 +804,10 @@ cmds(struct pt_regs *excp) break; case 'x': case 'X': + return cmd; case EOF: + printf(" \n"); + mdelay(2000); return cmd; case '?': printf(help_string); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 13881f199607..d6dabee55f2f 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -313,7 +313,7 @@ int __init find_via_pmu(void) goto fail; } taddr = of_translate_address(vias, reg); - if (taddr == 0) { + if (taddr == OF_BAD_ADDR) { printk(KERN_ERR "via-pmu: Can't translate address !\n"); goto fail; } @@ -376,7 +376,7 @@ int __init find_via_pmu(void) return 0; } - printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n", + printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n", PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version); sys_ctrler = SYS_CTRLER_PMU; diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index 8d6b44c8f35d..58cdc883e38c 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -14,7 +14,7 @@ #include extern void (*udbg_putc)(char c); -extern char (*udbg_getc)(void); +extern int (*udbg_getc)(void); extern int (*udbg_getc_poll)(void); extern void udbg_puts(const char *s); -- cgit v1.2.3 From d2dd482bc17c3bc240045f80a7c4b4d5cea5e29c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 30 Nov 2005 16:57:28 +1100 Subject: [PATCH] powerpc: Update OF address parsers This updates the OF address parsers to return the IO flags indicating the type of address obtained. It also adds a PCI call for converting physical addresses that hit IO space into into IO tokens, and add routines that return the translated addresses into struct resource Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 5 +- arch/powerpc/kernel/pci_64.c | 14 +++ arch/powerpc/kernel/prom_parse.c | 165 ++++++++++++++++++++++++++---- arch/powerpc/platforms/powermac/feature.c | 2 +- arch/ppc/kernel/pci.c | 15 +++ drivers/macintosh/macio_asic.c | 12 +-- include/asm-powerpc/pci-bridge.h | 9 ++ include/asm-powerpc/prom.h | 28 ++++- include/asm-ppc/pci-bridge.h | 9 ++ include/asm-ppc/prom.h | 28 ++++- 10 files changed, 251 insertions(+), 36 deletions(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 83023bb59ad9..d179ec502292 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -146,6 +146,7 @@ static int __init add_legacy_pci_port(struct device_node *np, { phys_addr_t addr, base; u32 *addrp; + unsigned int flags; int iotype, index = -1, lindex = 0; /* We only support ports that have a clock frequency properly @@ -159,12 +160,12 @@ static int __init add_legacy_pci_port(struct device_node *np, return -1; /* Get the PCI address. Assume BAR 0 */ - addrp = of_get_pci_address(pci_dev, 0, NULL); + addrp = of_get_pci_address(pci_dev, 0, NULL, &flags); if (addrp == NULL) return -1; /* We only support BAR 0 for now */ - iotype = (addrp[0] & 0x02000000) ? UPIO_MEM : UPIO_PORT; + iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT; addr = of_translate_address(pci_dev, addrp); /* Set the IO base to the same as the translated address for MMIO, diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 5f241fcd88e8..0988222741f0 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -1181,6 +1181,20 @@ void phbs_remap_io(void) remap_bus_range(hose->bus); } +unsigned int pci_address_to_pio(phys_addr_t address) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + if (address >= hose->io_base_phys && + address < (hose->io_base_phys + hose->pci_io_size)) + return (unsigned int)hose->io_base_virt + + (address - hose->io_base_phys); + } + return (unsigned int)-1; +} +EXPORT_SYMBOL_GPL(pci_address_to_pio); + static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 23c85af53d47..5b764277f470 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #ifdef DEBUG #define DBG(fmt...) do { printk(fmt); } while(0) @@ -54,6 +56,7 @@ struct of_bus { int *addrc, int *sizec); u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(u32 *addr); }; @@ -61,8 +64,8 @@ struct of_bus { * Default translator (generic bus) */ -static void of_default_count_cells(struct device_node *dev, - int *addrc, int *sizec) +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) { if (addrc) *addrc = prom_n_addr_cells(dev); @@ -70,7 +73,7 @@ static void of_default_count_cells(struct device_node *dev, *sizec = prom_n_size_cells(dev); } -static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) { u64 cp, s, da; @@ -86,7 +89,7 @@ static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna) return da - cp; } -static int of_default_translate(u32 *addr, u64 offset, int na) +static int of_bus_default_translate(u32 *addr, u64 offset, int na) { u64 a = of_read_addr(addr, na); memset(addr, 0, na * 4); @@ -98,6 +101,11 @@ static int of_default_translate(u32 *addr, u64 offset, int na) return 0; } +static unsigned int of_bus_default_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + /* * PCI bus specific translator @@ -139,7 +147,24 @@ static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) static int of_bus_pci_translate(u32 *addr, u64 offset, int na) { - return of_default_translate(addr + 1, offset, na - 1); + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_pci_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; } /* @@ -182,9 +207,22 @@ static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) static int of_bus_isa_translate(u32 *addr, u64 offset, int na) { - return of_default_translate(addr + 1, offset, na - 1); + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_isa_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + if (w & 1) + flags |= IORESOURCE_IO; + else + flags |= IORESOURCE_MEM; + return flags; } + /* * Array of bus specific translators */ @@ -198,6 +236,7 @@ static struct of_bus of_busses[] = { .count_cells = of_bus_pci_count_cells, .map = of_bus_pci_map, .translate = of_bus_pci_translate, + .get_flags = of_bus_pci_get_flags, }, /* ISA */ { @@ -207,15 +246,17 @@ static struct of_bus of_busses[] = { .count_cells = of_bus_isa_count_cells, .map = of_bus_isa_map, .translate = of_bus_isa_translate, + .get_flags = of_bus_isa_get_flags, }, /* Default */ { .name = "default", .addresses = "reg", .match = NULL, - .count_cells = of_default_count_cells, - .map = of_default_map, - .translate = of_default_translate, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, }, }; @@ -254,7 +295,8 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, ranges = (u32 *)get_property(parent, "ranges", &rlen); if (ranges == NULL || rlen == 0) { offset = of_read_addr(addr, na); - memset(addr, 0, pna); + memset(addr, 0, pna * 4); + DBG("OF: no ranges, 1:1 translation\n"); goto finish; } @@ -370,7 +412,8 @@ u64 of_translate_address(struct device_node *dev, u32 *in_addr) } EXPORT_SYMBOL(of_translate_address); -u32 *of_get_address(struct device_node *dev, int index, u64 *size) +u32 *of_get_address(struct device_node *dev, int index, u64 *size, + unsigned int *flags) { u32 *prop; unsigned int psize; @@ -399,22 +442,106 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size) if (i == index) { if (size) *size = of_read_addr(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); return prop; } return NULL; } EXPORT_SYMBOL(of_get_address); -u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size) +u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, + unsigned int *flags) { - u32 *addr; - int index; + u32 *prop; + unsigned int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; - for (index = 0; (addr = of_get_address(dev, index, size)) != NULL; - index++) { - if ((addr[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) - return addr; - } + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + bus = of_match_bus(parent); + if (strcmp(bus->name, "pci")) + return NULL; + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_COUNTS(na, ns)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = (u32 *)get_property(dev, bus->addresses, &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) + if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { + if (size) + *size = of_read_addr(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); + return prop; + } return NULL; } EXPORT_SYMBOL(of_get_pci_address); + +static int __of_address_to_resource(struct device_node *dev, u32 *addrp, + u64 size, unsigned int flags, + struct resource *r) +{ + u64 taddr; + + if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + return -EINVAL; + taddr = of_translate_address(dev, addrp); + if (taddr == OF_BAD_ADDR) + return -EINVAL; + memset(r, 0, sizeof(struct resource)); + if (flags & IORESOURCE_IO) { + unsigned int port; + port = pci_address_to_pio(taddr); + if (port == (unsigned int)-1) + return -EINVAL; + r->start = port; + r->end = port + size - 1; + } else { + r->start = taddr; + r->end = taddr + size - 1; + } + r->flags = flags; + r->name = dev->name; + return 0; +} + +int of_address_to_resource(struct device_node *dev, int index, + struct resource *r) +{ + u32 *addrp; + u64 size; + unsigned int flags; + + addrp = of_get_address(dev, index, &size, &flags); + if (addrp == NULL) + return -EINVAL; + return __of_address_to_resource(dev, addrp, size, flags, r); +} +EXPORT_SYMBOL_GPL(of_address_to_resource); + +int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r) +{ + u32 *addrp; + u64 size; + unsigned int flags; + + addrp = of_get_pci_address(dev, bar, &size, &flags); + if (addrp == NULL) + return -EINVAL; + return __of_address_to_resource(dev, addrp, size, flags, r); +} +EXPORT_SYMBOL_GPL(of_pci_address_to_resource); diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 52a9d0c1b8b8..b2928bbe9227 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2683,7 +2683,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); return; } - addrp = of_get_pci_address(node, 0, &size); + addrp = of_get_pci_address(node, 0, &size, NULL); if (addrp == NULL) { printk(KERN_ERR "pmac_feature: %s: can't find base !\n", node->full_name); diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 0aa184112fb1..af364003880b 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1805,6 +1805,21 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr) EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); +unsigned int pci_address_to_pio(phys_addr_t address) +{ + struct pci_controller* hose = hose_head; + + for (; hose; hose = hose->next) { + unsigned int size = hose->io_resource.end - + hose->io_resource.start + 1; + if (address >= hose->io_base_phys && + address < (hose->io_base_phys + size)) + return (unsigned int)hose->io_base_virt + + (address - hose->io_base_phys); + } + return (unsigned int)-1; +} +EXPORT_SYMBOL(pci_address_to_pio); /* * Null PCI config access functions, for the case when we can't diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index f14c744a94ef..0137ff239f13 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -332,18 +332,14 @@ static void macio_setup_resources(struct macio_dev *dev, struct resource *parent_res) { struct device_node *np = dev->ofdev.node; - u32 *addr; - u64 size; + struct resource r; int index; - for (index = 0; (addr = of_get_address(np, index, &size)) != NULL; - index++) { + for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) { struct resource *res = &dev->resource[index]; if (index >= MACIO_DEV_COUNT_RESOURCES) break; - res->start = of_translate_address(np, addr); - res->end = res->start + (unsigned long)size - 1; - res->flags = IORESOURCE_MEM; + *res = r; res->name = dev->ofdev.dev.bus_id; if (macio_resource_quirks(np, res, index)) { @@ -353,7 +349,7 @@ static void macio_setup_resources(struct macio_dev *dev, /* Currently, we consider failure as harmless, this may * change in the future, once I've found all the device * tree bugs in older machines & worked around them - */ +l */ if (insert_resource(parent_res, res)) { printk(KERN_WARNING "Can't request resource " "%d for MacIO device %s\n", diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 00d21513d009..01132bb602e3 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -156,6 +156,15 @@ extern struct pci_controller * pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); +#ifdef CONFIG_PCI +extern unsigned int pci_address_to_pio(phys_addr_t address); +#else +static inline unsigned int pci_address_to_pio(phys_addr_t address) +{ + return (unsigned int)-1; +} +#endif + /* Return values for ppc_md.pci_probe_mode function */ #define PCI_PROBE_NONE -1 /* Don't look at this bus at all */ #define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */ diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index fb732c992bd2..73d27bad55fa 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -223,14 +223,36 @@ extern struct resource *request_OF_resource(struct device_node* node, int index, const char* name_postfix); extern int release_OF_resource(struct device_node* node, int index); + /* - * Address translation function(s) + * OF address retreival & translation + */ + + +/* Translate an OF address block into a CPU physical address */ #define OF_BAD_ADDR ((u64)-1) extern u64 of_translate_address(struct device_node *np, u32 *addr); -extern u32 *of_get_address(struct device_node *dev, int index, u64 *size); -extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size); +/* Extract an address from a device, returns the region size and + * the address space flags too. The PCI version uses a BAR number + * instead of an absolute index + */ +extern u32 *of_get_address(struct device_node *dev, int index, + u64 *size, unsigned int *flags); +extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, + u64 *size, unsigned int *flags); + +/* Get an address as a resource. Note that if your address is + * a PIO address, the conversion will fail if the physical address + * can't be internally converted to an IO token with + * pci_address_to_pio(), that is because it's either called to early + * or it can't be matched to any host bridge IO space + */ +extern int of_address_to_resource(struct device_node *dev, int index, + struct resource *r); +extern int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r); #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index e58c78f90a5a..95672ddfe528 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -137,5 +137,14 @@ static inline unsigned char bridge_swizzle(unsigned char pin, */ extern int pciauto_bus_scan(struct pci_controller *, int); +#ifdef CONFIG_PCI +extern unsigned int pci_address_to_pio(phys_addr_t address); +#else +static inline unsigned int pci_address_to_pio(phys_addr_t address) +{ + return (unsigned int)-1; +} +#endif + #endif #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index a10a2d64b300..eb317a0806e4 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -138,12 +138,34 @@ extern unsigned long sub_reloc_offset(unsigned long); /* - * Address translation function(s) + * OF address retreival & translation + */ + + +/* Translate an OF address block into a CPU physical address */ #define OF_BAD_ADDR ((u64)-1) extern u64 of_translate_address(struct device_node *np, u32 *addr); -extern u32 *of_get_address(struct device_node *dev, int index, u64 *size); -extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size); + +/* Extract an address from a device, returns the region size and + * the address space flags too. The PCI version uses a BAR number + * instead of an absolute index + */ +extern u32 *of_get_address(struct device_node *dev, int index, + u64 *size, unsigned int *flags); +extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, + u64 *size, unsigned int *flags); + +/* Get an address as a resource. Note that if your address is + * a PIO address, the conversion will fail if the physical address + * can't be internally converted to an IO token with + * pci_address_to_pio(), that is because it's either called to early + * or it can't be matched to any host bridge IO space + */ +extern int of_address_to_resource(struct device_node *dev, int index, + struct resource *r); +extern int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r); #endif /* _PPC_PROM_H */ -- cgit v1.2.3 From 54c233102f3680c7f08b6f06d229cc48503b79c4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 5 Dec 2005 15:50:39 +1100 Subject: Revert "[PATCH] powerpc: Minor numa memory code cleanup" This reverts f1fdc0117004d343698b9830e141491d5ae320d1 commit. --- arch/powerpc/mm/numa.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 30b5d6a1d838..ba7a3055a9fc 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -254,17 +254,29 @@ static int __init find_min_common_depth(void) return depth; } -static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) +static int __init get_mem_addr_cells(void) { struct device_node *memory = NULL; + int rc; memory = of_find_node_by_type(memory, "memory"); - if (memory) { - *n_addr_cells = prom_n_addr_cells(memory); - *n_size_cells = prom_n_size_cells(memory); - of_node_put(memory); - } - /* if (!memory) we are in trouble, let other code error out */ + if (!memory) + return 0; /* it won't matter */ + + rc = prom_n_addr_cells(memory); + return rc; +} + +static int __init get_mem_size_cells(void) +{ + struct device_node *memory = NULL; + int rc; + + memory = of_find_node_by_type(memory, "memory"); + if (!memory) + return 0; /* it won't matter */ + rc = prom_n_size_cells(memory); + return rc; } static unsigned long __init read_n_cells(int n, unsigned int **buf) @@ -374,7 +386,7 @@ static int __init parse_numa_properties(void) { struct device_node *cpu = NULL; struct device_node *memory = NULL; - int n_addr_cells, n_size_cells; + int addr_cells, size_cells; int max_domain; unsigned long i; @@ -413,7 +425,8 @@ static int __init parse_numa_properties(void) } } - get_n_mem_cells(&n_addr_cells, &n_size_cells); + addr_cells = get_mem_addr_cells(); + size_cells = get_mem_size_cells(); memory = NULL; while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { unsigned long start; @@ -430,8 +443,8 @@ static int __init parse_numa_properties(void) ranges = memory->n_addrs; new_range: /* these are order-sensitive, and modify the buffer pointer */ - start = read_n_cells(n_addr_cells, &memcell_buf); - size = read_n_cells(n_size_cells, &memcell_buf); + start = read_n_cells(addr_cells, &memcell_buf); + size = read_n_cells(size_cells, &memcell_buf); numa_domain = of_node_numa_domain(memory); -- cgit v1.2.3 From 84c9fdd11e40f46028ff4669bfe5177ce9521266 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Wed, 30 Nov 2005 13:47:23 -0800 Subject: [PATCH] powerpc: Minor numa memory code cleanup Here is an updated version of the patch that panics if no memory is found as Nathan suggested. I'm still concerned that panic strings (not just the one added here) at this stage of booting do not show up on my system. But, that is an issue separate from this patch. Combine get_mem_*_cells() routines to avoid multiple memory node lookups. Added missing of_node_put() call. Changed variable names to help with some confusion as to meaning. Signed-off-by: Mike Kravetz Signed-off-by: Paul Mackerras --- arch/powerpc/mm/numa.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index ba7a3055a9fc..e812d3d0d6ae 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -254,29 +254,17 @@ static int __init find_min_common_depth(void) return depth; } -static int __init get_mem_addr_cells(void) +static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) { struct device_node *memory = NULL; - int rc; memory = of_find_node_by_type(memory, "memory"); if (!memory) - return 0; /* it won't matter */ + panic("numa.c: No memory nodes found!"); - rc = prom_n_addr_cells(memory); - return rc; -} - -static int __init get_mem_size_cells(void) -{ - struct device_node *memory = NULL; - int rc; - - memory = of_find_node_by_type(memory, "memory"); - if (!memory) - return 0; /* it won't matter */ - rc = prom_n_size_cells(memory); - return rc; + *n_addr_cells = prom_n_addr_cells(memory); + *n_size_cells = prom_n_size_cells(memory); + of_node_put(memory); } static unsigned long __init read_n_cells(int n, unsigned int **buf) @@ -386,7 +374,7 @@ static int __init parse_numa_properties(void) { struct device_node *cpu = NULL; struct device_node *memory = NULL; - int addr_cells, size_cells; + int n_addr_cells, n_size_cells; int max_domain; unsigned long i; @@ -425,8 +413,7 @@ static int __init parse_numa_properties(void) } } - addr_cells = get_mem_addr_cells(); - size_cells = get_mem_size_cells(); + get_n_mem_cells(&n_addr_cells, &n_size_cells); memory = NULL; while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { unsigned long start; @@ -443,8 +430,8 @@ static int __init parse_numa_properties(void) ranges = memory->n_addrs; new_range: /* these are order-sensitive, and modify the buffer pointer */ - start = read_n_cells(addr_cells, &memcell_buf); - size = read_n_cells(size_cells, &memcell_buf); + start = read_n_cells(n_addr_cells, &memcell_buf); + size = read_n_cells(n_size_cells, &memcell_buf); numa_domain = of_node_numa_domain(memory); -- cgit v1.2.3 From 7b653cafcbf187c6d86ee3551e4d73a610f18d27 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Sat, 3 Dec 2005 16:42:25 -0200 Subject: [PATCH] ppc: removed unused variable i from code. Signed-off-by: Paul Mackerras --- arch/ppc/platforms/chrp_setup.c | 1 - arch/ppc/platforms/prep_setup.c | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c index f1b70ab3c6fd..056ac2a7b5c1 100644 --- a/arch/ppc/platforms/chrp_setup.c +++ b/arch/ppc/platforms/chrp_setup.c @@ -404,7 +404,6 @@ static struct irqaction xmon_irqaction = { void __init chrp_init_IRQ(void) { struct device_node *np; - int i; unsigned long chrp_int_ack = 0; unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index a6a188910a1a..d06535802003 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -953,7 +953,6 @@ prep_calibrate_decr(void) static void __init prep_init_IRQ(void) { - int i; unsigned int pci_viddid, pci_did; if (OpenPIC_Addr != NULL) { -- cgit v1.2.3 From 9100b205fdc70b300894954ebebbf2709c5ed525 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 29 Nov 2005 19:20:55 +0000 Subject: [PATCH] powerpc32: clean up available memory models Clean up the currently available memory models for ppc32 under the powerpc architecture. We need FLATMEM for ppc32: enable it. SPARSEMEM is not parameterised for ppc32 so disable that. Take this opportunity to clean up white space for FLATMEM_ENABLE. Signed-off-by: Andy Whitcroft Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 0e4617104f8c..2c1186ada3ab 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -586,11 +586,12 @@ config ARCH_SELECT_MEMORY_MODEL depends on PPC64 config ARCH_FLATMEM_ENABLE - def_bool y - depends on PPC64 && !NUMA + def_bool y + depends on (PPC64 && !NUMA) || PPC32 config ARCH_SPARSEMEM_ENABLE def_bool y + depends on PPC64 config ARCH_SPARSEMEM_DEFAULT def_bool y -- cgit v1.2.3 From e40c7f02723e2be5d3144917191aa9fbec5bb64e Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 29 Nov 2005 19:25:54 +0000 Subject: [PATCH] powerpc32: fix definition of distribute_irqs When we select ppc32 under the powerpc architecture we get the error below. This relates to defining distribute_irqs when this configuratiom option is undefined. CC arch/powerpc/sysdev/mpic.o .../arch/powerpc/sysdev/mpic.c: In function `mpic_setup_this_cpu': .../arch/powerpc/sysdev/mpic.c:788: error: `CONFIG_IRQ_ALL_CPUS' undeclared (first use in this function) Signed-off-by: Andy Whitcroft Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 58d1cc2023c8..ae24e2b82c5a 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -45,7 +45,11 @@ static struct mpic *mpic_primary; static DEFINE_SPINLOCK(mpic_lock); #ifdef CONFIG_PPC32 /* XXX for now */ -#define distribute_irqs CONFIG_IRQ_ALL_CPUS +#ifdef CONFIG_IRQ_ALL_CPUS +#define distribute_irqs (1) +#else +#define distribute_irqs (0) +#endif #endif /* -- cgit v1.2.3 From cd0ca2ce4b2f4a5132e7e230be8a510755c20870 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:12 +1100 Subject: [PATCH] powerpc: Propagate regs through to machine_crash_shutdown Currently machine_crash_shutdown() gets a struct pt_regs, but doesn't pass it through to the ppc_md function, it should. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/machine_kexec.c | 2 +- include/asm-powerpc/machdep.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index d8225c797199..a91e40c9ae45 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -23,7 +23,7 @@ note_buf_t crash_notes[NR_CPUS]; void machine_crash_shutdown(struct pt_regs *regs) { if (ppc_md.machine_crash_shutdown) - ppc_md.machine_crash_shutdown(); + ppc_md.machine_crash_shutdown(regs); } /* diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index d6a1a2b5507d..32539022f0a4 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -222,7 +222,7 @@ struct machdep_calls { * to run successfully. * XXX Should we move this one out of kexec scope? */ - void (*machine_crash_shutdown)(void); + void (*machine_crash_shutdown)(struct pt_regs *regs); /* Called to do what every setup is needed on image and the * reboot code buffer. Returns 0 on success. -- cgit v1.2.3 From 51fae6de24da57bc6cdaa1b253595c3513ecbf2d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:15 +1100 Subject: [PATCH] powerpc: Add a is_kernel_addr() macro There's a bunch of code that compares an address with KERNELBASE to see if it's a "kernel address", ie. >= KERNELBASE. The proper test is actually to compare with PAGE_OFFSET, since we're going to change KERNELBASE soon. So replace all of them with an is_kernel_addr() macro that does that. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 2 +- arch/powerpc/kernel/setup-common.c | 2 +- arch/powerpc/mm/slb.c | 6 +++--- arch/powerpc/mm/stab.c | 6 +++--- arch/powerpc/mm/tlb_64.c | 2 +- arch/powerpc/oprofile/op_model_power4.c | 4 ++-- arch/powerpc/oprofile/op_model_rs64.c | 3 +-- arch/powerpc/xmon/xmon.c | 4 ++-- include/asm-powerpc/page.h | 6 ++++++ 9 files changed, 20 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index bcdc209dca85..369e1a6cdd40 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1994,7 +1994,7 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) if (r3 && r4 && r4 != 0xdeadbeef) { unsigned long val; - RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; + RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3; RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; val = RELOC(prom_initrd_start); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index a6d8aebf2bc6..d5c52fae023a 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -319,7 +319,7 @@ void __init check_for_initrd(void) /* If we were passed an initrd, set the ROOT_DEV properly if the values * look sensible. If not, clear initrd reference. */ - if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && + if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) && initrd_end > initrd_start) ROOT_DEV = Root_RAM0; else diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 60e852f2f8e5..a47b273600ec 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -134,14 +134,14 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) else unmapped_base = TASK_UNMAPPED_BASE_USER64; - if (pc >= KERNELBASE) + if (is_kernel_addr(pc)) return; slb_allocate(pc); if (GET_ESID(pc) == GET_ESID(stack)) return; - if (stack >= KERNELBASE) + if (is_kernel_addr(stack)) return; slb_allocate(stack); @@ -149,7 +149,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) || (GET_ESID(stack) == GET_ESID(unmapped_base))) return; - if (unmapped_base >= KERNELBASE) + if (is_kernel_addr(unmapped_base)) return; slb_allocate(unmapped_base); } diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 51e7951414e5..a18dab0d6b12 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -122,7 +122,7 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm) unsigned long offset; /* Kernel or user address? */ - if (ea >= KERNELBASE) { + if (is_kernel_addr(ea)) { vsid = get_kernel_vsid(ea); } else { if ((ea >= TASK_SIZE_USER64) || (! mm)) @@ -133,7 +133,7 @@ static int __ste_allocate(unsigned long ea, struct mm_struct *mm) stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid); - if (ea < KERNELBASE) { + if (!is_kernel_addr(ea)) { offset = __get_cpu_var(stab_cache_ptr); if (offset < NR_STAB_CACHE_ENTRIES) __get_cpu_var(stab_cache[offset++]) = stab_entry; @@ -190,7 +190,7 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm) entry++, ste++) { unsigned long ea; ea = ste->esid_data & ESID_MASK; - if (ea < KERNELBASE) { + if (!is_kernel_addr(ea)) { ste->esid_data = 0; } } diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c index 859d29a0cac5..bb3afb6e6317 100644 --- a/arch/powerpc/mm/tlb_64.c +++ b/arch/powerpc/mm/tlb_64.c @@ -168,7 +168,7 @@ void hpte_update(struct mm_struct *mm, unsigned long addr, batch->mm = mm; batch->psize = psize; } - if (addr < KERNELBASE) { + if (!is_kernel_addr(addr)) { vsid = get_vsid(mm->context.id, addr); WARN_ON(vsid == 0); } else diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index a3401b46f3ba..659a021da0c7 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -252,7 +252,7 @@ static unsigned long get_pc(struct pt_regs *regs) return (unsigned long)__va(pc); /* Not sure where we were */ - if (pc < KERNELBASE) + if (!is_kernel_addr(pc)) /* function descriptor madness */ return *((unsigned long *)kernel_unknown_bucket); @@ -264,7 +264,7 @@ static int get_kernel(unsigned long pc) int is_kernel; if (!mmcra_has_sihv) { - is_kernel = (pc >= KERNELBASE); + is_kernel = is_kernel_addr(pc); } else { unsigned long mmcra = mfspr(SPRN_MMCRA); is_kernel = ((mmcra & MMCRA_SIPR) == 0); diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c index e010b85996e8..5c909ee609fe 100644 --- a/arch/powerpc/oprofile/op_model_rs64.c +++ b/arch/powerpc/oprofile/op_model_rs64.c @@ -178,7 +178,6 @@ static void rs64_handle_interrupt(struct pt_regs *regs, int val; int i; unsigned long pc = mfspr(SPRN_SIAR); - int is_kernel = (pc >= KERNELBASE); /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); @@ -187,7 +186,7 @@ static void rs64_handle_interrupt(struct pt_regs *regs, val = ctr_read(i); if (val < 0) { if (ctr[i].enabled) { - oprofile_add_pc(pc, is_kernel, i); + oprofile_add_pc(pc, is_kernel_addr(pc), i); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 465b75c5647e..22612ed5379c 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -1013,7 +1013,7 @@ static long check_bp_loc(unsigned long addr) unsigned int instr; addr &= ~3; - if (addr < KERNELBASE) { + if (!is_kernel_addr(addr)) { printf("Breakpoints may only be placed at kernel addresses\n"); return 0; } @@ -1064,7 +1064,7 @@ bpt_cmds(void) dabr.address = 0; dabr.enabled = 0; if (scanhex(&dabr.address)) { - if (dabr.address < KERNELBASE) { + if (!is_kernel_addr(dabr.address)) { printf(badaddr); break; } diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index 18c1e5ee81a3..94905ba2cf41 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h @@ -86,6 +86,12 @@ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE) +/* + * Don't compare things with KERNELBASE or PAGE_OFFSET to test for + * "kernelness", use is_kernel_addr() - it should do what you want. + */ +#define is_kernel_addr(x) ((x) >= PAGE_OFFSET) + #ifndef __ASSEMBLY__ #undef STRICT_MM_TYPECHECKS -- cgit v1.2.3 From b5666f70395016a55cc9d57826508b8a346398d0 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 5 Dec 2005 10:24:33 -0600 Subject: [PATCH] powerpc: Separate usage of KERNELBASE and PAGE_OFFSET This patch separates usage of KERNELBASE and PAGE_OFFSET. I haven't looked at any of the PPC32 code, if we ever want to support Kdump on PPC we'll have to do another audit, ditto for iSeries. This patch makes PAGE_OFFSET the constant, it'll always be 0xC * 1 gazillion for 64-bit. To get a physical address from a virtual one you subtract PAGE_OFFSET, _not_ KERNELBASE. KERNELBASE is the virtual address of the start of the kernel, it's often the same as PAGE_OFFSET, but _might not be_. If you want to know something's offset from the start of the kernel you should subtract KERNELBASE. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/btext.c | 4 ++-- arch/powerpc/kernel/entry_64.S | 4 ++-- arch/powerpc/kernel/lparmap.c | 6 +++--- arch/powerpc/kernel/machine_kexec_64.c | 5 ++--- arch/powerpc/mm/hash_utils_64.c | 6 +++--- arch/powerpc/mm/slb.c | 4 ++-- arch/powerpc/mm/slb_low.S | 6 +++--- arch/powerpc/mm/stab.c | 10 +++++----- include/asm-powerpc/page.h | 16 +++++++++++++++- 9 files changed, 37 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 893dd24a9f67..5de0d80ca2f2 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -60,7 +60,7 @@ int force_printk_to_btext = 0; * * The display is mapped to virtual address 0xD0000000, rather * than 1:1, because some some CHRP machines put the frame buffer - * in the region starting at 0xC0000000 (KERNELBASE). + * in the region starting at 0xC0000000 (PAGE_OFFSET). * This mapping is temporary and will disappear as soon as the * setup done by MMU_Init() is applied. * @@ -71,7 +71,7 @@ int force_printk_to_btext = 0; */ void __init btext_prepare_BAT(void) { - unsigned long vaddr = KERNELBASE + 0x10000000; + unsigned long vaddr = PAGE_OFFSET + 0x10000000; unsigned long addr; unsigned long lowbits; diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 7b9397169709..aacebb33e98a 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -690,7 +690,7 @@ _GLOBAL(enter_rtas) /* Setup our real return addr */ SET_REG_TO_LABEL(r4,.rtas_return_loc) - SET_REG_TO_CONST(r9,KERNELBASE) + SET_REG_TO_CONST(r9,PAGE_OFFSET) sub r4,r4,r9 mtlr r4 @@ -718,7 +718,7 @@ _GLOBAL(enter_rtas) _STATIC(rtas_return_loc) /* relocation is off at this point */ mfspr r4,SPRN_SPRG3 /* Get PACA */ - SET_REG_TO_CONST(r5, KERNELBASE) + SET_REG_TO_CONST(r5, PAGE_OFFSET) sub r4,r4,r5 /* RELOC the PACA base pointer */ mfmsr r6 diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c index 5a05a797485f..8a53d436ad9a 100644 --- a/arch/powerpc/kernel/lparmap.c +++ b/arch/powerpc/kernel/lparmap.c @@ -16,8 +16,8 @@ const struct LparMap __attribute__((__section__(".text"))) xLparMap = { .xSegmentTableOffs = STAB0_PAGE, .xEsids = { - { .xKernelEsid = GET_ESID(KERNELBASE), - .xKernelVsid = KERNEL_VSID(KERNELBASE), }, + { .xKernelEsid = GET_ESID(PAGE_OFFSET), + .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), }, { .xKernelEsid = GET_ESID(VMALLOCBASE), .xKernelVsid = KERNEL_VSID(VMALLOCBASE), }, }, @@ -25,7 +25,7 @@ const struct LparMap __attribute__((__section__(".text"))) xLparMap = { .xRanges = { { .xPages = HvPagesToMap, .xOffset = 0, - .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - HW_PAGE_SHIFT), + .xVPN = KERNEL_VSID(PAGE_OFFSET) << (SID_SHIFT - HW_PAGE_SHIFT), }, }, }; diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index ec0f06bfc24a..0b0fa4768995 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -153,9 +153,8 @@ void kexec_copy_flush(struct kimage *image) * including ones that were in place on the original copy */ for (i = 0; i < nr_segments; i++) - flush_icache_range(ranges[i].mem + KERNELBASE, - ranges[i].mem + KERNELBASE + - ranges[i].memsz); + flush_icache_range((unsigned long)__va(ranges[i].mem), + (unsigned long)__va(ranges[i].mem + ranges[i].memsz)); } #ifdef CONFIG_SMP diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 846a1894cf95..5bb433cbe41b 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -456,7 +456,7 @@ void __init htab_initialize(void) /* create bolted the linear mapping in the hash table */ for (i=0; i < lmb.memory.cnt; i++) { - base = lmb.memory.region[i].base + KERNELBASE; + base = (unsigned long)__va(lmb.memory.region[i].base); size = lmb.memory.region[i].size; DBG("creating mapping for region: %lx : %lx\n", base, size); @@ -498,8 +498,8 @@ void __init htab_initialize(void) * for either 4K or 16MB pages. */ if (tce_alloc_start) { - tce_alloc_start += KERNELBASE; - tce_alloc_end += KERNELBASE; + tce_alloc_start = (unsigned long)__va(tce_alloc_start); + tce_alloc_end = (unsigned long)__va(tce_alloc_end); if (base + size >= tce_alloc_start) tce_alloc_start = base + size + 1; diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index a47b273600ec..cc22570856af 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -75,7 +75,7 @@ static void slb_flush_and_rebolt(void) vflags = SLB_VSID_KERNEL | virtual_llp; ksp_esid_data = mk_esid_data(get_paca()->kstack, 2); - if ((ksp_esid_data & ESID_MASK) == KERNELBASE) + if ((ksp_esid_data & ESID_MASK) == PAGE_OFFSET) ksp_esid_data &= ~SLB_ESID_V; /* We need to do this all in asm, so we're sure we don't touch @@ -213,7 +213,7 @@ void slb_initialize(void) asm volatile("isync":::"memory"); asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); - create_slbe(KERNELBASE, lflags, 0); + create_slbe(PAGE_OFFSET, lflags, 0); /* VMALLOC space has 4K pages always for now */ create_slbe(VMALLOCBASE, vflags, 1); diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 950ffc5848c7..d1acee38f163 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -37,9 +37,9 @@ _GLOBAL(slb_allocate_realmode) srdi r9,r3,60 /* get region */ srdi r10,r3,28 /* get esid */ - cmpldi cr7,r9,0xc /* cmp KERNELBASE for later use */ + cmpldi cr7,r9,0xc /* cmp PAGE_OFFSET for later use */ - /* r3 = address, r10 = esid, cr7 = <>KERNELBASE */ + /* r3 = address, r10 = esid, cr7 = <> PAGE_OFFSET */ blt cr7,0f /* user or kernel? */ /* kernel address: proto-VSID = ESID */ @@ -166,7 +166,7 @@ _GLOBAL(slb_allocate_user) /* * Finish loading of an SLB entry and return * - * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <>KERNELBASE + * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9, cr7 = <> PAGE_OFFSET */ slb_finish_load: ASM_VSID_SCRAMBLE(r10,r9) diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index a18dab0d6b12..82e4951826bc 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -40,7 +40,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) unsigned long entry, group, old_esid, castout_entry, i; unsigned int global_entry; struct stab_entry *ste, *castout_ste; - unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE; + unsigned long kernel_segment = (esid << SID_SHIFT) >= PAGE_OFFSET; vsid_data = vsid << STE_VSID_SHIFT; esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V; @@ -83,7 +83,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid) } /* Dont cast out the first kernel segment */ - if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE) + if ((castout_ste->esid_data & ESID_MASK) != PAGE_OFFSET) break; castout_entry = (castout_entry + 1) & 0xf; @@ -251,7 +251,7 @@ void stabs_alloc(void) panic("Unable to allocate segment table for CPU %d.\n", cpu); - newstab += KERNELBASE; + newstab = (unsigned long)__va(newstab); memset((void *)newstab, 0, HW_PAGE_SIZE); @@ -270,11 +270,11 @@ void stabs_alloc(void) */ void stab_initialize(unsigned long stab) { - unsigned long vsid = get_kernel_vsid(KERNELBASE); + unsigned long vsid = get_kernel_vsid(PAGE_OFFSET); unsigned long stabreal; asm volatile("isync; slbia; isync":::"memory"); - make_ste(stab, GET_ESID(KERNELBASE), vsid); + make_ste(stab, GET_ESID(PAGE_OFFSET), vsid); /* Order update */ asm volatile("sync":::"memory"); diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index 94905ba2cf41..4696bdbcc085 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h @@ -37,6 +37,20 @@ */ #define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) +/* + * KERNELBASE is the virtual address of the start of the kernel, it's often + * the same as PAGE_OFFSET, but _might not be_. + * + * The kdump dump kernel is one example where KERNELBASE != PAGE_OFFSET. + * + * To get a physical address from a virtual one you subtract PAGE_OFFSET, + * _not_ KERNELBASE. + * + * If you want to know something's offset from the start of the kernel you + * should subtract KERNELBASE. + * + * If you want to test if something's a kernel address, use is_kernel_addr(). + */ #define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START) #define KERNELBASE PAGE_OFFSET @@ -56,7 +70,7 @@ #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE)) +#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) /* -- cgit v1.2.3 From 237a0989e2902b7d43c4228a36d82f8691fb2118 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Mon, 5 Dec 2005 12:06:42 -0800 Subject: [PATCH] powerpc: numa placement for dynamically added memory This places dynamically added memory within the appropriate numa node. A new routine hot_add_scn_to_nid() replicates most of the memory scanning code in parse_numa_properties(). Signed-off-by: Mike Kravetz Signed-off-by: Paul Mackerras --- arch/powerpc/mm/mem.c | 11 ++++---- arch/powerpc/mm/numa.c | 57 +++++++++++++++++++++++++++++++++++++---- include/asm-powerpc/sparsemem.h | 8 ++++++ 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index ed6ed2e30dac..5e5bff5616a8 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -114,18 +114,17 @@ void online_page(struct page *page) num_physpages++; } -/* - * This works only for the non-NUMA case. Later, we'll need a lookup - * to convert from real physical addresses to nid, that doesn't use - * pfn_to_nid(). - */ int __devinit add_memory(u64 start, u64 size) { - struct pglist_data *pgdata = NODE_DATA(0); + struct pglist_data *pgdata; struct zone *zone; + int nid; unsigned long start_pfn = start >> PAGE_SHIFT; unsigned long nr_pages = size >> PAGE_SHIFT; + nid = hot_add_scn_to_nid(start); + pgdata = NODE_DATA(nid); + start += KERNELBASE; create_section_mapping(start, start + size); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index e812d3d0d6ae..40c99deb691b 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -37,6 +37,7 @@ EXPORT_SYMBOL(node_data); static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; static int min_common_depth; +static int n_mem_addr_cells, n_mem_size_cells; /* * We need somewhere to store start/end/node for each region until we have @@ -267,7 +268,7 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) of_node_put(memory); } -static unsigned long __init read_n_cells(int n, unsigned int **buf) +static unsigned long __devinit read_n_cells(int n, unsigned int **buf) { unsigned long result = 0; @@ -374,7 +375,6 @@ static int __init parse_numa_properties(void) { struct device_node *cpu = NULL; struct device_node *memory = NULL; - int n_addr_cells, n_size_cells; int max_domain; unsigned long i; @@ -413,7 +413,7 @@ static int __init parse_numa_properties(void) } } - get_n_mem_cells(&n_addr_cells, &n_size_cells); + get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); memory = NULL; while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { unsigned long start; @@ -430,8 +430,8 @@ static int __init parse_numa_properties(void) ranges = memory->n_addrs; new_range: /* these are order-sensitive, and modify the buffer pointer */ - start = read_n_cells(n_addr_cells, &memcell_buf); - size = read_n_cells(n_size_cells, &memcell_buf); + start = read_n_cells(n_mem_addr_cells, &memcell_buf); + size = read_n_cells(n_mem_size_cells, &memcell_buf); numa_domain = of_node_numa_domain(memory); @@ -717,3 +717,50 @@ static int __init early_numa(char *p) return 0; } early_param("numa", early_numa); + +#ifdef CONFIG_MEMORY_HOTPLUG +/* + * Find the node associated with a hot added memory section. Section + * corresponds to a SPARSEMEM section, not an LMB. It is assumed that + * sections are fully contained within a single LMB. + */ +int hot_add_scn_to_nid(unsigned long scn_addr) +{ + struct device_node *memory = NULL; + + if (!numa_enabled || (min_common_depth < 0)) + return 0; + + while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { + unsigned long start, size; + int numa_domain, ranges; + unsigned int *memcell_buf; + unsigned int len; + + memcell_buf = (unsigned int *)get_property(memory, "reg", &len); + if (!memcell_buf || len <= 0) + continue; + + ranges = memory->n_addrs; /* ranges in cell */ +ha_new_range: + start = read_n_cells(n_mem_addr_cells, &memcell_buf); + size = read_n_cells(n_mem_size_cells, &memcell_buf); + numa_domain = of_node_numa_domain(memory); + + /* Domains not present at boot default to 0 */ + if (!node_online(numa_domain)) + numa_domain = any_online_node(NODE_MASK_ALL); + + if ((scn_addr >= start) && (scn_addr < (start + size))) { + of_node_put(memory); + return numa_domain; + } + + if (--ranges) /* process all ranges in cell */ + goto ha_new_range; + } + + BUG(); /* section address should be found above */ + return 0; +} +#endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h index ba1b34fdb967..c3f17d442f7d 100644 --- a/include/asm-powerpc/sparsemem.h +++ b/include/asm-powerpc/sparsemem.h @@ -13,6 +13,14 @@ #ifdef CONFIG_MEMORY_HOTPLUG extern void create_section_mapping(unsigned long start, unsigned long end); +#ifdef CONFIG_NUMA +extern int hot_add_scn_to_nid(unsigned long scn_addr); +#else +static inline int hot_add_scn_to_nid(unsigned long scn_addr) +{ + return 0; +} +#endif /* CONFIG_NUMA */ #endif /* CONFIG_MEMORY_HOTPLUG */ #endif /* CONFIG_SPARSEMEM */ -- cgit v1.2.3 From 398f68580f3edd99728028facf571e4a07f9a035 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 5 Dec 2005 19:31:36 -0200 Subject: [PATCH] powerpc/8xx: Fix m8xx_wdt issues The following fixes some issues with the last mpc8xx_wdt update: - Adds missing #include - Use "uint __iomem" pointer for in_be32/out_be32 Signed-off-by: Marcelo Tosatti Signed-off-by: Paul Mackerras --- drivers/char/watchdog/mpc8xx_wdt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c index ac6fbace4724..b2fc71e20850 100644 --- a/drivers/char/watchdog/mpc8xx_wdt.c +++ b/drivers/char/watchdog/mpc8xx_wdt.c @@ -18,6 +18,7 @@ #include #include #include +#include #include static unsigned long wdt_opened; @@ -25,24 +26,26 @@ static int wdt_status; static void mpc8xx_wdt_handler_disable(void) { - volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + volatile uint __iomem *piscr; + piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr; if (!m8xx_has_internal_rtc) m8xx_wdt_stop_timer(); else - out_be32(imap->im_sit.sit_piscr, in_be32(&imap->im_sit.sit_piscr) & ~(PISCR_PIE | PISCR_PTE)); + out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE)); printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n"); } static void mpc8xx_wdt_handler_enable(void) { - volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + volatile uint __iomem *piscr; + piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr; if (!m8xx_has_internal_rtc) m8xx_wdt_install_timer(); else - out_be32(&imap->im_sit.sit_piscr, in_be32(&imap->im_sit.sit_piscr) | PISCR_PIE | PISCR_PTE); + out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE); printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n"); } -- cgit v1.2.3 From e07102db63d10d9f9d94d21dfdb1178e65154b9e Mon Sep 17 00:00:00 2001 From: linas Date: Mon, 5 Dec 2005 19:37:35 -0600 Subject: [PATCH] powerpc: minor cleanup of void ptr deref Minor: use macro to perform void pointer deref; this may someday help avoid pointer typecasting errors. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/pci.c | 2 +- arch/powerpc/platforms/pseries/iommu.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 443be526cde7..e0b66f55a5f8 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -326,7 +326,7 @@ static int u3_ht_skip_device(struct pci_controller *hose, else busdn = hose->arch_data; for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->data && PCI_DN(dn)->devfn == devfn) + if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn) break; if (dn == NULL) return -1; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 2043659ea7b1..169f9148789c 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -436,7 +436,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) return; } - ppci = pdn->data; + ppci = PCI_DN(pdn); if (!ppci->iommu_table) { /* Bussubno hasn't been copied yet. * Do it now because iommu_table_setparms_lpar needs it. @@ -483,10 +483,10 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev) * an already allocated iommu table is found and use that. */ - while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL) + while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL) dn = dn->parent; - if (dn && dn->data) { + if (dn && PCI_DN(dn)) { PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table; } else { DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev)); @@ -497,7 +497,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti { int err = NOTIFY_OK; struct device_node *np = node; - struct pci_dn *pci = np->data; + struct pci_dn *pci = PCI_DN(np); switch (action) { case PSERIES_RECONFIG_REMOVE: @@ -533,7 +533,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) */ dn = pci_device_to_OF_node(dev); - for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table; + for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; pdn = pdn->parent) { dma_window = (unsigned int *) get_property(pdn, "ibm,dma-window", NULL); @@ -552,7 +552,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) DBG("Found DMA window, allocating table\n"); } - pci = pdn->data; + pci = PCI_DN(pdn); if (!pci->iommu_table) { /* iommu_table_setparms_lpar needs bussubno. */ pci->bussubno = pci->phb->bus->number; -- cgit v1.2.3 From d4e4b3520c4df46cf1d15a56379a6fa57e267b7d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 7 Dec 2005 13:01:05 +1100 Subject: [PATCH] powerpc: fix for "Update OF address parsers" This allows iSeries to build again. It just moves pci_address_to_pio outside the #ifdef CONFIG_PPC_MULTIPLATFORM. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_64.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 0988222741f0..4eb93fc1eef2 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -1181,20 +1181,6 @@ void phbs_remap_io(void) remap_bus_range(hose->bus); } -unsigned int pci_address_to_pio(phys_addr_t address) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - if (address >= hose->io_base_phys && - address < (hose->io_base_phys + hose->pci_io_size)) - return (unsigned int)hose->io_base_virt + - (address - hose->io_base_phys); - } - return (unsigned int)-1; -} -EXPORT_SYMBOL_GPL(pci_address_to_pio); - static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); @@ -1337,6 +1323,20 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) #endif /* CONFIG_PPC_MULTIPLATFORM */ +unsigned int pci_address_to_pio(phys_addr_t address) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + if (address >= hose->io_base_phys && + address < (hose->io_base_phys + hose->pci_io_size)) + return (unsigned int)hose->io_base_virt + + (address - hose->io_base_phys); + } + return (unsigned int)-1; +} +EXPORT_SYMBOL_GPL(pci_address_to_pio); + #define IOBASE_BRIDGE_NUMBER 0 #define IOBASE_MEMORY 1 -- cgit v1.2.3 From 4693c09a47203d79a9adb69acaf3b3bb3dcf9390 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 7 Dec 2005 14:52:16 +1100 Subject: powerpc: Fix typo in head_64.S Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 881e18e8ef59..65aedc938a6e 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -727,7 +727,7 @@ decrementer_iSeries_masked: li r11,1 stb r11,PACALPPACA+LPPACADECRINT(r13) LOADBASE(r12,tb_ticks_per_jiffy) - lwz r12,OFF(tb_ticks_per_jiffy)(r13) + lwz r12,OFF(tb_ticks_per_jiffy)(r12) mtspr SPRN_DEC,r12 /* fall through */ -- cgit v1.2.3 From 398ab1fcb960ea0800f40a9c36355855e3e23389 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:23 +1100 Subject: [PATCH] powerpc: Add CONFIG_CRASH_DUMP This patch adds a Kconfig variable, CONFIG_CRASH_DUMP, which configures the built kernel for use as a Kdump kernel. Currently "all" this involves is changing the value of KERNELBASE to 32 MB. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 11 +++++++++++ arch/powerpc/kernel/setup_64.c | 3 +++ include/asm-powerpc/page.h | 10 +++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 2c1186ada3ab..773b880d5577 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -379,6 +379,17 @@ config CELL_IIC bool default y +config CRASH_DUMP + bool "kernel crash dumps (EXPERIMENTAL)" + depends on PPC_MULTIPLATFORM + depends on EXPERIMENTAL + help + Build a kernel suitable for use as a kdump capture kernel. + The kernel will be linked at a different address than normal, and + so can only be used for Kdump. + + Don't change this unless you know what you are doing. + config IBMVIO depends on PPC_PSERIES || PPC_ISERIES bool diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 65603e9af984..6509dd7c2f8f 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -512,6 +512,9 @@ void __init setup_system(void) ppc64_caches.iline_size); printk("htab_address = 0x%p\n", htab_address); printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); +#if PHYSICAL_START > 0 + printk("physical_start = 0x%x\n", PHYSICAL_START); +#endif printk("-----------------------------------------------------\n"); mm_init_ppc64(); diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index 4696bdbcc085..76d7cb4b4ffc 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h @@ -51,8 +51,16 @@ * * If you want to test if something's a kernel address, use is_kernel_addr(). */ + +#ifdef CONFIG_CRASH_DUMP +/* Kdump kernel runs at 32 MB, change at your peril. */ +#define PHYSICAL_START 0x2000000 +#else +#define PHYSICAL_START 0x0 +#endif + #define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START) -#define KERNELBASE PAGE_OFFSET +#define KERNELBASE (PAGE_OFFSET + PHYSICAL_START) #ifdef CONFIG_DISCONTIGMEM #define page_to_pfn(page) discontigmem_page_to_pfn(page) -- cgit v1.2.3 From 8c4f1f2958ff9d4a6760f3bdd0cfb7d2b9e12093 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:33 +1100 Subject: [PATCH] powerpc: Create a trampoline for the fwnmi vectors The fwnmi vectors can be anywhere < 32 MB, so we need to use a trampoline for them. The kdump kernel will register the trampoline addresses, which will then jump up to the real code above 32 MB. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 2 ++ arch/powerpc/platforms/pseries/ras.c | 6 ++---- arch/powerpc/platforms/pseries/setup.c | 18 ++++++++++-------- include/asm-powerpc/firmware.h | 6 ++++++ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 65aedc938a6e..f4194f5fd2e5 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -553,6 +553,7 @@ slb_miss_user_pseries: * Vectors for the FWNMI option. Share common code. */ .globl system_reset_fwnmi + .align 7 system_reset_fwnmi: HMT_MEDIUM mtspr SPRN_SPRG1,r13 /* save r13 */ @@ -560,6 +561,7 @@ system_reset_fwnmi: EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) .globl machine_check_fwnmi + .align 7 machine_check_fwnmi: HMT_MEDIUM mtspr SPRN_SPRG1,r13 /* save r13 */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index fbd214d68b07..49b305f9c152 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -49,14 +49,12 @@ #include #include #include +#include static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); -char mce_data_buf[RTAS_ERROR_LOG_MAX] -; -/* This is true if we are using the firmware NMI handler (typically LPAR) */ -extern int fwnmi_active; +char mce_data_buf[RTAS_ERROR_LOG_MAX]; static int ras_get_sensor_state_token; static int ras_check_exception_token; diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 8828dc378c3e..d678f228fc0f 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -77,8 +77,6 @@ #endif extern void find_udbg_vterm(void); -extern void system_reset_fwnmi(void); /* from head.S */ -extern void machine_check_fwnmi(void); /* from head.S */ int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -104,18 +102,22 @@ void pSeries_show_cpuinfo(struct seq_file *m) /* Initialize firmware assisted non-maskable interrupts if * the firmware supports this feature. - * */ static void __init fwnmi_init(void) { - int ret; + unsigned long system_reset_addr, machine_check_addr; + int ibm_nmi_register = rtas_token("ibm,nmi-register"); if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE) return; - ret = rtas_call(ibm_nmi_register, 2, 1, NULL, - __pa((unsigned long)system_reset_fwnmi), - __pa((unsigned long)machine_check_fwnmi)); - if (ret == 0) + + /* If the kernel's not linked at zero we point the firmware at low + * addresses anyway, and use a trampoline to get to the real code. */ + system_reset_addr = __pa(system_reset_fwnmi) - PHYSICAL_START; + machine_check_addr = __pa(machine_check_fwnmi) - PHYSICAL_START; + + if (0 == rtas_call(ibm_nmi_register, 2, 1, NULL, system_reset_addr, + machine_check_addr)) fwnmi_active = 1; } diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h index 12fabbcb04f0..f804b34cf06a 100644 --- a/include/asm-powerpc/firmware.h +++ b/include/asm-powerpc/firmware.h @@ -98,6 +98,12 @@ typedef struct { extern firmware_feature_t firmware_features_table[]; #endif +extern void system_reset_fwnmi(void); +extern void machine_check_fwnmi(void); + +/* This is true if we are using the firmware NMI handler (typically LPAR) */ +extern int fwnmi_active; + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_FIRMWARE_H */ -- cgit v1.2.3 From 0cc4746cadda16826a1b3214c042a2f75445b71c Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:37 +1100 Subject: [PATCH] powerpc: Reroute interrupts from 0 + offset to PHYSICAL_START + offset Regardless of where the kernel's linked we always get interrupts at low addresses. This patch creates a trampoline in the first 3 pages of memory, where interrupts land, and patches those addresses to jump into the real kernel code at PHYSICAL_START. We also need to reserve the trampoline code and a bit more in prom.c Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 1 + arch/powerpc/kernel/crash_dump.c | 53 ++++++++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/prom.c | 6 ++++- arch/powerpc/kernel/setup_64.c | 5 ++++ include/asm-powerpc/kdump.h | 13 ++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/kernel/crash_dump.c create mode 100644 include/asm-powerpc/kdump.h diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 89714929f444..5719248d344d 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o +obj-$(CONFIG_CRASH_DUMP) += crash_dump.o ifeq ($(CONFIG_PPC_MERGE),y) diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c new file mode 100644 index 000000000000..63919bcfc9fe --- /dev/null +++ b/arch/powerpc/kernel/crash_dump.c @@ -0,0 +1,53 @@ +/* + * Routines for doing kexec-based kdump. + * + * Copyright (C) 2005, IBM Corp. + * + * Created by: Michael Ellerman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#undef DEBUG + +#include +#include +#include + +#ifdef DEBUG +#include +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +static void __init create_trampoline(unsigned long addr) +{ + /* The maximum range of a single instruction branch, is the current + * instruction's address + (32 MB - 4) bytes. For the trampoline we + * need to branch to current address + 32 MB. So we insert a nop at + * the trampoline address, then the next instruction (+ 4 bytes) + * does a branch to (32 MB - 4). The net effect is that when we + * branch to "addr" we jump to ("addr" + 32 MB). Although it requires + * two instructions it doesn't require any registers. + */ + create_instruction(addr, 0x60000000); /* nop */ + create_branch(addr + 4, addr + PHYSICAL_START, 0); +} + +void __init kdump_setup(void) +{ + unsigned long i; + + DBG(" -> kdump_setup()\n"); + + for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) { + create_trampoline(i); + } + + create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); + create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); + + DBG(" <- kdump_setup()\n"); +} diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 3bf968e74095..9aac77ca3167 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1335,11 +1336,14 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_memory, NULL); lmb_enforce_memory_limit(memory_limit); lmb_analyze(); - lmb_reserve(0, __pa(klimit)); DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); /* Reserve LMB regions used by kernel, initrd, dt, etc... */ + lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); +#ifdef CONFIG_CRASH_DUMP + lmb_reserve(0, KDUMP_RESERVE_LIMIT); +#endif early_reserve_mem(); DBG("Scanning CPUs ...\n"); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 6509dd7c2f8f..e67120e34652 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr) } ppc_md = **mach; +#ifdef CONFIG_CRASH_DUMP + kdump_setup(); +#endif + DBG("Found, Initializing memory management...\n"); /* diff --git a/include/asm-powerpc/kdump.h b/include/asm-powerpc/kdump.h new file mode 100644 index 000000000000..a87aed00d61f --- /dev/null +++ b/include/asm-powerpc/kdump.h @@ -0,0 +1,13 @@ +#ifndef _PPC64_KDUMP_H +#define _PPC64_KDUMP_H + +/* How many bytes to reserve at zero for kdump. The reserve limit should + * be greater or equal to the trampoline's end address. */ +#define KDUMP_RESERVE_LIMIT 0x8000 + +#define KDUMP_TRAMPOLINE_START 0x0100 +#define KDUMP_TRAMPOLINE_END 0x3000 + +extern void kdump_setup(void); + +#endif /* __PPC64_KDUMP_H */ -- cgit v1.2.3 From 758438a7b8da593c9116e95cc7fdff6e9e0b0c40 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 5 Dec 2005 15:49:00 -0600 Subject: [PATCH] powerpc: Fixups for kernel linked at 32 MB There's a few places where we need to fix things up for the kernel to work if it's linked at 32MB: - platforms/powermac/smp.c To start secondary cpus on pmac we patch the reset vector, which is fine. Except if we're above 32MB we don't have enough bits for an absolute branch, it needs to relative. - kernel/head_64.s - A few branches in the cpu hold code need to load the full target address and do a bctr. - after_prom_start needs to load PHYSICAL_START as the dest address, not 0. - The exception prolog needs to load the low word of the target adddress, not just the low halfword. - Fixup handling of the initial stab address. - kernel/setup_64.c smp_release_cpus() needs to write 1 to the spinloop flag near 0, not 32 MB. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 30 ++++++++++++++++++++++++------ arch/powerpc/kernel/setup_64.c | 5 ++++- arch/powerpc/platforms/powermac/smp.c | 16 +++++++--------- include/asm-powerpc/mmu.h | 3 ++- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index f4194f5fd2e5..0763dd632b78 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -154,11 +154,15 @@ _GLOBAL(__secondary_hold) bne 100b #ifdef CONFIG_HMT - b .hmt_init + LOADADDR(r4, .hmt_init) + mtctr r4 + bctr #else #ifdef CONFIG_SMP + LOADADDR(r4, .pSeries_secondary_smp_init) + mtctr r4 mr r3,r24 - b .pSeries_secondary_smp_init + bctr #else BUG_OPCODE #endif @@ -200,6 +204,20 @@ exception_marker: #define EX_R3 64 #define EX_LR 72 +/* + * We're short on space and time in the exception prolog, so we can't use + * the normal LOADADDR macro. Normally we just need the low halfword of the + * address, but for Kdump we need the whole low word. + */ +#ifdef CONFIG_CRASH_DUMP +#define LOAD_HANDLER(reg, label) \ + oris reg,reg,(label)@h; /* virt addr of handler ... */ \ + ori reg,reg,(label)@l; /* .. and the rest */ +#else +#define LOAD_HANDLER(reg, label) \ + ori reg,reg,(label)@l; /* virt addr of handler ... */ +#endif + #define EXCEPTION_PROLOG_PSERIES(area, label) \ mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ @@ -212,7 +230,7 @@ exception_marker: clrrdi r12,r13,32; /* get high part of &label */ \ mfmsr r10; \ mfspr r11,SPRN_SRR0; /* save SRR0 */ \ - ori r12,r12,(label)@l; /* virt addr of handler */ \ + LOAD_HANDLER(r12,label) \ ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ mtspr SPRN_SRR0,r12; \ mfspr r12,SPRN_SRR1; /* and SRR1 */ \ @@ -1348,7 +1366,7 @@ _GLOBAL(do_stab_bolted) * fixed address (the linker can't compute (u64)&initial_stab >> * PAGE_SHIFT). */ - . = STAB0_PHYS_ADDR /* 0x6000 */ + . = STAB0_OFFSET /* 0x6000 */ .globl initial_stab initial_stab: .space 4096 @@ -1553,7 +1571,7 @@ _STATIC(__boot_from_prom) _STATIC(__after_prom_start) /* - * We need to run with __start at physical address 0. + * We need to run with __start at physical address PHYSICAL_START. * This will leave some code in the first 256B of * real memory, which are reserved for software use. * The remainder of the first page is loaded with the fixed @@ -1568,7 +1586,7 @@ _STATIC(__after_prom_start) mr r26,r3 SET_REG_TO_CONST(r27,KERNELBASE) - li r3,0 /* target addr */ + LOADADDR(r3, PHYSICAL_START) /* target addr */ // XXX FIXME: Use phys returned by OF (r30) add r4,r27,r26 /* source addr */ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e67120e34652..419e0b974b96 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -322,6 +322,7 @@ void early_setup_secondary(void) void smp_release_cpus(void) { extern unsigned long __secondary_hold_spinloop; + unsigned long *ptr; DBG(" -> smp_release_cpus()\n"); @@ -332,7 +333,9 @@ void smp_release_cpus(void) * This is useless but harmless on iSeries, secondaries are already * waiting on their paca spinloops. */ - __secondary_hold_spinloop = 1; + ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop + - PHYSICAL_START); + *ptr = 1; mb(); DBG(" <- smp_release_cpus()\n"); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index fb2a7c798e82..862f1e985c19 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -753,14 +753,15 @@ static int __init smp_core99_probe(void) static void __devinit smp_core99_kick_cpu(int nr) { unsigned int save_vector; - unsigned long new_vector; - unsigned long flags; + unsigned long target, flags; volatile unsigned int *vector = ((volatile unsigned int *)(KERNELBASE+0x100)); if (nr < 0 || nr > 3) return; - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); + + if (ppc_md.progress) + ppc_md.progress("smp_core99_kick_cpu", 0x346); local_irq_save(flags); local_irq_disable(); @@ -768,14 +769,11 @@ static void __devinit smp_core99_kick_cpu(int nr) /* Save reset vector */ save_vector = *vector; - /* Setup fake reset vector that does + /* Setup fake reset vector that does * b __secondary_start_pmac_0 + nr*8 - KERNELBASE */ - new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; - *vector = 0x48000002 + new_vector - KERNELBASE; - - /* flush data cache and inval instruction cache */ - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + target = (unsigned long) __secondary_start_pmac_0 + nr * 8; + create_branch((unsigned long)vector, target, BRANCH_SET_LINK); /* Put some life in our friend */ pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 29613500c2c2..0a7323f0083b 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -33,7 +33,8 @@ /* Location of cpu0's segment table */ #define STAB0_PAGE 0x6 -#define STAB0_PHYS_ADDR (STAB0_PAGE<<12) +#define STAB0_OFFSET (STAB0_PAGE << 12) +#define STAB0_PHYS_ADDR (STAB0_OFFSET + PHYSICAL_START) #ifndef __ASSEMBLY__ extern char initial_stab[]; -- cgit v1.2.3 From cc53291521701f9c7c7265bbb3c140563174d8b2 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:43 +1100 Subject: [PATCH] powerpc: Add arch dependent basic infrastructure for Kdump. Implementing the machine_crash_shutdown which will be called by crash_kexec (called in case of a panic, sysrq etc.). Disable the interrupts, shootdown cpus using debugger IPI and collect regs for all CPUs. elfcorehdr= specifies the location of elf core header stored by the crashed kernel. This command line option will be passed by the kexec-tools to capture kernel. savemaxmem= specifies the actual memory size that the first kernel has and this value will be used for dumping in the capture kernel. This command line option will be passed by the kexec-tools to capture kernel. Signed-off-by: Haren Myneni Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/crash.c | 264 ++++++++++++++++++++++++++++++++ arch/powerpc/kernel/crash_dump.c | 20 +++ arch/powerpc/kernel/machine_kexec_64.c | 13 +- arch/powerpc/kernel/smp.c | 22 ++- arch/powerpc/kernel/traps.c | 17 +- arch/powerpc/platforms/cell/setup.c | 1 + arch/powerpc/platforms/maple/setup.c | 1 + arch/powerpc/platforms/powermac/setup.c | 1 + arch/powerpc/platforms/pseries/setup.c | 1 + arch/powerpc/platforms/pseries/xics.c | 2 +- include/asm-powerpc/kexec.h | 10 +- 12 files changed, 345 insertions(+), 9 deletions(-) create mode 100644 arch/powerpc/kernel/crash.c diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 5719248d344d..5bdc5faac713 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -66,7 +66,7 @@ pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \ obj-$(CONFIG_PCI) += $(pci64-y) kexec-$(CONFIG_PPC64) := machine_kexec_64.o kexec-$(CONFIG_PPC32) := machine_kexec_32.o -obj-$(CONFIG_KEXEC) += machine_kexec.o $(kexec-y) +obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) ifeq ($(CONFIG_PPC_ISERIES),y) $(obj)/head_64.o: $(obj)/lparmap.s diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c new file mode 100644 index 000000000000..4681155121ef --- /dev/null +++ b/arch/powerpc/kernel/crash.c @@ -0,0 +1,264 @@ +/* + * Architecture specific (PPC64) functions for kexec based crash dumps. + * + * Copyright (C) 2005, IBM Corp. + * + * Created by: Haren Myneni + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + * + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* This keeps a track of which one is crashing cpu. */ +int crashing_cpu = -1; + +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, + size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) +3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +static void crash_save_this_cpu(struct pt_regs *regs, int cpu) +{ + struct elf_prstatus prstatus; + u32 *buf; + + if ((cpu < 0) || (cpu >= NR_CPUS)) + return; + + /* Using ELF notes here is opportunistic. + * I need a well defined structure format + * for the data I pass, and I need tags + * on the data to indicate what information I have + * squirrelled away. ELF notes happen to provide + * all of that that no need to invent something new. + */ + buf = &crash_notes[cpu][0]; + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + elf_core_copy_regs(&prstatus.pr_reg, regs); + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} + +/* FIXME Merge this with xmon_save_regs ?? */ +static inline void crash_get_current_regs(struct pt_regs *regs) +{ + unsigned long tmp1, tmp2; + + __asm__ __volatile__ ( + "std 0,0(%2)\n" + "std 1,8(%2)\n" + "std 2,16(%2)\n" + "std 3,24(%2)\n" + "std 4,32(%2)\n" + "std 5,40(%2)\n" + "std 6,48(%2)\n" + "std 7,56(%2)\n" + "std 8,64(%2)\n" + "std 9,72(%2)\n" + "std 10,80(%2)\n" + "std 11,88(%2)\n" + "std 12,96(%2)\n" + "std 13,104(%2)\n" + "std 14,112(%2)\n" + "std 15,120(%2)\n" + "std 16,128(%2)\n" + "std 17,136(%2)\n" + "std 18,144(%2)\n" + "std 19,152(%2)\n" + "std 20,160(%2)\n" + "std 21,168(%2)\n" + "std 22,176(%2)\n" + "std 23,184(%2)\n" + "std 24,192(%2)\n" + "std 25,200(%2)\n" + "std 26,208(%2)\n" + "std 27,216(%2)\n" + "std 28,224(%2)\n" + "std 29,232(%2)\n" + "std 30,240(%2)\n" + "std 31,248(%2)\n" + "mfmsr %0\n" + "std %0, 264(%2)\n" + "mfctr %0\n" + "std %0, 280(%2)\n" + "mflr %0\n" + "std %0, 288(%2)\n" + "bl 1f\n" + "1: mflr %1\n" + "std %1, 256(%2)\n" + "mtlr %0\n" + "mfxer %0\n" + "std %0, 296(%2)\n" + : "=&r" (tmp1), "=&r" (tmp2) + : "b" (regs)); +} + +/* We may have saved_regs from where the error came from + * or it is NULL if via a direct panic(). + */ +static void crash_save_self(struct pt_regs *saved_regs) +{ + struct pt_regs regs; + int cpu; + + cpu = smp_processor_id(); + if (saved_regs) + memcpy(®s, saved_regs, sizeof(regs)); + else + crash_get_current_regs(®s); + crash_save_this_cpu(®s, cpu); +} + +#ifdef CONFIG_SMP +static atomic_t waiting_for_crash_ipi; + +void crash_ipi_callback(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + if (cpu == crashing_cpu) + return; + + if (!cpu_online(cpu)) + return; + + if (ppc_md.kexec_cpu_down) + ppc_md.kexec_cpu_down(1, 1); + + local_irq_disable(); + + crash_save_this_cpu(regs, cpu); + atomic_dec(&waiting_for_crash_ipi); + kexec_smp_wait(); + /* NOTREACHED */ +} + +static void crash_kexec_prepare_cpus(void) +{ + unsigned int msecs; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + + crash_send_ipi(crash_ipi_callback); + smp_wmb(); + + /* + * FIXME: Until we will have the way to stop other CPUSs reliabally, + * the crash CPU will send an IPI and wait for other CPUs to + * respond. If not, proceed the kexec boot even though we failed to + * capture other CPU states. + */ + msecs = 1000000; + while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) { + barrier(); + mdelay(1); + } + + /* Would it be better to replace the trap vector here? */ + + /* + * FIXME: In case if we do not get all CPUs, one possibility: ask the + * user to do soft reset such that we get all. + * IPI handler is already set by the panic cpu initially. Therefore, + * all cpus could invoke this handler from die() and the panic CPU + * will call machine_kexec() directly from this handler to do + * kexec boot. + */ + if (atomic_read(&waiting_for_crash_ipi)) + printk(KERN_ALERT "done waiting: %d cpus not responding\n", + atomic_read(&waiting_for_crash_ipi)); + /* Leave the IPI callback set */ +} +#else +static void crash_kexec_prepare_cpus(void) +{ + /* + * move the secondarys to us so that we can copy + * the new kernel 0-0x100 safely + * + * do this if kexec in setup.c ? + */ + smp_release_cpus(); +} + +#endif + +void default_machine_crash_shutdown(struct pt_regs *regs) +{ + /* + * This function is only called after the system + * has paniced or is otherwise in a critical state. + * The minimum amount of code to allow a kexec'd kernel + * to run successfully needs to happen here. + * + * In practice this means stopping other cpus in + * an SMP system. + * The kernel is broken so disable interrupts. + */ + local_irq_disable(); + + if (ppc_md.kexec_cpu_down) + ppc_md.kexec_cpu_down(1, 0); + + /* + * Make a note of crashing cpu. Will be used in machine_kexec + * such that another IPI will not be sent. + */ + crashing_cpu = smp_processor_id(); + crash_kexec_prepare_cpus(); + crash_save_self(regs); +} diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 63919bcfc9fe..5337ab759780 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -11,6 +11,8 @@ #undef DEBUG +#include +#include #include #include #include @@ -51,3 +53,21 @@ void __init kdump_setup(void) DBG(" <- kdump_setup()\n"); } + +static int __init parse_elfcorehdr(char *p) +{ + if (p) + elfcorehdr_addr = memparse(p, &p); + + return 0; +} +__setup("elfcorehdr=", parse_elfcorehdr); + +static int __init parse_savemaxmem(char *p) +{ + if (p) + saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; + + return 0; +} +__setup("savemaxmem=", parse_savemaxmem); diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 0b0fa4768995..d6431440c54f 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -265,11 +265,18 @@ extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, /* too late to fail here */ void default_machine_kexec(struct kimage *image) { - /* prepare control code if any */ - /* shutdown other cpus into our wait loop and quiesce interrupts */ - kexec_prepare_cpus(); + /* + * If the kexec boot is the normal one, need to shutdown other cpus + * into our wait loop and quiesce interrupts. + * Otherwise, in the case of crashed mode (crashing_cpu >= 0), + * stopping other CPUs and collecting their pt_regs is done before + * using debugger IPI. + */ + + if (crashing_cpu == -1) + kexec_prepare_cpus(); /* switch to a staticly allocated stack. Based on irq stack code. * XXX: the task struct will likely be invalid once we do the copy! diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index a90df6bf0940..8e3ca674d359 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -75,6 +75,8 @@ void smp_call_function_interrupt(void); int smt_enabled_at_boot = 1; +static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; + #ifdef CONFIG_MPIC int __init smp_mpic_probe(void) { @@ -123,11 +125,16 @@ void smp_message_recv(int msg, struct pt_regs *regs) /* XXX Do we have to do this? */ set_need_resched(); break; -#ifdef CONFIG_DEBUGGER case PPC_MSG_DEBUGGER_BREAK: + if (crash_ipi_function_ptr) { + crash_ipi_function_ptr(regs); + break; + } +#ifdef CONFIG_DEBUGGER debugger_ipi(regs); break; -#endif +#endif /* CONFIG_DEBUGGER */ + /* FALLTHROUGH */ default: printk("SMP %d: smp_message_recv(): unknown msg %d\n", smp_processor_id(), msg); @@ -147,6 +154,17 @@ void smp_send_debugger_break(int cpu) } #endif +#ifdef CONFIG_KEXEC +void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) +{ + crash_ipi_function_ptr = crash_ipi_callback; + if (crash_ipi_callback) { + mb(); + smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK); + } +} +#endif + static void stop_this_cpu(void *dummy) { local_irq_disable(); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 1511454c4690..76b579ca5230 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -95,7 +96,7 @@ static DEFINE_SPINLOCK(die_lock); int die(const char *str, struct pt_regs *regs, long err) { - static int die_counter; + static int die_counter, crash_dump_start = 0; int nl = 0; if (debugger(regs)) @@ -156,7 +157,21 @@ int die(const char *str, struct pt_regs *regs, long err) print_modules(); show_regs(regs); bust_spinlocks(0); + + if (!crash_dump_start && kexec_should_crash(current)) { + crash_dump_start = 1; + spin_unlock_irq(&die_lock); + crash_kexec(regs); + /* NOTREACHED */ + } spin_unlock_irq(&die_lock); + if (crash_dump_start) + /* + * Only for soft-reset: Other CPUs will be responded to an IPI + * sent by first kexec CPU. + */ + for(;;) + ; if (in_interrupt()) panic("Fatal exception in interrupt"); diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 25e0f68d0531..56273e56cbfb 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -217,5 +217,6 @@ struct machdep_calls __initdata cell_md = { #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, #endif }; diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 8724e031e965..65fe4c166a68 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -282,5 +282,6 @@ struct machdep_calls __initdata maple_md = { #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, #endif }; diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 6ee620fe5195..c0638e47c298 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -771,6 +771,7 @@ struct machdep_calls __initdata pmac_md = { #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, #endif #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC32 diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index d678f228fc0f..2cb082871210 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -629,5 +629,6 @@ struct machdep_calls __initdata pSeries_md = { .kexec_cpu_down = pseries_kexec_cpu_down, .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, + .machine_crash_shutdown = default_machine_crash_shutdown, #endif }; diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 0377decc0719..0c0cfa32eb58 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -407,7 +407,7 @@ irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) smp_message_recv(PPC_MSG_MIGRATE_TASK, regs); } #endif -#ifdef CONFIG_DEBUGGER +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, &xics_ipi_message[cpu].value)) { mb(); diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h index 934b4981651d..ae76ed5d973f 100644 --- a/include/asm-powerpc/kexec.h +++ b/include/asm-powerpc/kexec.h @@ -32,6 +32,8 @@ #ifndef __ASSEMBLY__ +#ifdef CONFIG_KEXEC + #define MAX_NOTE_BYTES 1024 typedef u32 note_buf_t[MAX_NOTE_BYTES / sizeof(u32)]; @@ -41,11 +43,17 @@ extern note_buf_t crash_notes[]; extern void kexec_smp_wait(void); /* get and clear naca physid, wait for master to copy new code to 0 */ extern void __init kexec_setup(void); -#endif +extern int crashing_cpu; +extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)); +#endif /* __powerpc64 __ */ struct kimage; +struct pt_regs; extern void default_machine_kexec(struct kimage *image); extern int default_machine_kexec_prepare(struct kimage *image); +extern void default_machine_crash_shutdown(struct pt_regs *regs); + +#endif /* !CONFIG_KEXEC */ #endif /* ! __ASSEMBLY__ */ #endif /* _ASM_POWERPC_KEXEC_H */ -- cgit v1.2.3 From dcee30361d25ea83499a99f921f9a56b4a1a79e7 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:48 +1100 Subject: [PATCH] powerpc: Parse crashkernel= parameter in first kernel This patch adds code to parse and setup the crash kernel resource in the first kernel. PPC64 ignores the @x part, we always run at 32 MB. Signed-off-by: Haren Myneni Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 11 +++++++++ arch/powerpc/kernel/prom_init.c | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 9aac77ca3167..fddc9c13bff5 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1198,6 +1199,16 @@ static int __init early_init_dt_scan_chosen(unsigned long node, } #endif /* CONFIG_PPC_RTAS */ +#ifdef CONFIG_KEXEC + lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL); + if (lprop) + crashk_res.start = *lprop; + + lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL); + if (lprop) + crashk_res.end = crashk_res.start + *lprop - 1; +#endif + /* break now */ return 1; } diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 369e1a6cdd40..2ae860c306d7 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -192,6 +192,11 @@ static unsigned long __initdata alloc_bottom; static unsigned long __initdata rmo_top; static unsigned long __initdata ram_top; +#ifdef CONFIG_KEXEC +static unsigned long __initdata prom_crashk_base; +static unsigned long __initdata prom_crashk_size; +#endif + static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; static int __initdata mem_reserve_cnt; @@ -590,6 +595,34 @@ static void __init early_cmdline_parse(void) RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000); #endif } + +#ifdef CONFIG_KEXEC + /* + * crashkernel=size@addr specifies the location to reserve for + * crash kernel. + */ + opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel=")); + if (opt) { + opt += 12; + RELOC(prom_crashk_size) = prom_memparse(opt, &opt); + + if (ALIGN(RELOC(prom_crashk_size), 0x1000000) != + RELOC(prom_crashk_size)) { + prom_printf("Warning: crashkernel size is not " + "aligned to 16MB\n"); + } + + /* + * At present, the crash kernel always run at 32MB. + * Just ignore whatever user passed. + */ + RELOC(prom_crashk_base) = 0x2000000; + if (*opt == '@') { + prom_printf("Warning: PPC64 kdump kernel always runs " + "at 32 MB\n"); + } + } +#endif } #ifdef CONFIG_PPC_PSERIES @@ -1011,6 +1044,12 @@ static void __init prom_init_mem(void) prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); prom_printf(" ram_top : %x\n", RELOC(ram_top)); +#ifdef CONFIG_KEXEC + if (RELOC(prom_crashk_base)) { + prom_printf(" crashk_base : %x\n", RELOC(prom_crashk_base)); + prom_printf(" crashk_size : %x\n", RELOC(prom_crashk_size)); + } +#endif } @@ -2094,6 +2133,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_init_mem(); +#ifdef CONFIG_KEXEC + if (RELOC(prom_crashk_base)) + reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size)); +#endif /* * Determine which cpu is actually running right _now_ */ @@ -2150,6 +2193,16 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, } #endif +#ifdef CONFIG_KEXEC + if (RELOC(prom_crashk_base)) { + prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base", + PTRRELOC(&prom_crashk_base), + sizeof(RELOC(prom_crashk_base))); + prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size", + PTRRELOC(&prom_crashk_size), + sizeof(RELOC(prom_crashk_size))); + } +#endif /* * Fixup any known bugs in the device-tree */ -- cgit v1.2.3 From 54c32021eb6feafc32e90104e960b38301521b7b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:51 +1100 Subject: [PATCH] powerpc: Add arch-dependent copy_oldmem_page Signed-off-by: Haren Myneni Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/crash_dump.c | 36 ++++++++++++++++++++++++++++++++++++ include/asm-powerpc/kexec.h | 2 ++ kernel/crash_dump.c | 3 +++ 3 files changed, 41 insertions(+) diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 5337ab759780..87effa3f21a7 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef DEBUG #include @@ -71,3 +72,38 @@ static int __init parse_savemaxmem(char *p) return 0; } __setup("savemaxmem=", parse_savemaxmem); + +/* + * copy_oldmem_page - copy one page from "oldmem" + * @pfn: page frame number to be copied + * @buf: target memory address for the copy; this can be in kernel address + * space or user address space (see @userbuf) + * @csize: number of bytes to copy + * @offset: offset in bytes into the page (based on pfn) to begin the copy + * @userbuf: if set, @buf is in user address space, use copy_to_user(), + * otherwise @buf is in kernel address space, use memcpy(). + * + * Copy a page from "oldmem". For this page, there is no pte mapped + * in the current kernel. We stitch up a pte, similar to kmap_atomic. + */ +ssize_t copy_oldmem_page(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +{ + void *vaddr; + + if (!csize) + return 0; + + vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0); + + if (userbuf) { + if (copy_to_user((char __user *)buf, (vaddr + offset), csize)) { + iounmap(vaddr); + return -EFAULT; + } + } else + memcpy(buf, (vaddr + offset), csize); + + iounmap(vaddr); + return csize; +} diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h index ae76ed5d973f..c0f6d6b0d935 100644 --- a/include/asm-powerpc/kexec.h +++ b/include/asm-powerpc/kexec.h @@ -30,6 +30,8 @@ #define KEXEC_ARCH KEXEC_ARCH_PPC #endif +#define HAVE_ARCH_COPY_OLDMEM_PAGE + #ifndef __ASSEMBLY__ #ifdef CONFIG_KEXEC diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c index 334c37f5218a..fccb27dbc623 100644 --- a/kernel/crash_dump.c +++ b/kernel/crash_dump.c @@ -14,10 +14,12 @@ #include #include +#include /* Stores the physical address of elf header of crash image. */ unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; +#ifndef HAVE_ARCH_COPY_OLDMEM_PAGE /** * copy_oldmem_page - copy one page from "oldmem" * @pfn: page frame number to be copied @@ -59,3 +61,4 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, kfree(page); return csize; } +#endif -- cgit v1.2.3 From ba7594852f4e7121b3f037d59f983637b795f0dd Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 4 Dec 2005 18:39:55 +1100 Subject: [PATCH] powerpc: Add support for "linux,usable-memory" on memory nodes Milton has proposed that we should support a "linux,usable-memory" property on memory nodes which describes, in preference to "reg", the regions of memory Linux should use. This facility is required for kdump to inform the second kernel which memory it should use. Signed-off-by: Haren Myneni Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 9 +++++++-- arch/powerpc/mm/numa.c | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index fddc9c13bff5..7e798d5b03b4 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -567,7 +567,10 @@ static int __init interpret_root_props(struct device_node *np, unsigned int *rp; int rpsize = (naddrc + nsizec) * sizeof(unsigned int); - rp = (unsigned int *) get_property(np, "reg", &l); + rp = (unsigned int *) get_property(np, "linux,usable-memory", &l); + if (rp == NULL) + rp = (unsigned int *) get_property(np, "reg", &l); + if (rp != 0 && l >= rpsize) { i = 0; adr = (struct address_range *) (*mem_start); @@ -1275,7 +1278,9 @@ static int __init early_init_dt_scan_memory(unsigned long node, } else if (strcmp(type, "memory") != 0) return 0; - reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); + reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); + if (reg == NULL) + reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); if (reg == NULL) return 0; diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 40c99deb691b..97e83f1d1bdb 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -423,7 +423,12 @@ static int __init parse_numa_properties(void) unsigned int *memcell_buf; unsigned int len; - memcell_buf = (unsigned int *)get_property(memory, "reg", &len); + memcell_buf = (unsigned int *)get_property(memory, + "linux,usable-memory", &len); + if (!memcell_buf || len <= 0) + memcell_buf = + (unsigned int *)get_property(memory, "reg", + &len); if (!memcell_buf || len <= 0) continue; -- cgit v1.2.3 From 39c73c332c8264c0a3a1ce58aa3eae52d17af025 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:21 -0500 Subject: [PATCH] spufs: Make all exports GPL-only This changes all exported symbols of spufs to EXPORT_SYMBOL_GPL. The spu_ibox_read/spu_wbox_write symbols are not exported any more when the scheduler patch is applied. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 408c455cff08..b71313ae7526 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -399,7 +399,7 @@ struct spu *spu_alloc(void) return spu; } -EXPORT_SYMBOL(spu_alloc); +EXPORT_SYMBOL_GPL(spu_alloc); void spu_free(struct spu *spu) { @@ -407,7 +407,7 @@ void spu_free(struct spu *spu) list_add_tail(&spu->list, &spu_list); up(&spu_mutex); } -EXPORT_SYMBOL(spu_free); +EXPORT_SYMBOL_GPL(spu_free); static int spu_handle_mm_fault(struct spu *spu) { @@ -576,7 +576,7 @@ int spu_run(struct spu *spu) return ret; } -EXPORT_SYMBOL(spu_run); +EXPORT_SYMBOL_GPL(spu_run); static void __iomem * __init map_spe_prop(struct device_node *n, const char *name) -- cgit v1.2.3 From d88cfffac0002c56c1a7a813cb885fa6b5fdcd0e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:22 -0500 Subject: [PATCH] spufs: fix local store page refcounting With the new rules for reserved pages, the spufs now needs working page reference counting. I should probably look into converting to vm_insert_page, but for now this patch makes spufs work again. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/setup.c | 2 +- arch/powerpc/platforms/cell/spufs/file.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 56273e56cbfb..c41a6e2e2c30 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -114,7 +114,7 @@ static void __init cell_spuprop_present(struct device_node *spe, for (pfn = start_pfn; pfn < end_pfn; pfn++) { struct page *page = pfn_to_page(pfn); set_page_links(page, ZONE_DMA, node_id, pfn); - set_page_count(page, 0); + set_page_count(page, 1); reset_page_mapcount(page); SetPageReserved(page); INIT_LIST_HEAD(&page->lru); diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 786fdb1a1cc1..0fe1feccc02d 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,7 @@ spufs_mem_mmap_nopage(struct vm_area_struct *vma, if (type) *type = VM_FAULT_MINOR; + page_cache_get(page); return page; } @@ -120,7 +122,6 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; /* FIXME: */ - vma->vm_flags |= VM_RESERVED; vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | _PAGE_NO_CACHE); -- cgit v1.2.3 From b41305a39a6966d8e8b1449d6b7c194923bfb451 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:23 -0500 Subject: [PATCH] spufs: Fix oops when spufs module is not loaded try_module_get returns true when NULL arguments, so we first need to check if there is a module loaded before getting the reference count. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_syscalls.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 43e0b187ffde..91d564df944e 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -37,11 +37,12 @@ asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, mode_t mode) { long ret; + struct module *owner = spufs_calls.owner; ret = -ENOSYS; - if (try_module_get(spufs_calls.owner)) { + if (owner && try_module_get(spufs_calls.owner)) { ret = spufs_calls.create_thread(name, flags, mode); - module_put(spufs_calls.owner); + module_put(owner); } return ret; } @@ -51,16 +52,17 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) long ret; struct file *filp; int fput_needed; + struct module *owner = spufs_calls.owner; ret = -ENOSYS; - if (try_module_get(spufs_calls.owner)) { + if (owner && try_module_get(owner)) { ret = -EBADF; filp = fget_light(fd, &fput_needed); if (filp) { ret = spufs_calls.spu_run(filp, unpc, ustatus); fput_light(filp, fput_needed); } - module_put(spufs_calls.owner); + module_put(owner); } return ret; } -- cgit v1.2.3 From 3b3d22cb84a0bb12f6bbb2b1158972894bec3f21 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:24 -0500 Subject: [PATCH] spufs: Turn off debugging output spufs is rather noisy when debugging is enabled, this turns off the messages for production use. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 2 +- arch/powerpc/platforms/cell/spufs/sched.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index b71313ae7526..167580ce8691 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -20,7 +20,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define DEBUG 1 +#undef DEBUG #include #include diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index c0d9d83a9ac3..575027062b0b 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -24,7 +24,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define DEBUG 1 +#undef DEBUG + #include #include #include -- cgit v1.2.3 From 5110459f181ef1f11200bb3dec61953f08cc49e7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:25 -0500 Subject: [PATCH] spufs: Improved SPU preemptability. This patch makes it easier to preempt an SPU context by having the scheduler hold ctx->state_sema for much shorter periods of time. As part of this restructuring, the control logic for the "run" operation is moved from arch/ppc64/kernel/spu_base.c to fs/spufs/file.c. Of course the base retains "bottom half" handlers for class{0,1} irqs. The new run loop will re-acquire an SPU if preempted. From: Mark Nutter Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 93 +++---------------- arch/powerpc/platforms/cell/spufs/backing_ops.c | 19 ++++ arch/powerpc/platforms/cell/spufs/context.c | 5 +- arch/powerpc/platforms/cell/spufs/file.c | 117 ++++++++++++++++++++++-- arch/powerpc/platforms/cell/spufs/hw_ops.c | 17 ++++ arch/powerpc/platforms/cell/spufs/sched.c | 67 ++++++++------ arch/powerpc/platforms/cell/spufs/spufs.h | 5 + include/asm-powerpc/spu.h | 5 +- 8 files changed, 205 insertions(+), 123 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 167580ce8691..8abd4bd19665 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -130,7 +130,8 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) spu->dar = ea; spu->dsisr = dsisr; mb(); - wake_up(&spu->stop_wq); + if (spu->stop_callback) + spu->stop_callback(spu); return 0; } @@ -151,7 +152,8 @@ static int __spu_trap_stop(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); spu->stop_code = in_be32(&spu->problem->spu_status_R); - wake_up(&spu->stop_wq); + if (spu->stop_callback) + spu->stop_callback(spu); return 0; } @@ -159,7 +161,8 @@ static int __spu_trap_halt(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); spu->stop_code = in_be32(&spu->problem->spu_status_R); - wake_up(&spu->stop_wq); + if (spu->stop_callback) + spu->stop_callback(spu); return 0; } @@ -190,12 +193,13 @@ spu_irq_class_0(int irq, void *data, struct pt_regs *regs) spu = data; spu->class_0_pending = 1; - wake_up(&spu->stop_wq); + if (spu->stop_callback) + spu->stop_callback(spu); return IRQ_HANDLED; } -static int +int spu_irq_class_0_bottom(struct spu *spu) { unsigned long stat; @@ -214,8 +218,10 @@ spu_irq_class_0_bottom(struct spu *spu) __spu_trap_error(spu); out_be64(&spu->priv1->int_stat_class0_RW, stat); - return 0; + + return (stat & 0x7) ? -EIO : 0; } +EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom); static irqreturn_t spu_irq_class_1(int irq, void *data, struct pt_regs *regs) @@ -250,6 +256,7 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) return stat ? IRQ_HANDLED : IRQ_NONE; } +EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom); static irqreturn_t spu_irq_class_2(int irq, void *data, struct pt_regs *regs) @@ -478,7 +485,7 @@ bad_area: return -EFAULT; } -static int spu_handle_pte_fault(struct spu *spu) +int spu_irq_class_1_bottom(struct spu *spu) { u64 ea, dsisr, access, error = 0UL; int ret = 0; @@ -508,76 +515,6 @@ static int spu_handle_pte_fault(struct spu *spu) return ret; } -static inline int spu_pending(struct spu *spu, u32 * stat) -{ - struct spu_problem __iomem *prob = spu->problem; - u64 pte_fault; - - *stat = in_be32(&prob->spu_status_R); - pte_fault = spu->dsisr & - (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); - return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; -} - -int spu_run(struct spu *spu) -{ - struct spu_problem __iomem *prob; - struct spu_priv1 __iomem *priv1; - struct spu_priv2 __iomem *priv2; - u32 status; - int ret; - - prob = spu->problem; - priv1 = spu->priv1; - priv2 = spu->priv2; - - /* Let SPU run. */ - eieio(); - out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); - - do { - ret = wait_event_interruptible(spu->stop_wq, - spu_pending(spu, &status)); - - if (spu->dsisr & - (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) - ret = spu_handle_pte_fault(spu); - - if (spu->class_0_pending) - spu_irq_class_0_bottom(spu); - - if (!ret && signal_pending(current)) - ret = -ERESTARTSYS; - - } while (!ret && !(status & - (SPU_STATUS_STOPPED_BY_STOP | - SPU_STATUS_STOPPED_BY_HALT))); - - /* Ensure SPU is stopped. */ - out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); - eieio(); - while (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) - cpu_relax(); - - out_be64(&priv2->slb_invalidate_all_W, 0); - out_be64(&priv1->tlb_invalidate_entry_W, 0UL); - eieio(); - - /* Check for SPU breakpoint. */ - if (unlikely(current->ptrace & PT_PTRACED)) { - status = in_be32(&prob->spu_status_R); - - if ((status & SPU_STATUS_STOPPED_BY_STOP) - && status >> SPU_STOP_STATUS_SHIFT == 0x3fff) { - force_sig(SIGTRAP, current); - ret = -ERESTARTSYS; - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(spu_run); - static void __iomem * __init map_spe_prop(struct device_node *n, const char *name) { @@ -693,9 +630,9 @@ static int __init create_spu(struct device_node *spe) out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); out_be64(&spu->priv1->mfc_sr1_RW, 0x33); - init_waitqueue_head(&spu->stop_wq); spu->ibox_callback = NULL; spu->wbox_callback = NULL; + spu->stop_callback = NULL; down(&spu_mutex); spu->number = number++; diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index caf0984064e2..66567c109965 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -232,6 +232,23 @@ static char *spu_backing_get_ls(struct spu_context *ctx) return ctx->csa.lscsa->ls; } +static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val) +{ + spin_lock(&ctx->csa.register_lock); + ctx->csa.prob.spu_runcntl_RW = val; + if (val & SPU_RUNCNTL_RUNNABLE) { + ctx->csa.prob.spu_status_R |= SPU_STATUS_RUNNING; + } else { + ctx->csa.prob.spu_status_R &= ~SPU_STATUS_RUNNING; + } + spin_unlock(&ctx->csa.register_lock); +} + +static void spu_backing_runcntl_stop(struct spu_context *ctx) +{ + spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP); +} + struct spu_context_ops spu_backing_ops = { .mbox_read = spu_backing_mbox_read, .mbox_stat_read = spu_backing_mbox_stat_read, @@ -249,4 +266,6 @@ struct spu_context_ops spu_backing_ops = { .npc_write = spu_backing_npc_write, .status_read = spu_backing_status_read, .get_ls = spu_backing_get_ls, + .runcntl_write = spu_backing_runcntl_write, + .runcntl_stop = spu_backing_runcntl_stop, }; diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 5d6195fc107d..0d88a1c24f67 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -45,6 +45,7 @@ struct spu_context *alloc_spu_context(struct address_space *local_store) init_rwsem(&ctx->state_sema); init_waitqueue_head(&ctx->ibox_wq); init_waitqueue_head(&ctx->wbox_wq); + init_waitqueue_head(&ctx->stop_wq); ctx->ibox_fasync = NULL; ctx->wbox_fasync = NULL; ctx->state = SPU_STATE_SAVED; @@ -105,7 +106,7 @@ void spu_release(struct spu_context *ctx) up_read(&ctx->state_sema); } -static void spu_unmap_mappings(struct spu_context *ctx) +void spu_unmap_mappings(struct spu_context *ctx) { unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); } @@ -126,7 +127,6 @@ int spu_acquire_runnable(struct spu_context *ctx) down_write(&ctx->state_sema); if (ctx->state == SPU_STATE_SAVED) { - spu_unmap_mappings(ctx); ret = spu_activate(ctx, 0); ctx->state = SPU_STATE_RUNNABLE; } @@ -154,7 +154,6 @@ void spu_acquire_saved(struct spu_context *ctx) down_write(&ctx->state_sema); if (ctx->state == SPU_STATE_RUNNABLE) { - spu_unmap_mappings(ctx); spu_deactivate(ctx); ctx->state = SPU_STATE_SAVED; } diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 0fe1feccc02d..af5adc372224 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -540,26 +541,122 @@ static struct file_operations spufs_wbox_stat_fops = { .read = spufs_wbox_stat_read, }; -long spufs_run_spu(struct file *file, struct spu_context *ctx, - u32 *npc, u32 *status) +/* interrupt-level stop callback function. */ +void spufs_stop_callback(struct spu *spu) +{ + struct spu_context *ctx = spu->ctx; + + wake_up_all(&ctx->stop_wq); +} + +static inline int spu_stopped(struct spu_context *ctx, u32 * stat) +{ + struct spu *spu; + u64 pte_fault; + + *stat = ctx->ops->status_read(ctx); + if (ctx->state != SPU_STATE_RUNNABLE) + return 1; + spu = ctx->spu; + pte_fault = spu->dsisr & + (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); + return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; +} + +static inline int spu_run_init(struct spu_context *ctx, u32 * npc, + u32 * status) { int ret; - ret = spu_acquire_runnable(ctx); - if (ret) + if ((ret = spu_acquire_runnable(ctx)) != 0) return ret; - ctx->ops->npc_write(ctx, *npc); + ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); + return 0; +} - ret = spu_run(ctx->spu); - - if (!ret) - ret = ctx->ops->status_read(ctx); +static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, + u32 * status) +{ + int ret = 0; + *status = ctx->ops->status_read(ctx); *npc = ctx->ops->npc_read(ctx); - spu_release(ctx); + + if (signal_pending(current)) + ret = -ERESTARTSYS; + if (unlikely(current->ptrace & PT_PTRACED)) { + if ((*status & SPU_STATUS_STOPPED_BY_STOP) + && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { + force_sig(SIGTRAP, current); + ret = -ERESTARTSYS; + } + } + return ret; +} + +static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, + u32 *status) +{ + int ret; + + if ((ret = spu_run_fini(ctx, npc, status)) != 0) + return ret; + if (*status & (SPU_STATUS_STOPPED_BY_STOP | + SPU_STATUS_STOPPED_BY_HALT)) { + return *status; + } + if ((ret = spu_run_init(ctx, npc, status)) != 0) + return ret; + return 0; +} + +static inline int spu_process_events(struct spu_context *ctx) +{ + struct spu *spu = ctx->spu; + u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; + int ret = 0; + + if (spu->dsisr & pte_fault) + ret = spu_irq_class_1_bottom(spu); + if (spu->class_0_pending) + ret = spu_irq_class_0_bottom(spu); + if (!ret && signal_pending(current)) + ret = -ERESTARTSYS; + return ret; +} + +long spufs_run_spu(struct file *file, struct spu_context *ctx, + u32 * npc, u32 * status) +{ + int ret; + + if ((ret = spu_run_init(ctx, npc, status)) != 0) + return ret; + + do { + ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); + if (unlikely(ret)) + break; + if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { + ret = spu_reacquire_runnable(ctx, npc, status); + if (ret) { + return ret; + } + continue; + } + ret = spu_process_events(ctx); + + } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | + SPU_STATUS_STOPPED_BY_HALT))); + + ctx->ops->runcntl_stop(ctx); + ret = spu_run_fini(ctx, npc, status); + if (!ret) + ret = *status; spu_yield(ctx); + return ret; } diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index 2e90cae98a87..68812415ee29 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -186,6 +186,21 @@ static char *spu_hw_get_ls(struct spu_context *ctx) return ctx->spu->local_store; } +static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val) +{ + eieio(); + out_be32(&ctx->spu->problem->spu_runcntl_RW, val); +} + +static void spu_hw_runcntl_stop(struct spu_context *ctx) +{ + spin_lock_irq(&ctx->spu->register_lock); + out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP); + while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING) + cpu_relax(); + spin_unlock_irq(&ctx->spu->register_lock); +} + struct spu_context_ops spu_hw_ops = { .mbox_read = spu_hw_mbox_read, .mbox_stat_read = spu_hw_mbox_stat_read, @@ -203,4 +218,6 @@ struct spu_context_ops spu_hw_ops = { .npc_write = spu_hw_npc_write, .status_read = spu_hw_status_read, .get_ls = spu_hw_get_ls, + .runcntl_write = spu_hw_runcntl_write, + .runcntl_stop = spu_hw_runcntl_stop, }; diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 575027062b0b..e2f10b5b8a6a 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -119,7 +119,8 @@ static void prio_wakeup(struct spu_runqueue *rq) } } -static void prio_wait(struct spu_runqueue *rq, u64 flags) +static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx, + u64 flags) { int prio = current->prio; wait_queue_head_t *wq = &rq->prio.waitq[prio]; @@ -130,9 +131,11 @@ static void prio_wait(struct spu_runqueue *rq, u64 flags) prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE); if (!signal_pending(current)) { up(&rq->sem); + up_write(&ctx->state_sema); pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__, current->pid, current->prio); schedule(); + down_write(&ctx->state_sema); down(&rq->sem); } finish_wait(wq, &wait); @@ -173,7 +176,9 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) mm_needs_global_tlbie(spu->mm); spu->ibox_callback = spufs_ibox_callback; spu->wbox_callback = spufs_wbox_callback; + spu->stop_callback = spufs_stop_callback; mb(); + spu_unmap_mappings(ctx); spu_restore(&ctx->csa, spu); } @@ -181,10 +186,12 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) { pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__, spu->pid, spu->number); + spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); ctx->state = SPU_STATE_SAVED; spu->ibox_callback = NULL; spu->wbox_callback = NULL; + spu->stop_callback = NULL; spu->mm = NULL; spu->pid = 0; spu->prio = MAX_PRIO; @@ -196,37 +203,35 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) static struct spu *preempt_active(struct spu_runqueue *rq) { struct list_head *p; - struct spu_context *ctx; - struct spu *spu; + struct spu *worst, *spu; - /* Future: implement real preemption. For now just - * boot a lower priority ctx that is in "detached" - * state, i.e. on a processor but not currently in - * spu_run(). - */ + worst = list_entry(rq->active_list.next, struct spu, sched_list); list_for_each(p, &rq->active_list) { spu = list_entry(p, struct spu, sched_list); - if (current->prio < spu->prio) { - ctx = spu->ctx; - if (down_write_trylock(&ctx->state_sema)) { - if (ctx->state != SPU_STATE_RUNNABLE) { - up_write(&ctx->state_sema); - continue; - } - pr_debug("%s: booting pid=%d from SPU %d\n", - __FUNCTION__, spu->pid, spu->number); - del_active(rq, spu); - up(&rq->sem); - unbind_context(spu, ctx); - up_write(&ctx->state_sema); - return spu; - } + if (spu->prio > worst->prio) { + worst = spu; + } + } + if (current->prio < worst->prio) { + struct spu_context *ctx = worst->ctx; + + spu = worst; + if (down_write_trylock(&ctx->state_sema)) { + pr_debug("%s: booting pid=%d from SPU %d\n", + __FUNCTION__, spu->pid, spu->number); + del_active(rq, spu); + up(&rq->sem); + wake_up_all(&ctx->stop_wq); + ctx->ops->runcntl_stop(ctx); + unbind_context(spu, ctx); + up_write(&ctx->state_sema); + return spu; } } return NULL; } -static struct spu *get_idle_spu(u64 flags) +static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags) { struct spu_runqueue *rq; struct spu *spu = NULL; @@ -255,7 +260,7 @@ static struct spu *get_idle_spu(u64 flags) if ((spu = preempt_active(rq)) != NULL) return spu; } - prio_wait(rq, flags); + prio_wait(rq, ctx, flags); if (signal_pending(current)) { prio_wakeup(rq); spu = NULL; @@ -322,7 +327,7 @@ int spu_activate(struct spu_context *ctx, u64 flags) if (ctx->spu) return 0; - spu = get_idle_spu(flags); + spu = get_idle_spu(ctx, flags); if (!spu) return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN; bind_context(spu, ctx); @@ -347,17 +352,19 @@ void spu_deactivate(struct spu_context *ctx) void spu_yield(struct spu_context *ctx) { struct spu *spu; + int need_yield = 0; - if (!down_write_trylock(&ctx->state_sema)) - return; + down_write(&ctx->state_sema); spu = ctx->spu; - if ((ctx->state == SPU_STATE_RUNNABLE) && - (sched_find_first_bit(spu->rq->prio.bitmap) <= current->prio)) { + if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) { pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number); spu_deactivate(ctx); ctx->state = SPU_STATE_SAVED; + need_yield = 1; } up_write(&ctx->state_sema); + if (unlikely(need_yield)) + yield(); } int __init spu_sched_init(void) diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 93c6a0537562..20f4e51d1069 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -51,6 +51,7 @@ struct spu_context { struct kref kref; wait_queue_head_t ibox_wq; wait_queue_head_t wbox_wq; + wait_queue_head_t stop_wq; struct fasync_struct *ibox_fasync; struct fasync_struct *wbox_fasync; struct spu_context_ops *ops; @@ -74,6 +75,8 @@ struct spu_context_ops { void (*npc_write) (struct spu_context * ctx, u32 data); u32(*status_read) (struct spu_context * ctx); char*(*get_ls) (struct spu_context * ctx); + void (*runcntl_write) (struct spu_context * ctx, u32 data); + void (*runcntl_stop) (struct spu_context * ctx); }; extern struct spu_context_ops spu_hw_ops; @@ -99,6 +102,7 @@ struct spu_context * alloc_spu_context(struct address_space *local_store); void destroy_spu_context(struct kref *kref); struct spu_context * get_spu_context(struct spu_context *ctx); int put_spu_context(struct spu_context *ctx); +void spu_unmap_mappings(struct spu_context *ctx); void spu_forget(struct spu_context *ctx); void spu_acquire(struct spu_context *ctx); @@ -118,5 +122,6 @@ size_t spu_ibox_read(struct spu_context *ctx, u32 *data); /* irq callback funcs. */ void spufs_ibox_callback(struct spu *spu); void spufs_wbox_callback(struct spu *spu); +void spufs_stop_callback(struct spu *spu); #endif diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 092ec97be326..dd91ed8563d2 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -135,9 +135,9 @@ struct spu { spinlock_t register_lock; u32 stop_code; - wait_queue_head_t stop_wq; void (* wbox_callback)(struct spu *spu); void (* ibox_callback)(struct spu *spu); + void (* stop_callback)(struct spu *spu); char irq_c0[8]; char irq_c1[8]; @@ -146,7 +146,8 @@ struct spu { struct spu *spu_alloc(void); void spu_free(struct spu *spu); -int spu_run(struct spu *spu); +int spu_irq_class_0_bottom(struct spu *spu); +int spu_irq_class_1_bottom(struct spu *spu); extern struct spufs_calls { asmlinkage long (*create_thread)(const char __user *name, -- cgit v1.2.3 From 2a911f0bb73e67826062b7d073dd7367ca449724 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:26 -0500 Subject: [PATCH] spufs: Improved SPU preemptability [part 2]. This patch reduces lock complexity of SPU scheduler, particularly for involuntary preemptive switches. As a result the new code does a better job of mapping the highest priority tasks to SPUs. Lock complexity is reduced by using the system default workqueue to perform involuntary saves. In this way we avoid nasty lock ordering problems that the previous code had. A "minimum timeslice" for SPU contexts is also introduced. The intent here is to avoid thrashing. While the new scheduler does a better job at prioritization it still does nothing for fairness. From: Mark Nutter Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 4 +- arch/powerpc/platforms/cell/spufs/sched.c | 81 ++++++++++++++++++++--------- arch/powerpc/platforms/cell/spufs/spufs.h | 5 ++ include/asm-powerpc/spu.h | 1 + 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 0d88a1c24f67..1758cec58bc7 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -116,8 +116,10 @@ int spu_acquire_runnable(struct spu_context *ctx) int ret = 0; down_read(&ctx->state_sema); - if (ctx->state == SPU_STATE_RUNNABLE) + if (ctx->state == SPU_STATE_RUNNABLE) { + ctx->spu->prio = current->prio; return 0; + } /* ctx is about to be freed, can't acquire any more */ if (!ctx->owner) { ret = -EINVAL; diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index e2f10b5b8a6a..fccc7709adbe 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -45,6 +45,8 @@ #include #include "spufs.h" +#define SPU_MIN_TIMESLICE (100 * HZ / 1000)) + #define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) struct spu_prio_array { atomic_t nr_blocked; @@ -168,6 +170,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) spu->number); spu->ctx = ctx; spu->flags = 0; + ctx->flags = 0; ctx->spu = spu; ctx->ops = &spu_hw_ops; spu->pid = current->pid; @@ -180,6 +183,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) mb(); spu_unmap_mappings(ctx); spu_restore(&ctx->csa, spu); + spu->timestamp = jiffies; } static inline void unbind_context(struct spu *spu, struct spu_context *ctx) @@ -188,6 +192,7 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) spu->pid, spu->number); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); + spu->timestamp = jiffies; ctx->state = SPU_STATE_SAVED; spu->ibox_callback = NULL; spu->wbox_callback = NULL; @@ -197,38 +202,62 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) spu->prio = MAX_PRIO; ctx->ops = &spu_backing_ops; ctx->spu = NULL; + ctx->flags = 0; + spu->flags = 0; spu->ctx = NULL; } -static struct spu *preempt_active(struct spu_runqueue *rq) +static void spu_reaper(void *data) { - struct list_head *p; - struct spu *worst, *spu; + struct spu_context *ctx = data; + struct spu *spu; - worst = list_entry(rq->active_list.next, struct spu, sched_list); - list_for_each(p, &rq->active_list) { - spu = list_entry(p, struct spu, sched_list); - if (spu->prio > worst->prio) { - worst = spu; + down_write(&ctx->state_sema); + spu = ctx->spu; + if (spu && (ctx->flags & SPU_CONTEXT_PREEMPT)) { + if (atomic_read(&spu->rq->prio.nr_blocked)) { + pr_debug("%s: spu=%d\n", __func__, spu->number); + ctx->ops->runcntl_stop(ctx); + spu_deactivate(ctx); + wake_up_all(&ctx->stop_wq); + } else { + clear_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags); } } - if (current->prio < worst->prio) { - struct spu_context *ctx = worst->ctx; + up_write(&ctx->state_sema); + put_spu_context(ctx); +} - spu = worst; - if (down_write_trylock(&ctx->state_sema)) { - pr_debug("%s: booting pid=%d from SPU %d\n", - __FUNCTION__, spu->pid, spu->number); - del_active(rq, spu); - up(&rq->sem); - wake_up_all(&ctx->stop_wq); - ctx->ops->runcntl_stop(ctx); - unbind_context(spu, ctx); - up_write(&ctx->state_sema); - return spu; +static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu) +{ + struct spu_context *ctx = get_spu_context(spu->ctx); + unsigned long now = jiffies; + unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE; + + set_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags); + INIT_WORK(&ctx->reap_work, spu_reaper, ctx); + if (time_after(now, expire)) + schedule_work(&ctx->reap_work); + else + schedule_delayed_work(&ctx->reap_work, expire - now); +} + +static void check_preempt_active(struct spu_runqueue *rq) +{ + struct list_head *p; + struct spu *worst = NULL; + + list_for_each(p, &rq->active_list) { + struct spu *spu = list_entry(p, struct spu, sched_list); + struct spu_context *ctx = spu->ctx; + if (!(ctx->flags & SPU_CONTEXT_PREEMPT)) { + if (!worst || (spu->prio > worst->prio)) { + worst = spu; + } } } - return NULL; + if (worst && (current->prio < worst->prio)) + schedule_spu_reaper(rq, worst); } static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags) @@ -256,10 +285,7 @@ static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags) continue; } } else { - if (is_best_prio(rq)) { - if ((spu = preempt_active(rq)) != NULL) - return spu; - } + check_preempt_active(rq); prio_wait(rq, ctx, flags); if (signal_pending(current)) { prio_wakeup(rq); @@ -361,6 +387,8 @@ void spu_yield(struct spu_context *ctx) spu_deactivate(ctx); ctx->state = SPU_STATE_SAVED; need_yield = 1; + } else if (spu) { + spu->prio = MAX_PRIO; } up_write(&ctx->state_sema); if (unlikely(need_yield)) @@ -399,6 +427,7 @@ int __init spu_sched_init(void) pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number); add_idle(rq, spu); spu->rq = rq; + spu->timestamp = jiffies; } if (!rq->nr_idle) { printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 20f4e51d1069..5bb75f22f722 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -37,6 +37,9 @@ enum { struct spu_context_ops; +#define SPU_CONTEXT_PREEMPT_nr 0UL +#define SPU_CONTEXT_PREEMPT (1UL << SPU_CONTEXT_PREEMPT_nr) + struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ @@ -55,6 +58,8 @@ struct spu_context { struct fasync_struct *ibox_fasync; struct fasync_struct *wbox_fasync; struct spu_context_ops *ops; + struct work_struct reap_work; + u64 flags; }; /* SPU context query/set operations. */ diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index dd91ed8563d2..698c4cb08c60 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -129,6 +129,7 @@ struct spu { struct mm_struct *mm; struct spu_context *ctx; struct spu_runqueue *rq; + unsigned long long timestamp; pid_t pid; int prio; int class_0_pending; -- cgit v1.2.3 From 3a843d7cd30ab6815610d9d6aa66b56df0ee1228 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:27 -0500 Subject: [PATCH] spufs: fix mailbox polling Handling mailbox interrupts was broken in multiple respects, the combination of which was hiding the bugs most of the time. - The ibox interrupt mask was open initially even though there are no waiters on a newly created SPU. - Acknowledging the mailbox interrupt did not work because it is level triggered and the mailbox data is never retrieved from inside the interrupt handler. - The interrupt handler delivered interrupts with a disabled mask if another interrupt is triggered for the same class but a different mask. - The poll function did not enable the interrupt if it had not been enabled, so we might run into the poll timeout if none of the other bugs saved us and no signal was delivered. We probably still have a similar problem with blocking read/write on mailbox files, but that will result in extra wakeup in the worst case, not in incorrect behaviour. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 11 +++++-- arch/powerpc/platforms/cell/spufs/backing_ops.c | 37 ++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/file.c | 24 ++++----------- arch/powerpc/platforms/cell/spufs/hw_ops.c | 41 ++++++++++++++++++++++++- arch/powerpc/platforms/cell/spufs/spufs.h | 2 ++ arch/powerpc/platforms/cell/spufs/switch.c | 4 +-- 6 files changed, 95 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 8abd4bd19665..f9da79eb3db0 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -202,12 +202,15 @@ spu_irq_class_0(int irq, void *data, struct pt_regs *regs) int spu_irq_class_0_bottom(struct spu *spu) { - unsigned long stat; + unsigned long stat, mask; spu->class_0_pending = 0; + mask = in_be64(&spu->priv1->int_mask_class0_RW); stat = in_be64(&spu->priv1->int_stat_class0_RW); + stat &= mask; + if (stat & 1) /* invalid MFC DMA */ __spu_trap_invalid_dma(spu); @@ -263,13 +266,15 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs) { struct spu *spu; unsigned long stat; + unsigned long mask; spu = data; stat = in_be64(&spu->priv1->int_stat_class2_RW); + mask = in_be64(&spu->priv1->int_mask_class2_RW); - pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, - in_be64(&spu->priv1->int_mask_class2_RW)); + pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); + stat &= mask; if (stat & 1) /* PPC core mailbox */ __spu_trap_mailbox(spu); diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index 66567c109965..a5c489a53c61 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,41 @@ static u32 spu_backing_mbox_stat_read(struct spu_context *ctx) return ctx->csa.prob.mb_stat_R; } +static unsigned int spu_backing_mbox_stat_poll(struct spu_context *ctx, + unsigned int events) +{ + int ret; + u32 stat; + + ret = 0; + spin_lock_irq(&ctx->csa.register_lock); + stat = ctx->csa.prob.mb_stat_R; + + /* if the requested event is there, return the poll + mask, otherwise enable the interrupt to get notified, + but first mark any pending interrupts as done so + we don't get woken up unnecessarily */ + + if (events & (POLLIN | POLLRDNORM)) { + if (stat & 0xff0000) + ret |= POLLIN | POLLRDNORM; + else { + ctx->csa.priv1.int_stat_class0_RW &= ~0x1; + ctx->csa.priv1.int_mask_class2_RW |= 0x1; + } + } + if (events & (POLLOUT | POLLWRNORM)) { + if (stat & 0x00ff00) + ret = POLLOUT | POLLWRNORM; + else { + ctx->csa.priv1.int_stat_class0_RW &= ~0x10; + ctx->csa.priv1.int_mask_class2_RW |= 0x10; + } + } + spin_unlock_irq(&ctx->csa.register_lock); + return ret; +} + static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data) { int ret; @@ -252,6 +288,7 @@ static void spu_backing_runcntl_stop(struct spu_context *ctx) struct spu_context_ops spu_backing_ops = { .mbox_read = spu_backing_mbox_read, .mbox_stat_read = spu_backing_mbox_stat_read, + .mbox_stat_poll = spu_backing_mbox_stat_poll, .ibox_read = spu_backing_ibox_read, .wbox_write = spu_backing_wbox_write, .signal1_read = spu_backing_signal1_read, diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index af5adc372224..9738de727f32 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -389,20 +389,13 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf, static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) { struct spu_context *ctx = file->private_data; - u32 mbox_stat; unsigned int mask; - spu_acquire(ctx); - - mbox_stat = ctx->ops->mbox_stat_read(ctx); - - spu_release(ctx); - poll_wait(file, &ctx->ibox_wq, wait); - mask = 0; - if (mbox_stat & 0xff0000) - mask |= POLLIN | POLLRDNORM; + spu_acquire(ctx); + mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); + spu_release(ctx); return mask; } @@ -494,18 +487,13 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) { struct spu_context *ctx = file->private_data; - u32 mbox_stat; unsigned int mask; - spu_acquire(ctx); - mbox_stat = ctx->ops->mbox_stat_read(ctx); - spu_release(ctx); - poll_wait(file, &ctx->wbox_wq, wait); - mask = 0; - if (mbox_stat & 0x00ff00) - mask = POLLOUT | POLLWRNORM; + spu_acquire(ctx); + mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); + spu_release(ctx); return mask; } diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index 68812415ee29..9a53e29f9d7e 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,6 +58,44 @@ static u32 spu_hw_mbox_stat_read(struct spu_context *ctx) return in_be32(&ctx->spu->problem->mb_stat_R); } +static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx, + unsigned int events) +{ + struct spu *spu = ctx->spu; + struct spu_priv1 __iomem *priv1 = spu->priv1; + int ret = 0; + u32 stat; + + spin_lock_irq(&spu->register_lock); + stat = in_be32(&spu->problem->mb_stat_R); + + /* if the requested event is there, return the poll + mask, otherwise enable the interrupt to get notified, + but first mark any pending interrupts as done so + we don't get woken up unnecessarily */ + + if (events & (POLLIN | POLLRDNORM)) { + if (stat & 0xff0000) + ret |= POLLIN | POLLRDNORM; + else { + out_be64(&priv1->int_stat_class2_RW, 0x1); + out_be64(&priv1->int_mask_class2_RW, + in_be64(&priv1->int_mask_class2_RW) | 0x1); + } + } + if (events & (POLLOUT | POLLWRNORM)) { + if (stat & 0x00ff00) + ret = POLLOUT | POLLWRNORM; + else { + out_be64(&priv1->int_stat_class2_RW, 0x10); + out_be64(&priv1->int_mask_class2_RW, + in_be64(&priv1->int_mask_class2_RW) | 0x10); + } + } + spin_unlock_irq(&spu->register_lock); + return ret; +} + static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data) { struct spu *spu = ctx->spu; @@ -204,6 +242,7 @@ static void spu_hw_runcntl_stop(struct spu_context *ctx) struct spu_context_ops spu_hw_ops = { .mbox_read = spu_hw_mbox_read, .mbox_stat_read = spu_hw_mbox_stat_read, + .mbox_stat_poll = spu_hw_mbox_stat_poll, .ibox_read = spu_hw_ibox_read, .wbox_write = spu_hw_wbox_write, .signal1_read = spu_hw_signal1_read, diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 5bb75f22f722..17cae5e5fdf5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -66,6 +66,8 @@ struct spu_context { struct spu_context_ops { int (*mbox_read) (struct spu_context * ctx, u32 * data); u32(*mbox_stat_read) (struct spu_context * ctx); + unsigned int (*mbox_stat_poll)(struct spu_context *ctx, + unsigned int events); int (*ibox_read) (struct spu_context * ctx, u32 * data); int (*wbox_write) (struct spu_context * ctx, u32 data); u32(*signal1_read) (struct spu_context * ctx); diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 51266257b0a5..010a9fe55ef8 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -2155,8 +2155,8 @@ static void init_priv1(struct spu_state *csa) CLASS0_ENABLE_SPU_ERROR_INTR; csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | CLASS1_ENABLE_STORAGE_FAULT_INTR; - csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_MAILBOX_INTR | - CLASS2_ENABLE_SPU_STOP_INTR | CLASS2_ENABLE_SPU_HALT_INTR; + csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR | + CLASS2_ENABLE_SPU_HALT_INTR; } static void init_priv2(struct spu_state *csa) -- cgit v1.2.3 From dad482c25698134b79c80694c81f0495019e0842 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 5 Dec 2005 22:52:29 -0500 Subject: [PATCH] cell: add platform detection code I can't really get a conclusive answer from the firmware people what to check for, so I just try scanning for anything that starts with "IBM,CPB", which should be correct for all hardware produced so far and for systemsim. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 2ae860c306d7..6007d51d119b 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -1539,6 +1539,8 @@ static int __init prom_find_machine_type(void) #ifdef CONFIG_PPC64 if (strstr(p, RELOC("Momentum,Maple"))) return PLATFORM_MAPLE; + if (strstr(p, RELOC("IBM,CPB"))) + return PLATFORM_CELL; #endif i += sl + 1; } -- cgit v1.2.3 From a819f8ba76e81669fcc2665ac532cac650694b99 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 9 Dec 2005 11:57:44 -0600 Subject: [PATCH] ppc32: Add TQM85xx (8540/8541/8555/8560) board support This patch adds support for the TQ Components TQM85xx modules. Currently the modules TQM8540/8541/8555/8560 are supported. Signed-off-by: Stefan Roese Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/configs/TQM8540_defconfig | 973 ++++++++++++++++++++++++++++++++++++ arch/ppc/configs/TQM8541_defconfig | 986 ++++++++++++++++++++++++++++++++++++ arch/ppc/configs/TQM8555_defconfig | 983 ++++++++++++++++++++++++++++++++++++ arch/ppc/configs/TQM8560_defconfig | 992 +++++++++++++++++++++++++++++++++++++ arch/ppc/platforms/85xx/Kconfig | 28 +- arch/ppc/platforms/85xx/Makefile | 4 + arch/ppc/platforms/85xx/tqm85xx.c | 419 ++++++++++++++++ arch/ppc/platforms/85xx/tqm85xx.h | 56 +++ include/asm-ppc/mpc85xx.h | 4 + 9 files changed, 4441 insertions(+), 4 deletions(-) create mode 100644 arch/ppc/configs/TQM8540_defconfig create mode 100644 arch/ppc/configs/TQM8541_defconfig create mode 100644 arch/ppc/configs/TQM8555_defconfig create mode 100644 arch/ppc/configs/TQM8560_defconfig create mode 100644 arch/ppc/platforms/85xx/tqm85xx.c create mode 100644 arch/ppc/platforms/85xx/tqm85xx.h diff --git a/arch/ppc/configs/TQM8540_defconfig b/arch/ppc/configs/TQM8540_defconfig new file mode 100644 index 000000000000..99bf3b7a2762 --- /dev/null +++ b/arch/ppc/configs/TQM8540_defconfig @@ -0,0 +1,973 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.15-rc2 +# Fri Nov 25 17:26:50 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_LBD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor +# +# CONFIG_6xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +CONFIG_MATH_EMULATION=y +# CONFIG_KEXEC is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_PPC_GEN550=y +CONFIG_85xx=y +CONFIG_PPC_INDIRECT_PCI_BE=y + +# +# Freescale 85xx options +# +# CONFIG_MPC8540_ADS is not set +# CONFIG_MPC8548_CDS is not set +# CONFIG_MPC8555_CDS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_SBC8560 is not set +# CONFIG_STX_GP3 is not set +CONFIG_TQM8540=y +# CONFIG_TQM8541 is not set +# CONFIG_TQM8555 is not set +# CONFIG_TQM8560 is not set +CONFIG_MPC8540=y + +# +# Platform options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_PPC_I8259=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_LEGACY_PROC is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_AMDSTD_RETRY=0 +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_TQM85xx=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=y +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +CONFIG_SENSORS_LM75=y +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_HWMON_DEBUG_CHIP=y + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/configs/TQM8541_defconfig b/arch/ppc/configs/TQM8541_defconfig new file mode 100644 index 000000000000..0ff56695d349 --- /dev/null +++ b/arch/ppc/configs/TQM8541_defconfig @@ -0,0 +1,986 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.15-rc2 +# Wed Nov 30 13:36:28 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_LBD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor +# +# CONFIG_6xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +CONFIG_MATH_EMULATION=y +# CONFIG_KEXEC is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_PPC_GEN550=y +CONFIG_85xx=y +CONFIG_PPC_INDIRECT_PCI_BE=y + +# +# Freescale 85xx options +# +# CONFIG_MPC8540_ADS is not set +# CONFIG_MPC8548_CDS is not set +# CONFIG_MPC8555_CDS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_SBC8560 is not set +# CONFIG_STX_GP3 is not set +# CONFIG_TQM8540 is not set +CONFIG_TQM8541=y +# CONFIG_TQM8555 is not set +# CONFIG_TQM8560 is not set +CONFIG_MPC8555=y + +# +# Platform options +# +CONFIG_CPM2=y +# CONFIG_PC_KEYBOARD is not set +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_PPC_I8259=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_LEGACY_PROC is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_AMDSTD_RETRY=0 +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_TQM85xx=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_FS_ENET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_CPM is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_MPC8260 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=y +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_MAX6900 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8563 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +CONFIG_SENSORS_LM75=y +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_HWMON_DEBUG_CHIP=y + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set +# CONFIG_SCC_ENET is not set +# CONFIG_FEC_ENET is not set + +# +# CPM2 Options +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_KGDB_CONSOLE is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/configs/TQM8555_defconfig b/arch/ppc/configs/TQM8555_defconfig new file mode 100644 index 000000000000..730b3db2e47a --- /dev/null +++ b/arch/ppc/configs/TQM8555_defconfig @@ -0,0 +1,983 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.15-rc2 +# Thu Nov 24 17:10:52 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_LBD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor +# +# CONFIG_6xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +CONFIG_MATH_EMULATION=y +# CONFIG_KEXEC is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_PPC_GEN550=y +CONFIG_85xx=y +CONFIG_PPC_INDIRECT_PCI_BE=y + +# +# Freescale 85xx options +# +# CONFIG_MPC8540_ADS is not set +# CONFIG_MPC8548_CDS is not set +# CONFIG_MPC8555_CDS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_SBC8560 is not set +# CONFIG_STX_GP3 is not set +# CONFIG_TQM8540 is not set +# CONFIG_TQM8541 is not set +CONFIG_TQM8555=y +# CONFIG_TQM8560 is not set +CONFIG_MPC8555=y + +# +# Platform options +# +CONFIG_CPM2=y +# CONFIG_PC_KEYBOARD is not set +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_PPC_I8259=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_LEGACY_PROC is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_AMDSTD_RETRY=0 +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_TQM85xx=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_FS_ENET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_CPM is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=y +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +CONFIG_SENSORS_LM75=y +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_HWMON_DEBUG_CHIP=y + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set +# CONFIG_SCC_ENET is not set +# CONFIG_FEC_ENET is not set + +# +# CPM2 Options +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_KGDB_CONSOLE is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/configs/TQM8560_defconfig b/arch/ppc/configs/TQM8560_defconfig new file mode 100644 index 000000000000..1d902072825e --- /dev/null +++ b/arch/ppc/configs/TQM8560_defconfig @@ -0,0 +1,992 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.15-rc2 +# Wed Nov 30 16:47:53 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block layer +# +# CONFIG_LBD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Processor +# +# CONFIG_6xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +CONFIG_E500=y +CONFIG_BOOKE=y +CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set +CONFIG_SPE=y +CONFIG_MATH_EMULATION=y +# CONFIG_KEXEC is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_WANT_EARLY_SERIAL is not set +CONFIG_85xx=y +CONFIG_PPC_INDIRECT_PCI_BE=y + +# +# Freescale 85xx options +# +# CONFIG_MPC8540_ADS is not set +# CONFIG_MPC8548_CDS is not set +# CONFIG_MPC8555_CDS is not set +# CONFIG_MPC8560_ADS is not set +# CONFIG_SBC8560 is not set +# CONFIG_STX_GP3 is not set +# CONFIG_TQM8540 is not set +# CONFIG_TQM8541 is not set +# CONFIG_TQM8555 is not set +CONFIG_TQM8560=y +CONFIG_MPC8560=y + +# +# Platform options +# +CONFIG_CPM2=y +# CONFIG_PC_KEYBOARD is not set +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_PPC_I8259=y +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_LEGACY_PROC is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_AMDSTD_RETRY=0 +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_TQM85xx=y +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# OneNAND Flash Device Drivers +# +# CONFIG_MTD_ONENAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +# CONFIG_WINDFARM is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_FS_ENET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +CONFIG_GIANFAR=y +CONFIG_GFAR_NAPI=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_CPM=y +CONFIG_SERIAL_CPM_CONSOLE=y +CONFIG_SERIAL_CPM_SCC1=y +# CONFIG_SERIAL_CPM_SCC2 is not set +# CONFIG_SERIAL_CPM_SCC3 is not set +# CONFIG_SERIAL_CPM_SCC4 is not set +# CONFIG_SERIAL_CPM_SMC1 is not set +# CONFIG_SERIAL_CPM_SMC2 is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_MPC8260 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +CONFIG_SENSORS_DS1337=y +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_MAX6900 is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8563 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +CONFIG_SENSORS_LM75=y +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_HWMON_DEBUG_CHIP=y + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set +# CONFIG_SCC_ENET is not set +# CONFIG_FEC_ENET is not set + +# +# CPM2 Options +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_KGDB_CONSOLE is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig index c5bc2821d991..7ddd331a7145 100644 --- a/arch/ppc/platforms/85xx/Kconfig +++ b/arch/ppc/platforms/85xx/Kconfig @@ -39,7 +39,7 @@ config MPC8560_ADS config SBC8560 bool "WindRiver PowerQUICC III SBC8560" help - This option enables support for the WindRiver PowerQUICC III + This option enables support for the WindRiver PowerQUICC III SBC8560 board. config STX_GP3 @@ -48,6 +48,26 @@ config STX_GP3 This option enables support for the Silicon Turnkey Express GP3 board. +config TQM8540 + bool "TQ Components TQM8540" + help + This option enablese support for the TQ Components TQM8540 board. + +config TQM8541 + bool "TQ Components TQM8541" + help + This option enablese support for the TQ Components TQM8541 board. + +config TQM8555 + bool "TQ Components TQM8555" + help + This option enablese support for the TQ Components TQM8555 board. + +config TQM8560 + bool "TQ Components TQM8560" + help + This option enablese support for the TQ Components TQM8560 board. + endchoice # It's often necessary to know the specific 85xx processor type. @@ -55,7 +75,7 @@ endchoice # don't need to ask more redundant questions. config MPC8540 bool - depends on MPC8540_ADS + depends on MPC8540_ADS || TQM8540 default y config MPC8548 @@ -65,12 +85,12 @@ config MPC8548 config MPC8555 bool - depends on MPC8555_CDS + depends on MPC8555_CDS || TQM8541 || TQM8555 default y config MPC8560 bool - depends on SBC8560 || MPC8560_ADS || STX_GP3 + depends on SBC8560 || MPC8560_ADS || STX_GP3 || TQM8560 default y config 85xx_PCI2 diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile index efdf813108f2..6c4753c144d3 100644 --- a/arch/ppc/platforms/85xx/Makefile +++ b/arch/ppc/platforms/85xx/Makefile @@ -7,3 +7,7 @@ obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o obj-$(CONFIG_SBC8560) += sbc85xx.o sbc8560.o obj-$(CONFIG_STX_GP3) += stx_gp3.o +obj-$(CONFIG_TQM8540) += tqm85xx.o +obj-$(CONFIG_TQM8541) += tqm85xx.o +obj-$(CONFIG_TQM8555) += tqm85xx.o +obj-$(CONFIG_TQM8560) += tqm85xx.o diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c new file mode 100644 index 000000000000..c6dfd8f0f9df --- /dev/null +++ b/arch/ppc/platforms/85xx/tqm85xx.c @@ -0,0 +1,419 @@ +/* + * arch/ppc/platforms/85xx/tqm85xx.c + * + * TQM85xx (40/41/55/60) board specific routines + * + * Copyright (c) 2005 DENX Software Engineering + * Stefan Roese + * + * Based on original work by + * Kumar Gala + * Copyright 2004 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for linux/serial_core.h */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef CONFIG_PCI +unsigned long isa_io_base = 0; +unsigned long isa_mem_base = 0; +#endif + + +extern unsigned long total_memory; /* in mm/init */ + +unsigned char __res[sizeof (bd_t)]; + +/* Internal interrupts are all Level Sensitive, and Positive Polarity */ +static u_char tqm85xx_openpic_initsenses[] __initdata = { + MPC85XX_INTERNAL_IRQ_SENSES, + 0x0, /* External 0: */ + 0x0, /* External 1: */ +#if defined(CONFIG_PCI) + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI INTA */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI INTB */ +#else + 0x0, /* External 2: */ + 0x0, /* External 3: */ +#endif + 0x0, /* External 4: */ + 0x0, /* External 5: */ + 0x0, /* External 6: */ + 0x0, /* External 7: */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: PHY */ + 0x0, /* External 9: */ + 0x0, /* External 10: */ + 0x0, /* External 11: */ +}; + +static const char *GFAR_PHY_0 = "phy0:2"; +static const char *GFAR_PHY_1 = "phy0:1"; +#ifdef CONFIG_MPC8540 +static const char *GFAR_PHY_3 = "phy0:3"; +#endif + +/* ************************************************************************ + * + * Setup the architecture + * + */ +static void __init +tqm85xx_setup_arch(void) +{ + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + struct gianfar_platform_data *pdata; + struct gianfar_mdio_data *mdata; + +#ifdef CONFIG_MPC8560 + cpm2_reset(); +#endif + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + if (ppc_md.progress) + ppc_md.progress("tqm85xx_setup_arch()", 0); + + /* Set loops_per_jiffy to a half-way reasonable value, + for use until calibrate_delay gets called. */ + loops_per_jiffy = freq / HZ; + +#ifdef CONFIG_PCI + /* setup PCI host bridges */ + mpc85xx_setup_hose(); +#endif + +#ifndef CONFIG_MPC8560 +#if defined(CONFIG_SERIAL_8250) + mpc85xx_early_serial_map(); +#endif + +#ifdef CONFIG_SERIAL_TEXT_DEBUG + /* Invalidate the entry we stole earlier the serial ports + * should be properly mapped */ + invalidate_tlbcam_entry(num_tlbcam_entries - 1); +#endif +#endif /* CONFIG_MPC8560 */ + + /* setup the board related info for the MDIO bus */ + mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC85xx_MDIO); + + mdata->irq[0] = MPC85xx_IRQ_EXT8; + mdata->irq[1] = MPC85xx_IRQ_EXT8; + mdata->irq[2] = -1; + mdata->irq[3] = MPC85xx_IRQ_EXT8; + mdata->irq[31] = -1; + mdata->paddr += binfo->bi_immr_base; + + /* setup the board related information for the enet controllers */ + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->bus_id = GFAR_PHY_0; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } + + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->bus_id = GFAR_PHY_1; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } + +#ifdef CONFIG_MPC8540 + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC); + if (pdata) { + pdata->board_flags = 0; + pdata->bus_id = GFAR_PHY_3; + memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6); + } +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif +} + +#ifdef CONFIG_MPC8560 +static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs) +{ + while ((irq = cpm2_get_irq(regs)) >= 0) + __do_IRQ(irq, regs); + return IRQ_HANDLED; +} + +static struct irqaction cpm2_irqaction = { + .handler = cpm2_cascade, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "cpm2_cascade", +}; +#endif /* CONFIG_MPC8560 */ + +void __init +tqm85xx_init_IRQ(void) +{ + bd_t *binfo = (bd_t *) __res; + + /* Determine the Physical Address of the OpenPIC regs */ + phys_addr_t OpenPIC_PAddr = + binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; + OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE); + OpenPIC_InitSenses = tqm85xx_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof (tqm85xx_openpic_initsenses); + + /* Skip reserved space and internal sources */ + openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200); + + /* Map PIC IRQs 0-11 */ + openpic_set_sources(48, 12, OpenPIC_Addr + 0x10000); + + /* we let openpic interrupts starting from an offset, to + * leave space for cascading interrupts underneath. + */ + openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + +#ifdef CONFIG_MPC8560 + /* Setup CPM2 PIC */ + cpm2_init_IRQ(); + + setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction); +#endif /* CONFIG_MPC8560 */ + + return; +} + +int tqm85xx_show_cpuinfo(struct seq_file *m) +{ + uint pvid, svid, phid1; + uint memsize = total_memory; + bd_t *binfo = (bd_t *) __res; + unsigned int freq; + + /* get the core frequency */ + freq = binfo->bi_intfreq; + + pvid = mfspr(SPRN_PVR); + svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: TQ Components\n"); + seq_printf(m, "Machine\t\t: TQM%s\n", cur_ppc_sys_spec->ppc_sys_name); + seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000); + seq_printf(m, "PVR\t\t: 0x%x\n", pvid); + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + /* Display cpu Pll setting */ + phid1 = mfspr(SPRN_HID1); + seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); + + /* Display the amount of memory */ + seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + + return 0; +} + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_DS1337) +extern ulong ds1337_get_rtc_time(void); +extern int ds1337_set_rtc_time(unsigned long nowtime); + +static int __init +tqm85xx_rtc_hookup(void) +{ + struct timespec tv; + + ppc_md.set_rtc_time = ds1337_set_rtc_time; + ppc_md.get_rtc_time = ds1337_get_rtc_time; + + tv.tv_nsec = 0; + tv.tv_sec = (ppc_md.get_rtc_time)(); + do_settimeofday(&tv); + + return 0; +} +late_initcall(tqm85xx_rtc_hookup); +#endif + +#ifdef CONFIG_PCI +/* + * interrupt routing + */ +int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {PIRQA, PIRQB, 0, 0}, + }; + + const long min_idsel = 0x1c, max_idsel = 0x1c, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +int mpc85xx_exclude_device(u_char bus, u_char devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_RAPIDIO +void platform_rio_init(void) +{ + /* 512MB RIO LAW at 0xc0000000 */ + mpc85xx_rio_setup(0xc0000000, 0x20000000); +} +#endif /* CONFIG_RAPIDIO */ + +/* ************************************************************************ */ +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* parse_bootinfo must always be called first */ + parse_bootinfo(find_bootinfo()); + + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *) __res, (void *) (r3 + KERNELBASE), + sizeof (bd_t)); + } + +#if defined(CONFIG_SERIAL_TEXT_DEBUG) && !defined(CONFIG_MPC8560) + { + bd_t *binfo = (bd_t *) __res; + struct uart_port p; + + /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */ + settlbcam(num_tlbcam_entries - 1, binfo->bi_immr_base, + binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET; + p.uartclk = binfo->bi_busfreq; + + gen550_init(0, &p); + + memset(&p, 0, sizeof (p)); + p.iotype = SERIAL_IO_MEM; + p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET; + p.uartclk = binfo->bi_busfreq; + + gen550_init(1, &p); + } +#endif + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *) (r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *) (r6 + KERNELBASE)); + } + + identify_ppc_sys_by_id(mfspr(SPRN_SVR)); + + /* setup the PowerPC module struct */ + ppc_md.setup_arch = tqm85xx_setup_arch; + ppc_md.show_cpuinfo = tqm85xx_show_cpuinfo; + + ppc_md.init_IRQ = tqm85xx_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = mpc85xx_restart; + ppc_md.power_off = mpc85xx_power_off; + ppc_md.halt = mpc85xx_halt; + + ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.calibrate_decr = mpc85xx_calibrate_decr; + +#ifndef CONFIG_MPC8560 +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) + ppc_md.progress = gen550_progress; +#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB) + ppc_md.early_serial_map = mpc85xx_early_serial_map; +#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */ +#endif /* CONFIG_MPC8560 */ + + if (ppc_md.progress) + ppc_md.progress("tqm85xx_init(): exit", 0); + + return; +} diff --git a/arch/ppc/platforms/85xx/tqm85xx.h b/arch/ppc/platforms/85xx/tqm85xx.h new file mode 100644 index 000000000000..3775eb363fde --- /dev/null +++ b/arch/ppc/platforms/85xx/tqm85xx.h @@ -0,0 +1,56 @@ +/* + * arch/ppc/platforms/85xx/tqm85xx.h + * + * TQM85xx (40/41/55/60) board definitions + * + * Copyright (c) 2005 DENX Software Engineering + * Stefan Roese + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MACH_TQM85XX_H +#define __MACH_TQM85XX_H + +#include +#include +#include + +#define BOARD_CCSRBAR ((uint)0xe0000000) +#define CCSRBAR_SIZE ((uint)1024*1024) + +#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) + +#define PCI_CFG_ADDR_OFFSET (0x8000) +#define PCI_CFG_DATA_OFFSET (0x8004) + +/* PCI interrupt controller */ +#define PIRQA MPC85xx_IRQ_EXT2 +#define PIRQB MPC85xx_IRQ_EXT3 + +#define MPC85XX_PCI1_LOWER_IO 0x00000000 +#define MPC85XX_PCI1_UPPER_IO 0x00ffffff + +#define MPC85XX_PCI1_LOWER_MEM 0x80000000 +#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff + +#define MPC85XX_PCI1_IO_BASE 0xe2000000 +#define MPC85XX_PCI1_MEM_OFFSET 0x00000000 + +#define MPC85XX_PCI1_IO_SIZE 0x01000000 + +#define BASE_BAUD 115200 + +extern void mpc85xx_setup_hose(void) __init; +extern void mpc85xx_restart(char *cmd); +extern void mpc85xx_power_off(void); +extern void mpc85xx_halt(void); +extern void mpc85xx_init_IRQ(void) __init; +extern unsigned long mpc85xx_find_end_of_memory(void) __init; +extern void mpc85xx_calibrate_decr(void) __init; + +#endif /* __MACH_TQM85XX_H */ diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index 9d14baea3d71..c8a96aa44fb7 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h @@ -37,6 +37,10 @@ #ifdef CONFIG_STX_GP3 #include #endif +#if defined(CONFIG_TQM8540) || defined(CONFIG_TQM8541) || \ + defined(CONFIG_TQM8555) || defined(CONFIG_TQM8560) +#include +#endif #define _IO_BASE isa_io_base #define _ISA_MEM_BASE isa_mem_base -- cgit v1.2.3 From 59d6d39f30f4460b7e6489831caf7fbfe371941a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Dec 2005 19:04:15 +0100 Subject: [PATCH] spufs: fix module refcount race One of the two users of spufs_calls.owner still has a race when calling try_module_get while the module is removed. This makes it use the correct instance of owner. Noticed by Milton Miller. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_syscalls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 91d564df944e..261b507a901a 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -40,7 +40,7 @@ asmlinkage long sys_spu_create(const char __user *name, struct module *owner = spufs_calls.owner; ret = -ENOSYS; - if (owner && try_module_get(spufs_calls.owner)) { + if (owner && try_module_get(owner)) { ret = spufs_calls.create_thread(name, flags, mode); module_put(owner); } -- cgit v1.2.3 From 7945a4a27d5d914918b7637b055e01abfe05906e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Dec 2005 19:04:16 +0100 Subject: [PATCH] spufs: trivial compile fix One of my last patches contained a broken line from splitting out some other changes, this restores a working version. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index fccc7709adbe..719ff27ce73e 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -45,7 +45,7 @@ #include #include "spufs.h" -#define SPU_MIN_TIMESLICE (100 * HZ / 1000)) +#define SPU_MIN_TIMESLICE (100 * HZ / 1000) #define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) struct spu_prio_array { -- cgit v1.2.3 From 462c853eb574bc7843d9c56e84aca129aaa8e018 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Dec 2005 19:04:17 +0100 Subject: [PATCH] spufs: fix hexdump format Output from hexdump with "%08x" depends on HOST platform's endian. When building linux by cross toolchain, that difference makes errors. Signed-off-by: Masato Noguchi Signed-off-by: Geoff Levand Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index ac86b2596d04..9bfaba8791e3 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -46,7 +46,7 @@ cmd_hexdump = ( \ echo " * Do not edit!" ; \ echo " */" ; \ echo "static unsigned int $*_code[] __page_aligned = {" ; \ - hexdump -v -e '4/4 "0x%08x, " "\n"' $< ; \ + hexdump -v -e '"0x" 4/1 "%02x" "," "\n"' $< ; \ echo "};" ; \ ) > $@ quiet_cmd_hexdump = HEXDUMP $@ -- cgit v1.2.3 From 38307341af3a0be8ec5319756361b51ac29dffc7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Dec 2005 19:04:18 +0100 Subject: [PATCH] spufs: clear dsisr on CLASS1[Mf] exception Because of always clearing DSISR at spu class 1 interrupt handler, kernel may lose Class1[Mf] interrupt. Signed-off-by: Masato Noguchi Signed-off-by: Geoff Levand Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index f9da79eb3db0..3a5302151e09 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -240,7 +240,8 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) stat = in_be64(&spu->priv1->int_stat_class1_RW) & mask; dar = in_be64(&spu->priv1->mfc_dar_RW); dsisr = in_be64(&spu->priv1->mfc_dsisr_RW); - out_be64(&spu->priv1->mfc_dsisr_RW, 0UL); + if (stat & 2) /* mapping fault */ + out_be64(&spu->priv1->mfc_dsisr_RW, 0UL); out_be64(&spu->priv1->int_stat_class1_RW, stat); spin_unlock(&spu->register_lock); -- cgit v1.2.3 From 49d65b3ac5614431041abcd2eabc0d77eff5e32d Mon Sep 17 00:00:00 2001 From: "Jens.Osterkamp@de.ibm.com" Date: Fri, 9 Dec 2005 19:04:20 +0100 Subject: [PATCH] powerpc/cell: add iommu support for larger memory So far, the iommu code was hardwired to a linear mapping between 0x20000000 and 0x40000000, so it could only support 512MB of RAM. This patch still keeps the linear mapping, but looks for proper ibm,dma-window properties to set up larger windows, this makes the maximum supported RAM size 2GB. If there is anything unusual about the dma-window properties, we fall back to the old behavior. We also support switching off the iommu completely now with the regular iommu=off command line option. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/iommu.c | 225 ++++++++++++++++++++++++++++-------- 1 file changed, 176 insertions(+), 49 deletions(-) diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 74f999b4ac9e..46e7cb9c3e64 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include "iommu.h" @@ -220,8 +223,6 @@ set_iopt_cache(void __iomem *base, unsigned long index, { unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR; unsigned long __iomem *p = base + IOC_PT_CACHE_REG; - pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n", - index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag); out_be64(p, val); out_be64(&tags[index], tag); @@ -248,67 +249,176 @@ set_iocmd_config(void __iomem *base) out_be64(p, conf | IOCMD_CONF_TE); } -/* FIXME: get these from the device tree */ -#define ioc_base 0x20000511000ull -#define ioc_mmio_base 0x20000510000ull -#define ioid 0x48a -#define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */ -#define io_page_size 0x1000000 - -static unsigned long map_iopt_entry(unsigned long address) +static void enable_mapping(void __iomem *base, void __iomem *mmio_base) { - switch (address >> 20) { - case 0x600: - address = 0x24020000000ull; /* spider i/o */ - break; - default: - address += iopt_phys_offset; - break; - } - - return get_iopt_entry(address, ioid, IOPT_PROT_RW); + set_iocmd_config(base); + set_iost_origin(mmio_base); } -static void iommu_bus_setup_null(struct pci_bus *b) { } static void iommu_dev_setup_null(struct pci_dev *d) { } +static void iommu_bus_setup_null(struct pci_bus *b) { } + +struct cell_iommu { + unsigned long base; + unsigned long mmio_base; + void __iomem *mapped_base; + void __iomem *mapped_mmio_base; +}; + +static struct cell_iommu cell_iommus[NR_CPUS]; /* initialize the iommu to support a simple linear mapping * for each DMA window used by any device. For now, we * happen to know that there is only one DMA window in use, * starting at iopt_phys_offset. */ -static void cell_map_iommu(void) +static void cell_do_map_iommu(struct cell_iommu *iommu, + unsigned int ioid, + unsigned long map_start, + unsigned long map_size) { - unsigned long address; - void __iomem *base; + unsigned long io_address, real_address; + void __iomem *ioc_base, *ioc_mmio_base; ioste ioste; unsigned long index; - base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE); - pr_debug("%lx mapped to %p\n", ioc_base, base); - set_iocmd_config(base); - iounmap(base); + /* we pretend the io page table was at a very high address */ + const unsigned long fake_iopt = 0x10000000000ul; + const unsigned long io_page_size = 0x1000000; /* use 16M pages */ + const unsigned long io_segment_size = 0x10000000; /* 256M */ + + ioc_base = iommu->mapped_base; + ioc_mmio_base = iommu->mapped_mmio_base; + + for (real_address = 0, io_address = 0; + io_address <= map_start + map_size; + real_address += io_page_size, io_address += io_page_size) { + ioste = get_iost_entry(fake_iopt, io_address, io_page_size); + if ((real_address % io_segment_size) == 0) /* segment start */ + set_iost_cache(ioc_mmio_base, + io_address >> 28, ioste); + index = get_ioc_hash_1way(ioste, io_address); + pr_debug("addr %08lx, index %02lx, ioste %016lx\n", + io_address, index, ioste.val); + set_iopt_cache(ioc_mmio_base, + get_ioc_hash_1way(ioste, io_address), + get_ioc_tag(ioste, io_address), + get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW)); + } +} - base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE); - pr_debug("%lx mapped to %p\n", ioc_mmio_base, base); +static void iommu_devnode_setup(struct device_node *d) +{ + unsigned int *ioid; + unsigned long *dma_window, map_start, map_size, token; + struct cell_iommu *iommu; - set_iost_origin(base); + ioid = (unsigned int *)get_property(d, "ioid", NULL); + if (!ioid) + pr_debug("No ioid entry found !\n"); - for (address = 0; address < 0x100000000ul; address += io_page_size) { - ioste = get_iost_entry(0x10000000000ul, address, io_page_size); - if ((address & 0xfffffff) == 0) /* segment start */ - set_iost_cache(base, address >> 28, ioste); - index = get_ioc_hash_1way(ioste, address); - pr_debug("addr %08lx, index %02lx, ioste %016lx\n", - address, index, ioste.val); - set_iopt_cache(base, - get_ioc_hash_1way(ioste, address), - get_ioc_tag(ioste, address), - map_iopt_entry(address)); - } - iounmap(base); + dma_window = (unsigned long *)get_property(d, "ibm,dma-window", NULL); + if (!dma_window) + pr_debug("No ibm,dma-window entry found !\n"); + + map_start = dma_window[1]; + map_size = dma_window[2]; + token = dma_window[0] >> 32; + + iommu = &cell_iommus[token]; + + cell_do_map_iommu(iommu, *ioid, map_start, map_size); +} + +static void iommu_bus_setup(struct pci_bus *b) +{ + struct device_node *d = (struct device_node *)b->sysdata; + iommu_devnode_setup(d); +} + + +static int cell_map_iommu_hardcoded(int num_nodes) +{ + struct cell_iommu *iommu = NULL; + + pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__); + + /* node 0 */ + iommu = &cell_iommus[0]; + iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE); + iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE); + + enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); + + cell_do_map_iommu(iommu, 0x048a, + 0x20000000ul,0x20000000ul); + + if (num_nodes < 2) + return 0; + + /* node 1 */ + iommu = &cell_iommus[1]; + iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE); + iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE); + + enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); + + cell_do_map_iommu(iommu, 0x048a, + 0x20000000,0x20000000ul); + + return 0; } +static int cell_map_iommu(void) +{ + unsigned int num_nodes = 0, *node_id; + unsigned long *base, *mmio_base; + struct device_node *dn; + struct cell_iommu *iommu = NULL; + + /* determine number of nodes (=iommus) */ + pr_debug("%s(%d): determining number of nodes...", __FUNCTION__, __LINE__); + for(dn = of_find_node_by_type(NULL, "cpu"); + dn; + dn = of_find_node_by_type(dn, "cpu")) { + node_id = (unsigned int *)get_property(dn, "node-id", NULL); + + if (num_nodes < *node_id) + num_nodes = *node_id; + } + + num_nodes++; + pr_debug("%i found.\n", num_nodes); + + /* map the iommu registers for each node */ + pr_debug("%s(%d): Looping through nodes\n", __FUNCTION__, __LINE__); + for(dn = of_find_node_by_type(NULL, "cpu"); + dn; + dn = of_find_node_by_type(dn, "cpu")) { + + node_id = (unsigned int *)get_property(dn, "node-id", NULL); + base = (unsigned long *)get_property(dn, "ioc-cache", NULL); + mmio_base = (unsigned long *)get_property(dn, "ioc-translation", NULL); + + if (!base || !mmio_base || !node_id) + return cell_map_iommu_hardcoded(num_nodes); + + iommu = &cell_iommus[*node_id]; + iommu->base = *base; + iommu->mmio_base = *mmio_base; + + iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE); + iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE); + + enable_mapping(iommu->mapped_base, + iommu->mapped_mmio_base); + + /* everything else will be done in iommu_bus_setup */ + } + + return 1; +} + static void *cell_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { @@ -365,11 +475,28 @@ static int cell_dma_supported(struct device *dev, u64 mask) void cell_init_iommu(void) { - cell_map_iommu(); - - /* Direct I/O, IOMMU off */ - ppc_md.iommu_dev_setup = iommu_dev_setup_null; - ppc_md.iommu_bus_setup = iommu_bus_setup_null; + int setup_bus = 0; + + if (of_find_node_by_path("/mambo")) { + pr_info("Not using iommu on systemsim\n"); + } else { + + if (!(of_chosen && + get_property(of_chosen, "linux,iommu-off", NULL))) + setup_bus = cell_map_iommu(); + + if (setup_bus) { + pr_debug("%s: IOMMU mapping activated\n", __FUNCTION__); + ppc_md.iommu_dev_setup = iommu_dev_setup_null; + ppc_md.iommu_bus_setup = iommu_bus_setup; + } else { + pr_debug("%s: IOMMU mapping activated, " + "no device action necessary\n", __FUNCTION__); + /* Direct I/O, IOMMU off */ + ppc_md.iommu_dev_setup = iommu_dev_setup_null; + ppc_md.iommu_bus_setup = iommu_bus_setup_null; + } + } pci_dma_ops.alloc_coherent = cell_alloc_coherent; pci_dma_ops.free_coherent = cell_free_coherent; -- cgit v1.2.3 From d52771fce4e774fa786097d34412a057d487c697 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 9 Dec 2005 19:04:21 +0100 Subject: [PATCH] powerpc/cell: disable legacy i/o area We currently crash in the fedora installer because the keyboard driver tries to access I/O space that is not there on our hardware. This uses the same solution as powermac by just marking all legacy i/o as invalid. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/setup.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index c41a6e2e2c30..e5ee42b67509 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -201,6 +201,15 @@ static int __init cell_probe(int platform) return 1; } +/* + * Cell has no legacy IO; anything calling this function has to + * fail or bad things will happen + */ +static int cell_check_legacy_ioport(unsigned int baseport) +{ + return -ENODEV; +} + struct machdep_calls __initdata cell_md = { .probe = cell_probe, .setup_arch = cell_setup_arch, @@ -213,6 +222,7 @@ struct machdep_calls __initdata cell_md = { .get_rtc_time = rtas_get_rtc_time, .set_rtc_time = rtas_set_rtc_time, .calibrate_decr = generic_calibrate_decr, + .check_legacy_ioport = cell_check_legacy_ioport, .progress = cell_progress, #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, -- cgit v1.2.3 From f9ce299fc629d5c899a2e56b00e21f5da05cf590 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Dec 2005 19:21:44 +0100 Subject: [PATCH] powerpc: fix large nvram access /dev/nvram uses the user-provided read/write size for kmalloc, which fails, if a large number is passed. This will always use a single page at most, which can be expected to succeed. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/nvram_64.c | 106 +++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index c0fcd29918ce..fd7db8d542db 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -80,80 +80,74 @@ static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) static ssize_t dev_nvram_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - ssize_t len; - char *tmp_buffer; - int size; + ssize_t ret; + char *tmp = NULL; + ssize_t size; - if (ppc_md.nvram_size == NULL) - return -ENODEV; + ret = -ENODEV; + if (!ppc_md.nvram_size) + goto out; + + ret = 0; size = ppc_md.nvram_size(); + if (*ppos >= size || size < 0) + goto out; - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - if (*ppos >= size) - return 0; - if (count > size) - count = size; + count = min_t(size_t, count, size - *ppos); + count = min(count, PAGE_SIZE); - tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); - if (!tmp_buffer) { - printk(KERN_ERR "dev_read_nvram: kmalloc failed\n"); - return -ENOMEM; - } + ret = -ENOMEM; + tmp = kmalloc(count, GFP_KERNEL); + if (!tmp) + goto out; - len = ppc_md.nvram_read(tmp_buffer, count, ppos); - if ((long)len <= 0) { - kfree(tmp_buffer); - return len; - } + ret = ppc_md.nvram_read(tmp, count, ppos); + if (ret <= 0) + goto out; - if (copy_to_user(buf, tmp_buffer, len)) { - kfree(tmp_buffer); - return -EFAULT; - } + if (copy_to_user(buf, tmp, ret)) + ret = -EFAULT; - kfree(tmp_buffer); - return len; +out: + kfree(tmp); + return ret; } static ssize_t dev_nvram_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { - ssize_t len; - char * tmp_buffer; - int size; + ssize_t ret; + char *tmp = NULL; + ssize_t size; - if (ppc_md.nvram_size == NULL) - return -ENODEV; + ret = -ENODEV; + if (!ppc_md.nvram_size) + goto out; + + ret = 0; size = ppc_md.nvram_size(); + if (*ppos >= size || size < 0) + goto out; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - if (*ppos >= size) - return 0; - if (count > size) - count = size; + count = min_t(size_t, count, size - *ppos); + count = min(count, PAGE_SIZE); - tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); - if (!tmp_buffer) { - printk(KERN_ERR "dev_nvram_write: kmalloc failed\n"); - return -ENOMEM; - } - - if (copy_from_user(tmp_buffer, buf, count)) { - kfree(tmp_buffer); - return -EFAULT; - } + ret = -ENOMEM; + tmp = kmalloc(count, GFP_KERNEL); + if (!tmp) + goto out; - len = ppc_md.nvram_write(tmp_buffer, count, ppos); - if ((long)len <= 0) { - kfree(tmp_buffer); - return len; - } + ret = -EFAULT; + if (copy_from_user(tmp, buf, count)) + goto out; + + ret = ppc_md.nvram_write(tmp, count, ppos); + +out: + kfree(tmp); + return ret; - kfree(tmp_buffer); - return len; } static int dev_nvram_ioctl(struct inode *inode, struct file *file, -- cgit v1.2.3 From 2c066042ecc3b0d811440002b74fa3778d4432cb Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Sun, 11 Dec 2005 01:50:03 +0100 Subject: [PATCH] Documentation/powerpc: index update Add three files not mentioned in Documentation/powerpc/00-INDEX. Sort alphabetically. Signed-off-by: Nicolas Kaiser Signed-off-by: Paul Mackerras --- Documentation/powerpc/00-INDEX | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX index e7bea0a407b4..d6d65b9bcfe3 100644 --- a/Documentation/powerpc/00-INDEX +++ b/Documentation/powerpc/00-INDEX @@ -8,12 +8,18 @@ please mail me. cpu_features.txt - info on how we support a variety of CPUs with minimal compile-time options. +eeh-pci-error-recovery.txt + - info on PCI Bus EEH Error Recovery +hvcs.txt + - IBM "Hypervisor Virtual Console Server" Installation Guide +mpc52xx.txt + - Linux 2.6.x on MPC52xx family ppc_htab.txt - info about the Linux/PPC /proc/ppc_htab entry -smp.txt - - use and state info about Linux/PPC on MP machines SBC8260_memory_mapping.txt - EST SBC8260 board info +smp.txt + - use and state info about Linux/PPC on MP machines sound.txt - info on sound support under Linux/PPC zImage_layout.txt -- cgit v1.2.3 From 4b703a231799f43f3414b62300b8ad6736a4aa9d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 13 Dec 2005 06:56:47 +1100 Subject: [PATCH] ppc64: Add NUMA cpu summary at boot We used to print a NUMA cpu summary at boot before the hotplug cpu code was added. This has been useful for catching machine configuration as well as firmware bugs in the past. This patch restores that functionality. An example of the output is: Node 0 CPUs: 0-7 Node 1 CPUs: 8-15 Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/smp.c | 3 +++ arch/powerpc/mm/numa.c | 39 ++++++++++++++++++++++++++++++++++++--- include/asm-powerpc/topology.h | 4 ++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 8e3ca674d359..d381ec90b759 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -568,6 +569,8 @@ void __init smp_cpus_done(unsigned int max_cpus) smp_ops->setup_cpu(boot_cpuid); set_cpus_allowed(current, old_mask); + + dump_numa_cpu_topology(); } #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 97e83f1d1bdb..fc519cd90f77 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -489,7 +489,41 @@ static void __init setup_nonnuma(void) node_set_online(0); } -static void __init dump_numa_topology(void) +void __init dump_numa_cpu_topology(void) +{ + unsigned int node; + unsigned int cpu, count; + + if (min_common_depth == -1 || !numa_enabled) + return; + + for_each_online_node(node) { + printk(KERN_INFO "Node %d CPUs:", node); + + count = 0; + /* + * If we used a CPU iterator here we would miss printing + * the holes in the cpumap. + */ + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (cpu_isset(cpu, numa_cpumask_lookup_table[node])) { + if (count == 0) + printk(" %u", cpu); + ++count; + } else { + if (count > 1) + printk("-%u", cpu - 1); + count = 0; + } + } + + if (count > 1) + printk("-%u", NR_CPUS - 1); + printk("\n"); + } +} + +static void __init dump_numa_memory_topology(void) { unsigned int node; unsigned int count; @@ -521,7 +555,6 @@ static void __init dump_numa_topology(void) printk("-0x%lx", i); printk("\n"); } - return; } /* @@ -583,7 +616,7 @@ void __init do_init_bootmem(void) if (parse_numa_properties()) setup_nonnuma(); else - dump_numa_topology(); + dump_numa_memory_topology(); register_cpu_notifier(&ppc64_numa_nb); diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index db8095cbe09b..f8a130af7d09 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -55,8 +55,12 @@ static inline int node_to_first_cpu(int node) .nr_balance_failed = 0, \ } +extern void __init dump_numa_cpu_topology(void); + #else +static inline void dump_numa_cpu_topology(void) {} + #include #endif /* CONFIG_NUMA */ -- cgit v1.2.3 From 2406f6063a9caa8ea39e4040e1759db553388caf Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 13 Dec 2005 07:45:33 +1100 Subject: [PATCH] powerpc: Dont set 32bit cputable bits on 64bit Milton and I were looking at the cputable code and it looks like we can set spurious bits on 64bit. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- include/asm-powerpc/cputable.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index d1cfa3f515ea..4b6f03444ffe 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -311,6 +311,11 @@ enum { #endif CPU_FTRS_POSSIBLE = +#ifdef __powerpc64__ + CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | + CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL | + CPU_FTR_CI_LARGE_PAGE | +#else #if CLASSIC_PPC CPU_FTRS_PPC601 | CPU_FTRS_603 | CPU_FTRS_604 | CPU_FTRS_740_NOTAU | CPU_FTRS_740 | CPU_FTRS_750 | CPU_FTRS_750FX1 | @@ -344,14 +349,14 @@ enum { #ifdef CONFIG_E500 CPU_FTRS_E500 | CPU_FTRS_E500_2 | #endif -#ifdef __powerpc64__ - CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | - CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_CELL | - CPU_FTR_CI_LARGE_PAGE | -#endif +#endif /* __powerpc64__ */ 0, CPU_FTRS_ALWAYS = +#ifdef __powerpc64__ + CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & + CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL & +#else #if CLASSIC_PPC CPU_FTRS_PPC601 & CPU_FTRS_603 & CPU_FTRS_604 & CPU_FTRS_740_NOTAU & CPU_FTRS_740 & CPU_FTRS_750 & CPU_FTRS_750FX1 & @@ -385,10 +390,7 @@ enum { #ifdef CONFIG_E500 CPU_FTRS_E500 & CPU_FTRS_E500_2 & #endif -#ifdef __powerpc64__ - CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & - CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_CELL & -#endif +#endif /* __powerpc64__ */ CPU_FTRS_POSSIBLE, }; -- cgit v1.2.3 From 448b2719408c736080e1147c615ccefce16ede41 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 13 Dec 2005 07:56:54 +1100 Subject: [PATCH] powerpc: Remove old comment in head.S Remove a comment in head.S which is no longer relevant. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/head_64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 0763dd632b78..7f56f9bf76df 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1867,7 +1867,7 @@ _STATIC(start_here_multiplatform) mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r24 /* for this processor. */ add r13,r13,r26 /* convert to physical addr */ - mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */ + mtspr SPRN_SPRG3,r13 /* Do very early kernel initializations, including initial hash table, * stab and slb setup before we turn on relocation. */ -- cgit v1.2.3 From f75225d0a01e4f468b0395b02e549d2763bbabfb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 13 Dec 2005 17:46:23 +1100 Subject: [PATCH] powerpc: Add pmac32 defconfig for ARCH=powerpc This adds a defconfig for PowerMac with ARCH=powerpc Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/configs/pmac32_defconfig | 1729 +++++++++++++++++++++++++++++++++ 1 file changed, 1729 insertions(+) create mode 100644 arch/powerpc/configs/pmac32_defconfig diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig new file mode 100644 index 000000000000..398203bd98eb --- /dev/null +++ b/arch/powerpc/configs/pmac32_defconfig @@ -0,0 +1,1729 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.15-rc5 +# Tue Dec 13 17:24:05 2005 +# +# CONFIG_PPC64 is not set +CONFIG_PPC32=y +CONFIG_PPC_MERGE=y +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_PPC=y +CONFIG_EARLY_PRINTK=y +CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y + +# +# Processor support +# +CONFIG_6xx=y +# CONFIG_PPC_52xx is not set +# CONFIG_PPC_82xx is not set +# CONFIG_PPC_83xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_8xx is not set +# CONFIG_E200 is not set +# CONFIG_E500 is not set +CONFIG_PPC_FPU=y +CONFIG_ALTIVEC=y +CONFIG_PPC_STD_MMU=y +CONFIG_PPC_STD_MMU_32=y +# CONFIG_SMP is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_HOTPLUG=y +CONFIG_KOBJECT_UEVENT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Block layer +# +CONFIG_LBD=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + +# +# Platform support +# +CONFIG_PPC_MULTIPLATFORM=y +# CONFIG_PPC_ISERIES is not set +# CONFIG_EMBEDDED6xx is not set +# CONFIG_APUS is not set +# CONFIG_PPC_CHRP is not set +CONFIG_PPC_PMAC=y +CONFIG_PPC_OF=y +CONFIG_MPIC=y +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PPC_MPC106=y +# CONFIG_GENERIC_TBSYNC is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_PMAC=y +CONFIG_PPC601_SYNC_FIX=y +# CONFIG_TAU is not set +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Kernel options +# +# CONFIG_HIGHMEM is not set +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +# CONFIG_KEXEC is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_PROC_DEVICETREE=y +# CONFIG_CMDLINE_BOOL is not set +CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +CONFIG_PM_DEBUG=y +CONFIG_SOFTWARE_SUSPEND=y +CONFIG_PM_STD_PARTITION="" +CONFIG_SECCOMP=y +CONFIG_ISA_DMA_API=y + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_PPC_I8259 is not set +CONFIG_PPC_INDIRECT_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_LEGACY_PROC=y +# CONFIG_PCI_DEBUG is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +CONFIG_PCCARD=m +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_PCMCIA=m +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_IOCTL=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=m +# CONFIG_PD6729 is not set +# CONFIG_I82092 is not set +CONFIG_PCCARD_NONSTATIC=m + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# +# CONFIG_NETFILTER_NETLINK is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +# CONFIG_IP_NF_CT_ACCT is not set +# CONFIG_IP_NF_CONNTRACK_MARK is not set +# CONFIG_IP_NF_CONNTRACK_EVENTS is not set +# CONFIG_IP_NF_CT_PROTO_SCTP is not set +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_NETBIOS_NS=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_PPTP=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_IPRANGE=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_OWNER=m +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set +# CONFIG_IP_NF_MATCH_SCTP is not set +CONFIG_IP_NF_MATCH_DCCP=m +# CONFIG_IP_NF_MATCH_COMMENT is not set +# CONFIG_IP_NF_MATCH_HASHLIMIT is not set +CONFIG_IP_NF_MATCH_STRING=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +# CONFIG_IP_NF_TARGET_LOG is not set +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_TARGET_NFQUEUE is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_SAME=m +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_NAT_PPTP=m +# CONFIG_IP_NF_MANGLE is not set +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_TARGET_NOTRACK=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# DCCP Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP=m +CONFIG_INET_DCCP_DIAG=m + +# +# DCCP CCIDs Configuration (EXPERIMENTAL) +# +CONFIG_IP_DCCP_CCID3=m +CONFIG_IP_DCCP_TFRC_LIB=m + +# +# DCCP Kernel Hacking +# +# CONFIG_IP_DCCP_DEBUG is not set +# CONFIG_IP_DCCP_UNLOAD_HACK is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# Old SIR device drivers +# +# CONFIG_IRPORT_SIR is not set + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_SIGMATEL_FIR is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_FIR is not set +CONFIG_BT=m +CONFIG_BT_L2CAP=m +CONFIG_BT_SCO=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUSB=m +# CONFIG_BT_HCIUSB_SCO is not set +# CONFIG_BT_HCIUART is not set +CONFIG_BT_HCIBCM203X=m +# CONFIG_BT_HCIBPA10X is not set +CONFIG_BT_HCIBFUSB=m +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIVHCI is not set +CONFIG_IEEE80211=m +# CONFIG_IEEE80211_DEBUG is not set +CONFIG_IEEE80211_CRYPT_WEP=m +CONFIG_IEEE80211_CRYPT_CCMP=m +CONFIG_IEEE80211_CRYPT_TKIP=m + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_MAC_FLOPPY=y +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_UB=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=y +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_IDE_GENERIC is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_SL82C105=y +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +CONFIG_BLK_DEV_PDC202XX_NEW=y +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDE_PMAC_BLINK=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_ISCSI_TCP is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC7XXX_OLD=m +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_MESH_RESET_DELAY_MS=1000 +CONFIG_SCSI_MAC53C94=y + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +CONFIG_MD_RAID5=m +CONFIG_MD_RAID6=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +# CONFIG_IEEE1394_OUI_DB is not set +CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y +CONFIG_IEEE1394_CONFIG_ROM_IP1394=y +# CONFIG_IEEE1394_EXPORT_FULL_API is not set + +# +# Device Drivers +# +# CONFIG_IEEE1394_PCILYNX is not set +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +# CONFIG_IEEE1394_CMP is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_PMU=y +CONFIG_PMAC_APM_EMU=y +CONFIG_PMAC_MEDIABAY=y +CONFIG_PMAC_BACKLIGHT=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_THERM_WINDTUNNEL=m +CONFIG_THERM_ADT746X=m +# CONFIG_WINDFARM is not set +# CONFIG_ANSLCD is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_MACE=y +# CONFIG_MACE_AAUI_PORT is not set +CONFIG_BMAC=y +# CONFIG_HAPPYMEAL is not set +CONFIG_SUNGEM=y +# CONFIG_CASSINI is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set +# CONFIG_MV643XX_ETH is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_PCMCIA_WAVELAN is not set +# CONFIG_PCMCIA_NETWAVE is not set + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=m +CONFIG_APPLE_AIRPORT=m +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_ATMEL is not set + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_AIRO_CS is not set +# CONFIG_PCMCIA_WL3501 is not set + +# +# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# +CONFIG_PRISM54=m +# CONFIG_HOSTAP is not set +CONFIG_NET_WIRELESS=y + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=m +# CONFIG_SERIAL_8250_CS is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=m +# CONFIG_SERIAL_PMACZILOG is not set +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_NVRAM=y +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +CONFIG_AGP=m +CONFIG_AGP_UNINORTH=m +CONFIG_DRM=m +# CONFIG_DRM_TDFX is not set +CONFIG_DRM_R128=m +CONFIG_DRM_RADEON=m +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set +# CONFIG_DRM_VIA is not set +# CONFIG_DRM_SAVAGE is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +CONFIG_I2C_KEYWEST=m +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_MACMODES=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_CT65550=y +# CONFIG_FB_ASILIANT is not set +CONFIG_FB_IMSTT=y +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_S1D13XXX is not set +CONFIG_FB_NVIDIA=y +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_RIVA is not set +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +# CONFIG_FB_MATROX_G is not set +# CONFIG_FB_MATROX_I2C is not set +# CONFIG_FB_MATROX_MULTIHEAD is not set +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_I2C=y +# CONFIG_FB_RADEON_DEBUG is not set +CONFIG_FB_ATY128=y +CONFIG_FB_ATY=y +CONFIG_FB_ATY_CT=y +# CONFIG_FB_ATY_GENERIC_LCD is not set +# CONFIG_FB_ATY_XL_INIT is not set +CONFIG_FB_ATY_GX=y +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +CONFIG_FB_3DFX=y +# CONFIG_FB_3DFX_ACCEL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_CYBLA is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Sound +# +CONFIG_SOUND=m +CONFIG_DMASOUND_PMAC=m +CONFIG_DMASOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_GENERIC_DRIVER=y + +# +# Generic devices +# +CONFIG_SND_DUMMY=m +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set + +# +# ALSA PowerMac devices +# +CONFIG_SND_POWERMAC=m +# CONFIG_SND_POWERMAC_AUTO_DRC is not set + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_USX2Y is not set + +# +# PCMCIA devices +# + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_DYNAMIC_MINORS=y +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information +# +# CONFIG_USB_STORAGE is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +CONFIG_USB_APPLETOUCH=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=m +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +CONFIG_USB_NET_ZAURUS=m +# CONFIG_USB_ZD1201 is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRPRIME is not set +# CONFIG_USB_SERIAL_ANYDATA is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP2101 is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +CONFIG_USB_EZUSB=y + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETKIT is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_ZISOFS_FS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +CONFIG_RELAYFS_FS=m + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_LOCKD=y +CONFIG_EXPORTFS=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Library routines +# +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m + +# +# Instrumentation Support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUGGER=y +CONFIG_XMON=y +CONFIG_XMON_DEFAULT=y +# CONFIG_BDI_SWITCH is not set +CONFIG_BOOTX_TEXT=y + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +CONFIG_CRYPTO_AES=m +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +CONFIG_CRYPTO_MICHAEL_MIC=m +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# -- cgit v1.2.3 From 9cf84d7c97992dbe5360b241327341c07ce30fc9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 13 Dec 2005 17:48:35 +1100 Subject: [PATCH] powerpc: Fix platinumfb for some modes The platinumfb driver used only on some powermacs has an issue with some video modes & limited VRAM. This patch fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/video/platinumfb.c | 12 ++++++++---- drivers/video/platinumfb.h | 4 +++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index ca4082ae5a18..ba0af1b66bb6 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -138,13 +138,15 @@ static int platinumfb_set_par (struct fb_info *info) init = platinum_reg_init[pinfo->vmode-1]; - if (pinfo->vmode == 13 && pinfo->cmode > 0) - offset = 0x10; + if ((pinfo->vmode == VMODE_832_624_75) && (pinfo->cmode > CMODE_8)) + offset = 0x10; + info->screen_base = pinfo->frame_buffer + init->fb_offset + offset; info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset; info->fix.visual = (pinfo->cmode == CMODE_8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; - info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<cmode) + offset; + info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<cmode) + + offset; printk("line_length: %x\n", info->fix.line_length); return 0; } @@ -221,7 +223,9 @@ static int platinumfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static inline int platinum_vram_reqd(int video_mode, int color_mode) { return vmode_attrs[video_mode-1].vres * - (vmode_attrs[video_mode-1].hres * (1< CMODE_8)) ? 0x10 : 0x20) + 0x1000; } #define STORE_D2(a, d) { \ diff --git a/drivers/video/platinumfb.h b/drivers/video/platinumfb.h index 2834fc1c344b..f6bd77cafd17 100644 --- a/drivers/video/platinumfb.h +++ b/drivers/video/platinumfb.h @@ -158,7 +158,9 @@ static struct platinum_regvals platinum_reg_init_14 = { /* 832x624, 75Hz (13) */ static struct platinum_regvals platinum_reg_init_13 = { 0x70, - { 864, 1680, 3360 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */ + { 864, 1680, 3344 }, /* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB, + * and we use 3344 instead of 3360 to fit in 2Mb + */ { 0xff0, 4, 0, 0, 0, 0, 0x299, 0, 0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37, 0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52, -- cgit v1.2.3 From cc5d0189b9ba95260857a5018a1c2fef90008507 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 13 Dec 2005 18:01:21 +1100 Subject: [PATCH] powerpc: Remove device_node addrs/n_addr The pre-parsed addrs/n_addrs fields in struct device_node are finally gone. Remove the dodgy heuristics that did that parsing at boot and remove the fields themselves since we now have a good replacement with the new OF parsing code. This patch also fixes a bunch of drivers to use the new code instead, so that at least pmac32, pseries, iseries and g5 defconfigs build. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/btext.c | 2 - arch/powerpc/kernel/pci_64.c | 24 +- arch/powerpc/kernel/prom.c | 424 +-------------------------- arch/powerpc/kernel/prom_init.c | 3 +- arch/powerpc/kernel/rtas_pci.c | 49 +--- arch/powerpc/mm/numa.c | 6 +- arch/powerpc/platforms/powermac/feature.c | 75 +++-- arch/powerpc/platforms/powermac/nvram.c | 52 ++-- arch/powerpc/platforms/powermac/pci.c | 87 +++--- arch/powerpc/platforms/powermac/pic.c | 456 ++++++++++++++++-------------- arch/powerpc/platforms/powermac/pmac.h | 6 +- arch/powerpc/platforms/powermac/setup.c | 3 +- arch/powerpc/platforms/powermac/time.c | 15 +- drivers/block/swim3.c | 38 ++- drivers/ide/ppc/pmac.c | 4 +- drivers/macintosh/macio_asic.c | 26 +- drivers/macintosh/mediabay.c | 8 +- drivers/macintosh/via-cuda.c | 4 - drivers/macintosh/via-pmu.c | 9 +- drivers/scsi/mac53c94.c | 22 +- drivers/scsi/mesh.c | 3 +- drivers/serial/pmac_zilog.c | 15 +- drivers/video/controlfb.c | 114 ++++---- drivers/video/offb.c | 122 ++++---- drivers/video/platinumfb.c | 86 +++--- drivers/video/valkyriefb.c | 12 +- include/asm-powerpc/keylargo.h | 10 +- include/asm-powerpc/prom.h | 40 --- sound/oss/dmasound/dmasound_awacs.c | 81 +++--- sound/ppc/pmac.c | 100 ++++--- sound/ppc/pmac.h | 3 +- 31 files changed, 793 insertions(+), 1106 deletions(-) diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 5de0d80ca2f2..6223d39177cb 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -211,8 +211,6 @@ int __init btext_find_display(int allow_nonstdout) struct device_node *np = NULL; int rc = -ENODEV; - printk("trying to initialize btext ...\n"); - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); if (name != NULL) { np = of_find_node_by_path(name); diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 4eb93fc1eef2..523f35087e81 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -896,6 +896,25 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, unsigned long phb_io_base_phys, void __iomem * phb_io_base_virt) { + /* Remove these asap */ + + struct pci_address { + u32 a_hi; + u32 a_mid; + u32 a_lo; + }; + + struct isa_address { + u32 a_hi; + u32 a_lo; + }; + + struct isa_range { + struct isa_address isa_addr; + struct pci_address pci_addr; + unsigned int size; + }; + struct isa_range *range; unsigned long pci_addr; unsigned int isa_addr; @@ -1330,8 +1349,9 @@ unsigned int pci_address_to_pio(phys_addr_t address) list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { if (address >= hose->io_base_phys && address < (hose->io_base_phys + hose->pci_io_size)) - return (unsigned int)hose->io_base_virt + - (address - hose->io_base_phys); + return (unsigned int) + ((unsigned long)hose->io_base_virt + + (address - hose->io_base_phys)); } return (unsigned int)-1; } diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 7e798d5b03b4..1b97e13657e5 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -57,21 +57,6 @@ #define DBG(fmt...) #endif -struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; -}; - -struct isa_reg_property { - u32 space; - u32 address; - u32 size; -}; - - -typedef int interpret_func(struct device_node *, unsigned long *, - int, int, int); static int __initdata dt_root_addr_cells; static int __initdata dt_root_size_cells; @@ -410,237 +395,19 @@ static int __devinit finish_node_interrupts(struct device_node *np, return 0; } -static int __devinit interpret_pci_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct address_range *adr; - struct pci_reg_property *pci_addrs; - int i, l, n_addrs; - - pci_addrs = (struct pci_reg_property *) - get_property(np, "assigned-addresses", &l); - if (!pci_addrs) - return 0; - - n_addrs = l / sizeof(*pci_addrs); - - adr = prom_alloc(n_addrs * sizeof(*adr), mem_start); - if (!adr) - return -ENOMEM; - - if (measure_only) - return 0; - - np->addrs = adr; - np->n_addrs = n_addrs; - - for (i = 0; i < n_addrs; i++) { - adr[i].space = pci_addrs[i].addr.a_hi; - adr[i].address = pci_addrs[i].addr.a_lo | - ((u64)pci_addrs[i].addr.a_mid << 32); - adr[i].size = pci_addrs[i].size_lo; - } - - return 0; -} - -static int __init interpret_dbdma_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct reg_property32 *rp; - struct address_range *adr; - unsigned long base_address; - int i, l; - struct device_node *db; - - base_address = 0; - if (!measure_only) { - for (db = np->parent; db != NULL; db = db->parent) { - if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) { - base_address = db->addrs[0].address; - break; - } - } - } - - rp = (struct reg_property32 *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property32)) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= sizeof(struct reg_property32)) >= 0) { - if (!measure_only) { - adr[i].space = 2; - adr[i].address = rp[i].address + base_address; - adr[i].size = rp[i].size; - } - ++i; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __init interpret_macio_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct reg_property32 *rp; - struct address_range *adr; - unsigned long base_address; - int i, l; - struct device_node *db; - - base_address = 0; - if (!measure_only) { - for (db = np->parent; db != NULL; db = db->parent) { - if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { - base_address = db->addrs[0].address; - break; - } - } - } - - rp = (struct reg_property32 *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property32)) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= sizeof(struct reg_property32)) >= 0) { - if (!measure_only) { - adr[i].space = 2; - adr[i].address = rp[i].address + base_address; - adr[i].size = rp[i].size; - } - ++i; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __init interpret_isa_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct isa_reg_property *rp; - struct address_range *adr; - int i, l; - - rp = (struct isa_reg_property *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct isa_reg_property)) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= sizeof(struct isa_reg_property)) >= 0) { - if (!measure_only) { - adr[i].space = rp[i].space; - adr[i].address = rp[i].address; - adr[i].size = rp[i].size; - } - ++i; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __init interpret_root_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct address_range *adr; - int i, l; - unsigned int *rp; - int rpsize = (naddrc + nsizec) * sizeof(unsigned int); - - rp = (unsigned int *) get_property(np, "linux,usable-memory", &l); - if (rp == NULL) - rp = (unsigned int *) get_property(np, "reg", &l); - - if (rp != 0 && l >= rpsize) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= rpsize) >= 0) { - if (!measure_only) { - adr[i].space = 0; - adr[i].address = rp[naddrc - 1]; - adr[i].size = rp[naddrc + nsizec - 1]; - } - ++i; - rp += naddrc + nsizec; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - static int __devinit finish_node(struct device_node *np, unsigned long *mem_start, - interpret_func *ifunc, - int naddrc, int nsizec, int measure_only) { struct device_node *child; - int *ip, rc = 0; - - /* get the device addresses and interrupts */ - if (ifunc != NULL) - rc = ifunc(np, mem_start, naddrc, nsizec, measure_only); - if (rc) - goto out; + int rc = 0; rc = finish_node_interrupts(np, mem_start, measure_only); if (rc) goto out; - /* Look for #address-cells and #size-cells properties. */ - ip = (int *) get_property(np, "#address-cells", NULL); - if (ip != NULL) - naddrc = *ip; - ip = (int *) get_property(np, "#size-cells", NULL); - if (ip != NULL) - nsizec = *ip; - - if (!strcmp(np->name, "device-tree") || np->parent == NULL) - ifunc = interpret_root_props; - else if (np->type == 0) - ifunc = NULL; - else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) - ifunc = interpret_pci_props; - else if (!strcmp(np->type, "dbdma")) - ifunc = interpret_dbdma_props; - else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) - ifunc = interpret_macio_props; - else if (!strcmp(np->type, "isa")) - ifunc = interpret_isa_props; - else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) - ifunc = interpret_root_props; - else if (!((ifunc == interpret_dbdma_props - || ifunc == interpret_macio_props) - && (!strcmp(np->type, "escc") - || !strcmp(np->type, "media-bay")))) - ifunc = NULL; - for (child = np->child; child != NULL; child = child->sibling) { - rc = finish_node(child, mem_start, ifunc, - naddrc, nsizec, measure_only); + rc = finish_node(child, mem_start, measure_only); if (rc) goto out; } @@ -702,10 +469,10 @@ void __init finish_device_tree(void) * reason and then remove those additional 16 bytes */ size = 16; - finish_node(allnodes, &size, NULL, 0, 0, 1); + finish_node(allnodes, &size, 1); size -= 16; end = start = (unsigned long) __va(lmb_alloc(size, 128)); - finish_node(allnodes, &end, NULL, 0, 0, 0); + finish_node(allnodes, &end, 0); BUG_ON(end != start + size); DBG(" <- finish_device_tree\n"); @@ -1822,7 +1589,6 @@ static void of_node_release(struct kref *kref) prop = next; } kfree(node->intrs); - kfree(node->addrs); kfree(node->full_name); kfree(node->data); kfree(node); @@ -1904,9 +1670,7 @@ void of_detach_node(const struct device_node *np) * This should probably be split up into smaller chunks. */ -static int of_finish_dynamic_node(struct device_node *node, - unsigned long *unused1, int unused2, - int unused3, int unused4) +static int of_finish_dynamic_node(struct device_node *node) { struct device_node *parent = of_get_parent(node); int err = 0; @@ -1927,7 +1691,8 @@ static int of_finish_dynamic_node(struct device_node *node, return -ENODEV; /* fix up new node's linux_phandle field */ - if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) + if ((ibm_phandle = (unsigned int *)get_property(node, + "ibm,phandle", NULL))) node->linux_phandle = *ibm_phandle; out: @@ -1942,7 +1707,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb, switch (action) { case PSERIES_RECONFIG_ADD: - err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0); + err = of_finish_dynamic_node(node); + if (!err) + finish_node(node, NULL, 0); if (err < 0) { printk(KERN_ERR "finish_node returned %d\n", err); err = NOTIFY_BAD; @@ -2016,175 +1783,4 @@ int prom_add_property(struct device_node* np, struct property* prop) return 0; } -/* I quickly hacked that one, check against spec ! */ -static inline unsigned long -bus_space_to_resource_flags(unsigned int bus_space) -{ - u8 space = (bus_space >> 24) & 0xf; - if (space == 0) - space = 0x02; - if (space == 0x02) - return IORESOURCE_MEM; - else if (space == 0x01) - return IORESOURCE_IO; - else { - printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", - bus_space); - return 0; - } -} - -#ifdef CONFIG_PCI -static struct resource *find_parent_pci_resource(struct pci_dev* pdev, - struct address_range *range) -{ - unsigned long mask; - int i; - - /* Check this one */ - mask = bus_space_to_resource_flags(range->space); - for (i=0; iresource[i].flags & mask) == mask && - pdev->resource[i].start <= range->address && - pdev->resource[i].end > range->address) { - if ((range->address + range->size - 1) > pdev->resource[i].end) { - /* Add better message */ - printk(KERN_WARNING "PCI/OF resource overlap !\n"); - return NULL; - } - break; - } - } - if (i == DEVICE_COUNT_RESOURCE) - return NULL; - return &pdev->resource[i]; -} - -/* - * Request an OF device resource. Currently handles child of PCI devices, - * or other nodes attached to the root node. Ultimately, put some - * link to resources in the OF node. - */ -struct resource *request_OF_resource(struct device_node* node, int index, - const char* name_postfix) -{ - struct pci_dev* pcidev; - u8 pci_bus, pci_devfn; - unsigned long iomask; - struct device_node* nd; - struct resource* parent; - struct resource *res = NULL; - int nlen, plen; - - if (index >= node->n_addrs) - goto fail; - - /* Sanity check on bus space */ - iomask = bus_space_to_resource_flags(node->addrs[index].space); - if (iomask & IORESOURCE_MEM) - parent = &iomem_resource; - else if (iomask & IORESOURCE_IO) - parent = &ioport_resource; - else - goto fail; - - /* Find a PCI parent if any */ - nd = node; - pcidev = NULL; - while (nd) { - if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) - pcidev = pci_find_slot(pci_bus, pci_devfn); - if (pcidev) break; - nd = nd->parent; - } - if (pcidev) - parent = find_parent_pci_resource(pcidev, &node->addrs[index]); - if (!parent) { - printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", - node->name); - goto fail; - } - - res = __request_region(parent, node->addrs[index].address, - node->addrs[index].size, NULL); - if (!res) - goto fail; - nlen = strlen(node->name); - plen = name_postfix ? strlen(name_postfix) : 0; - res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); - if (res->name) { - strcpy((char *)res->name, node->name); - if (plen) - strcpy((char *)res->name+nlen, name_postfix); - } - return res; -fail: - return NULL; -} -EXPORT_SYMBOL(request_OF_resource); - -int release_OF_resource(struct device_node *node, int index) -{ - struct pci_dev* pcidev; - u8 pci_bus, pci_devfn; - unsigned long iomask, start, end; - struct device_node* nd; - struct resource* parent; - struct resource *res = NULL; - - if (index >= node->n_addrs) - return -EINVAL; - - /* Sanity check on bus space */ - iomask = bus_space_to_resource_flags(node->addrs[index].space); - if (iomask & IORESOURCE_MEM) - parent = &iomem_resource; - else if (iomask & IORESOURCE_IO) - parent = &ioport_resource; - else - return -EINVAL; - - /* Find a PCI parent if any */ - nd = node; - pcidev = NULL; - while(nd) { - if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) - pcidev = pci_find_slot(pci_bus, pci_devfn); - if (pcidev) break; - nd = nd->parent; - } - if (pcidev) - parent = find_parent_pci_resource(pcidev, &node->addrs[index]); - if (!parent) { - printk(KERN_WARNING "release_OF_resource(%s), parent not found\n", - node->name); - return -ENODEV; - } - /* Find us in the parent and its childs */ - res = parent->child; - start = node->addrs[index].address; - end = start + node->addrs[index].size - 1; - while (res) { - if (res->start == start && res->end == end && - (res->flags & IORESOURCE_BUSY)) - break; - if (res->start <= start && res->end >= end) - res = res->child; - else - res = res->sibling; - } - if (!res) - return -ENODEV; - - if (res->name) { - kfree(res->name); - res->name = NULL; - } - release_resource(res); - kfree(res); - - return 0; -} -EXPORT_SYMBOL(release_OF_resource); -#endif /* CONFIG_PCI */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 6007d51d119b..e381f2fc121c 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -558,7 +558,8 @@ unsigned long prom_memparse(const char *ptr, const char **retptr) static void __init early_cmdline_parse(void) { struct prom_t *_prom = &RELOC(prom); - char *opt, *p; + const char *opt; + char *p; int l = 0; RELOC(prom_cmd_line[0]) = 0; diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 60dec2401c26..45b8109951fe 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -188,39 +188,19 @@ int is_python(struct device_node *dev) return 0; } -static int get_phb_reg_prop(struct device_node *dev, - unsigned int addr_size_words, - struct reg_property64 *reg) +static void python_countermeasures(struct device_node *dev) { - unsigned int *ui_ptr = NULL, len; - - /* Found a PHB, now figure out where his registers are mapped. */ - ui_ptr = (unsigned int *)get_property(dev, "reg", &len); - if (ui_ptr == NULL) - return 1; - - if (addr_size_words == 1) { - reg->address = ((struct reg_property32 *)ui_ptr)->address; - reg->size = ((struct reg_property32 *)ui_ptr)->size; - } else { - *reg = *((struct reg_property64 *)ui_ptr); - } - - return 0; -} - -static void python_countermeasures(struct device_node *dev, - unsigned int addr_size_words) -{ - struct reg_property64 reg_struct; + struct resource registers; void __iomem *chip_regs; volatile u32 val; - if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) + if (of_address_to_resource(dev, 0, ®isters)) { + printk(KERN_ERR "Can't get address for Python workarounds !\n"); return; + } /* Python's register file is 1 MB in size. */ - chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); + chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000); /* * Firmware doesn't always clear this bit which is critical @@ -301,11 +281,10 @@ static int phb_set_bus_ranges(struct device_node *dev, } static int __devinit setup_phb(struct device_node *dev, - struct pci_controller *phb, - unsigned int addr_size_words) + struct pci_controller *phb) { if (is_python(dev)) - python_countermeasures(dev, addr_size_words); + python_countermeasures(dev); if (phb_set_bus_ranges(dev, phb)) return 1; @@ -320,8 +299,8 @@ unsigned long __init find_and_init_phbs(void) { struct device_node *node; struct pci_controller *phb; - unsigned int root_size_cells = 0; unsigned int index; + unsigned int root_size_cells = 0; unsigned int *opprop = NULL; struct device_node *root = of_find_node_by_path("/"); @@ -343,10 +322,11 @@ unsigned long __init find_and_init_phbs(void) phb = pcibios_alloc_controller(node); if (!phb) continue; - setup_phb(node, phb, root_size_cells); + setup_phb(node, phb); pci_process_bridge_OF_ranges(phb, node, 0); pci_setup_phb_io(phb, index == 0); #ifdef CONFIG_PPC_PSERIES + /* XXX This code need serious fixing ... --BenH */ if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { int addr = root_size_cells * (index + 2) - 1; mpic_assign_isu(pSeries_mpic, index, opprop[addr]); @@ -381,22 +361,17 @@ unsigned long __init find_and_init_phbs(void) struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) { - struct device_node *root = of_find_node_by_path("/"); - unsigned int root_size_cells = 0; struct pci_controller *phb; int primary; - root_size_cells = prom_n_size_cells(root); - primary = list_empty(&hose_list); phb = pcibios_alloc_controller(dn); if (!phb) return NULL; - setup_phb(dn, phb, root_size_cells); + setup_phb(dn, phb); pci_process_bridge_OF_ranges(phb, dn, primary); pci_setup_phb_io_dynamic(phb, primary); - of_node_put(root); pci_devs_phb_init_dynamic(phb); scan_phb(phb); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index fc519cd90f77..fc6f8ee9656f 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -432,7 +432,8 @@ static int __init parse_numa_properties(void) if (!memcell_buf || len <= 0) continue; - ranges = memory->n_addrs; + /* ranges in cell */ + ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); new_range: /* these are order-sensitive, and modify the buffer pointer */ start = read_n_cells(n_mem_addr_cells, &memcell_buf); @@ -779,7 +780,8 @@ int hot_add_scn_to_nid(unsigned long scn_addr) if (!memcell_buf || len <= 0) continue; - ranges = memory->n_addrs; /* ranges in cell */ + /* ranges in cell */ + ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); ha_new_range: start = read_n_cells(n_mem_addr_cells, &memcell_buf); size = read_n_cells(n_mem_size_cells, &memcell_buf); diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index b2928bbe9227..b1f896952b1b 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -1445,20 +1445,55 @@ static long g5_i2s_enable(struct device_node *node, long param, long value) /* Very crude implementation for now */ struct macio_chip *macio = &macio_chips[0]; unsigned long flags; - - if (value == 0) - return 0; /* don't disable yet */ + int cell; + u32 fcrs[3][3] = { + { 0, + K2_FCR1_I2S0_CELL_ENABLE | + K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE, + KL3_I2S0_CLK18_ENABLE + }, + { KL0_SCC_A_INTF_ENABLE, + K2_FCR1_I2S1_CELL_ENABLE | + K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE, + KL3_I2S1_CLK18_ENABLE + }, + { KL0_SCC_B_INTF_ENABLE, + SH_FCR1_I2S2_CELL_ENABLE | + SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE, + SH_FCR3_I2S2_CLK18_ENABLE + }, + }; + + if (macio->type != macio_keylargo2 /* && macio->type != macio_shasta*/) + return -ENODEV; + if (strncmp(node->name, "i2s-", 4)) + return -ENODEV; + cell = node->name[4] - 'a'; + switch(cell) { + case 0: + case 1: + break; +#if 0 + case 2: + if (macio->type == macio_shasta) + break; +#endif + default: + return -ENODEV; + } LOCK(flags); - MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE | - KL3_I2S0_CLK18_ENABLE); - udelay(10); - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE | - K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE); + if (value) { + MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]); + MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]); + MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]); + } else { + MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]); + MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]); + MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]); + } udelay(10); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET); UNLOCK(flags); - udelay(10); return 0; } @@ -2960,26 +2995,6 @@ pmac_feature_init(void) set_initial_features(); } -int __init pmac_feature_late_init(void) -{ -#if 0 - struct device_node *np; - - /* Request some resources late */ - if (uninorth_node) - request_OF_resource(uninorth_node, 0, NULL); - np = find_devices("hammerhead"); - if (np) - request_OF_resource(np, 0, NULL); - np = find_devices("interrupt-controller"); - if (np) - request_OF_resource(np, 0, NULL); -#endif - return 0; -} - -device_initcall(pmac_feature_late_init); - #if 0 static void dump_HT_speeds(char *name, u32 cfg, u32 frq) { diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 59e0e51cf663..3ebd045a3350 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -514,7 +514,7 @@ static void core99_nvram_sync(void) #endif } -static int __init core99_nvram_setup(struct device_node *dp) +static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr) { int i; u32 gen_bank0, gen_bank1; @@ -528,7 +528,7 @@ static int __init core99_nvram_setup(struct device_node *dp) printk(KERN_ERR "nvram: can't allocate ram image\n"); return -ENOMEM; } - nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); + nvram_data = ioremap(addr, NVRAM_SIZE*2); nvram_naddrs = 1; /* Make sure we get the correct case */ DBG("nvram: Checking bank 0...\n"); @@ -570,34 +570,48 @@ static int __init core99_nvram_setup(struct device_node *dp) int __init pmac_nvram_init(void) { struct device_node *dp; + struct resource r1, r2; + unsigned int s1 = 0, s2 = 0; int err = 0; nvram_naddrs = 0; - dp = find_devices("nvram"); + dp = of_find_node_by_name(NULL, "nvram"); if (dp == NULL) { printk(KERN_ERR "Can't find NVRAM device\n"); return -ENODEV; } - nvram_naddrs = dp->n_addrs; + + /* Try to obtain an address */ + if (of_address_to_resource(dp, 0, &r1) == 0) { + nvram_naddrs = 1; + s1 = (r1.end - r1.start) + 1; + if (of_address_to_resource(dp, 1, &r2) == 0) { + nvram_naddrs = 2; + s2 = (r2.end - r2.start) + 1; + } + } + is_core_99 = device_is_compatible(dp, "nvram,flash"); - if (is_core_99) - err = core99_nvram_setup(dp); + if (is_core_99) { + err = core99_nvram_setup(dp, r1.start); + goto bail; + } + #ifdef CONFIG_PPC32 - else if (_machine == _MACH_chrp && nvram_naddrs == 1) { - nvram_data = ioremap(dp->addrs[0].address + isa_mem_base, - dp->addrs[0].size); + if (_machine == _MACH_chrp && nvram_naddrs == 1) { + nvram_data = ioremap(r1.start, s1); nvram_mult = 1; ppc_md.nvram_read_val = direct_nvram_read_byte; ppc_md.nvram_write_val = direct_nvram_write_byte; } else if (nvram_naddrs == 1) { - nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE; + nvram_data = ioremap(r1.start, s1); + nvram_mult = (s1 + NVRAM_SIZE - 1) / NVRAM_SIZE; ppc_md.nvram_read_val = direct_nvram_read_byte; ppc_md.nvram_write_val = direct_nvram_write_byte; } else if (nvram_naddrs == 2) { - nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); - nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); + nvram_addr = ioremap(r1.start, s1); + nvram_data = ioremap(r2.start, s2); ppc_md.nvram_read_val = indirect_nvram_read_byte; ppc_md.nvram_write_val = indirect_nvram_write_byte; } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { @@ -606,13 +620,15 @@ int __init pmac_nvram_init(void) ppc_md.nvram_read_val = pmu_nvram_read_byte; ppc_md.nvram_write_val = pmu_nvram_write_byte; #endif /* CONFIG_ADB_PMU */ - } -#endif - else { + } else { printk(KERN_ERR "Incompatible type of NVRAM\n"); - return -ENXIO; + err = -ENXIO; } - lookup_partitions(); +#endif /* CONFIG_PPC32 */ +bail: + of_node_put(dp); + if (err == 0) + lookup_partitions(); return err; } diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index e0b66f55a5f8..5aab261075de 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -285,15 +285,13 @@ static struct pci_ops chaos_pci_ops = }; static void __init setup_chaos(struct pci_controller *hose, - struct reg_property *addr) + struct resource *addr) { /* assume a `chaos' bridge */ hose->ops = &chaos_pci_ops; - hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000); } -#else -#define setup_chaos(hose, addr) #endif /* CONFIG_PPC32 */ #ifdef CONFIG_PPC64 @@ -356,9 +354,11 @@ static unsigned long u3_ht_cfg_access(struct pci_controller* hose, /* For now, we don't self probe U3 HT bridge */ if (PCI_SLOT(devfn) == 0) return 0; - return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); + return ((unsigned long)hose->cfg_data) + + U3_HT_CFA0(devfn, offset); } else - return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); + return ((unsigned long)hose->cfg_data) + + U3_HT_CFA1(bus, devfn, offset); } static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, @@ -532,7 +532,8 @@ static void __init init_p2pbridge(void) } if (early_read_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) { - printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); + printk(KERN_ERR "init_p2pbridge: couldn't read bridge" + " control\n"); return; } val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; @@ -576,36 +577,38 @@ static void __init fixup_nec_usb2(void) continue; early_read_config_dword(hose, bus, devfn, 0xe4, &data); if (data & 1UL) { - printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n"); + printk("Found NEC PD720100A USB2 chip with disabled" + " EHCI, fixing up...\n"); data &= ~1UL; early_write_config_dword(hose, bus, devfn, 0xe4, data); - early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE, + early_write_config_byte(hose, bus, + devfn | 2, PCI_INTERRUPT_LINE, nec->intrs[0].line); } } } static void __init setup_bandit(struct pci_controller *hose, - struct reg_property *addr) + struct resource *addr) { hose->ops = ¯isc_pci_ops; - hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000); init_bandit(hose); } static int __init setup_uninorth(struct pci_controller *hose, - struct reg_property *addr) + struct resource *addr) { pci_assign_all_buses = 1; has_uninorth = 1; hose->ops = ¯isc_pci_ops; - hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); - hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); + hose->cfg_data = ioremap(addr->start + 0xc00000, 0x1000); /* We "know" that the bridge at f2000000 has the PCI slots. */ - return addr->address == 0xf2000000; + return addr->start == 0xf2000000; } -#endif +#endif /* CONFIG_PPC32 */ #ifdef CONFIG_PPC64 static void __init setup_u3_agp(struct pci_controller* hose) @@ -722,7 +725,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) hose->mem_resources[cur-1].end = res->start - 1; } } -#endif +#endif /* CONFIG_PPC64 */ /* * We assume that if we have a G3 powermac, we have one bridge called @@ -733,24 +736,17 @@ static int __init add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; -#ifdef CONFIG_PPC32 - struct reg_property *addr; -#endif + struct resource rsrc; char *disp_name; int *bus_range; - int primary = 1; + int primary = 1, has_address = 0; DBG("Adding PCI host bridge %s\n", dev->full_name); -#ifdef CONFIG_PPC32 - /* XXX fix this */ - addr = (struct reg_property *) get_property(dev, "reg", &len); - if (addr == NULL || len < sizeof(*addr)) { - printk(KERN_WARNING "Can't use %s: no address\n", - dev->full_name); - return -ENODEV; - } -#endif + /* Fetch host bridge registers address */ + has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); + + /* Get bus range if any */ bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume" @@ -770,6 +766,8 @@ static int __init add_bridge(struct device_node *dev) hose->last_busno = bus_range ? bus_range[1] : 0xff; disp_name = NULL; + + /* 64 bits only bridges */ #ifdef CONFIG_PPC64 if (device_is_compatible(dev, "u3-agp")) { setup_u3_agp(hose); @@ -782,25 +780,30 @@ static int __init add_bridge(struct device_node *dev) } printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", disp_name, hose->first_busno, hose->last_busno); -#else +#endif /* CONFIG_PPC64 */ + + /* 32 bits only bridges */ +#ifdef CONFIG_PPC32 if (device_is_compatible(dev, "uni-north")) { - primary = setup_uninorth(hose, addr); + primary = setup_uninorth(hose, &rsrc); disp_name = "UniNorth"; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ setup_grackle(hose); disp_name = "Grackle (MPC106)"; } else if (strcmp(dev->name, "bandit") == 0) { - setup_bandit(hose, addr); + setup_bandit(hose, &rsrc); disp_name = "Bandit"; } else if (strcmp(dev->name, "chaos") == 0) { - setup_chaos(hose, addr); + setup_chaos(hose, &rsrc); disp_name = "Chaos"; primary = 0; } - printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. Firmware bus number: %d->%d\n", - disp_name, addr->address, hose->first_busno, hose->last_busno); -#endif + printk(KERN_INFO "Found %s PCI host bridge at 0x%08lx. " + "Firmware bus number: %d->%d\n", + disp_name, rsrc.start, hose->first_busno, hose->last_busno); +#endif /* CONFIG_PPC32 */ + DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", hose, hose->cfg_addr, hose->cfg_data); @@ -814,8 +817,7 @@ static int __init add_bridge(struct device_node *dev) return 0; } -static void __init -pcibios_fixup_OF_interrupts(void) +static void __init pcibios_fixup_OF_interrupts(void) { struct pci_dev* dev = NULL; @@ -835,8 +837,7 @@ pcibios_fixup_OF_interrupts(void) } } -void __init -pmac_pcibios_fixup(void) +void __init pmac_pcibios_fixup(void) { /* Fixup interrupts according to OF tree */ pcibios_fixup_OF_interrupts(); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index a36527c98133..dbb524a851aa 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -5,8 +5,8 @@ * in a separate file * * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) - * - * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) + * Copyright (C) 2005 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * IBM, Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -54,12 +54,7 @@ struct pmac_irq_hw { }; /* Default addresses */ -static volatile struct pmac_irq_hw *pmac_irq_hw[4] = { - (struct pmac_irq_hw *) 0xf3000020, - (struct pmac_irq_hw *) 0xf3000010, - (struct pmac_irq_hw *) 0xf4000020, - (struct pmac_irq_hw *) 0xf4000010, -}; +static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4]; #define GC_LEVEL_MASK 0x3ff00000 #define OHARE_LEVEL_MASK 0x1ff00000 @@ -82,8 +77,7 @@ static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; * since it can lose interrupts (see pmac_set_irq_mask). * -- Cort */ -void -__set_lost(unsigned long irq_nr, int nokick) +void __set_lost(unsigned long irq_nr, int nokick) { if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { atomic_inc(&ppc_n_lost_interrupts); @@ -92,8 +86,7 @@ __set_lost(unsigned long irq_nr, int nokick) } } -static void -pmac_mask_and_ack_irq(unsigned int irq_nr) +static void pmac_mask_and_ack_irq(unsigned int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; @@ -224,8 +217,7 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } -int -pmac_get_irq(struct pt_regs *regs) +static int pmac_get_irq(struct pt_regs *regs) { int irq; unsigned long bits = 0; @@ -256,34 +248,40 @@ pmac_get_irq(struct pt_regs *regs) /* This routine will fix some missing interrupt values in the device tree * on the gatwick mac-io controller used by some PowerBooks + * + * Walking of OF nodes could use a bit more fixing up here, but it's not + * very important as this is all boot time code on static portions of the + * device-tree. + * + * However, the modifications done to "intrs" will have to be removed and + * replaced with proper updates of the "interrupts" properties or + * AAPL,interrupts, yet to be decided, once the dynamic parsing is there. */ -static void __init -pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, + int irq_base) { struct device_node *node; int count; memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); - node = gw->child; count = 0; - while(node) - { + for (node = NULL; (node = of_get_next_child(gw, node)) != NULL;) { /* Fix SCC */ - if (strcasecmp(node->name, "escc") == 0) - if (node->child) { - if (node->child->n_intrs < 3) { - node->child->intrs = &gatwick_int_pool[count]; - count += 3; - } - node->child->n_intrs = 3; - node->child->intrs[0].line = 15+irq_base; - node->child->intrs[1].line = 4+irq_base; - node->child->intrs[2].line = 5+irq_base; - printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", - node->child->intrs[0].line, - node->child->intrs[1].line, - node->child->intrs[2].line); + if ((strcasecmp(node->name, "escc") == 0) && node->child) { + if (node->child->n_intrs < 3) { + node->child->intrs = &gatwick_int_pool[count]; + count += 3; } + node->child->n_intrs = 3; + node->child->intrs[0].line = 15+irq_base; + node->child->intrs[1].line = 4+irq_base; + node->child->intrs[2].line = 5+irq_base; + printk(KERN_INFO "irq: fixed SCC on gatwick" + " (%d,%d,%d)\n", + node->child->intrs[0].line, + node->child->intrs[1].line, + node->child->intrs[2].line); + } /* Fix media-bay & left SWIM */ if (strcasecmp(node->name, "media-bay") == 0) { struct device_node* ya_node; @@ -292,12 +290,11 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) node->intrs = &gatwick_int_pool[count++]; node->n_intrs = 1; node->intrs[0].line = 29+irq_base; - printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", - node->intrs[0].line); + printk(KERN_INFO "irq: fixed media-bay on gatwick" + " (%d)\n", node->intrs[0].line); ya_node = node->child; - while(ya_node) - { + while(ya_node) { if (strcasecmp(ya_node->name, "floppy") == 0) { if (ya_node->n_intrs < 2) { ya_node->intrs = &gatwick_int_pool[count]; @@ -323,7 +320,6 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) ya_node = ya_node->sibling; } } - node = node->sibling; } if (count > 10) { printk("WARNING !! Gatwick interrupt pool overflow\n"); @@ -338,45 +334,41 @@ pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) * controller. If we find this second ohare, set it up and fix the * interrupt value in the device tree for the ethernet chip. */ -static int __init enable_second_ohare(void) +static void __init enable_second_ohare(struct device_node *np) { unsigned char bus, devfn; unsigned short cmd; - unsigned long addr; - struct device_node *irqctrler = find_devices("pci106b,7"); struct device_node *ether; - if (irqctrler == NULL || irqctrler->n_addrs <= 0) - return -1; - addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); - pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); - max_irqs = 64; - if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) { - struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler); - if (!hose) - printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); - else { - early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - cmd &= ~PCI_COMMAND_IO; - early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); + /* This code doesn't strictly belong here, it could be part of + * either the PCI initialisation or the feature code. It's kept + * here for historical reasons. + */ + if (pci_device_from_OF_node(np, &bus, &devfn) == 0) { + struct pci_controller* hose = + pci_find_hose_for_OF_device(np); + if (!hose) { + printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); + return; } + early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + cmd &= ~PCI_COMMAND_IO; + early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); } /* Fix interrupt for the modem/ethernet combo controller. The number - in the device tree (27) is bogus (correct for the ethernet-only - board but not the combo ethernet/modem board). - The real interrupt is 28 on the second controller -> 28+32 = 60. - */ - ether = find_devices("pci1011,14"); + * in the device tree (27) is bogus (correct for the ethernet-only + * board but not the combo ethernet/modem board). + * The real interrupt is 28 on the second controller -> 28+32 = 60. + */ + ether = of_find_node_by_name(NULL, "pci1011,14"); if (ether && ether->n_intrs > 0) { ether->intrs[0].line = 60; printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", ether->intrs[0].line); } - - /* Return the interrupt number of the cascade */ - return irqctrler->intrs[0].line; + of_node_put(ether); } #ifdef CONFIG_XMON @@ -394,189 +386,233 @@ static struct irqaction gatwick_cascade_action = { .mask = CPU_MASK_NONE, .name = "cascade", }; -#endif /* CONFIG_PPC32 */ -static int pmac_u3_cascade(struct pt_regs *regs, void *data) +static void __init pmac_pic_probe_oldstyle(void) { - return mpic_get_one_irq((struct mpic *)data, regs); -} - -void __init pmac_pic_init(void) -{ - struct device_node *irqctrler = NULL; - struct device_node *irqctrler2 = NULL; - struct device_node *np; -#ifdef CONFIG_PPC32 int i; - unsigned long addr; int irq_cascade = -1; -#endif - struct mpic *mpic1, *mpic2; + struct device_node *master = NULL; + struct device_node *slave = NULL; + u8 __iomem *addr; + struct resource r; - /* We first try to detect Apple's new Core99 chipset, since mac-io - * is quite different on those machines and contains an IBM MPIC2. - */ - np = find_type_devices("open-pic"); - while (np) { - if (np->parent && !strcmp(np->parent->name, "u3")) - irqctrler2 = np; - else - irqctrler = np; - np = np->next; - } - if (irqctrler != NULL && irqctrler->n_addrs > 0) { - unsigned char senses[128]; - - printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", - (unsigned int)irqctrler->addrs[0].address); - pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); - - prom_get_irq_senses(senses, 0, 128); - mpic1 = mpic_alloc(irqctrler->addrs[0].address, - MPIC_PRIMARY | MPIC_WANTS_RESET, - 0, 0, 128, 252, senses, 128, " OpenPIC "); - BUG_ON(mpic1 == NULL); - mpic_init(mpic1); - - if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && - irqctrler2->n_addrs > 0) { - printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", - (u32)irqctrler2->addrs[0].address, - irqctrler2->intrs[0].line); - - pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); - prom_get_irq_senses(senses, 128, 128 + 124); - - /* We don't need to set MPIC_BROKEN_U3 here since we don't have - * hypertransport interrupts routed to it - */ - mpic2 = mpic_alloc(irqctrler2->addrs[0].address, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, - 0, 128, 124, 0, senses, 124, - " U3-MPIC "); - BUG_ON(mpic2 == NULL); - mpic_init(mpic2); - mpic_setup_cascade(irqctrler2->intrs[0].line, - pmac_u3_cascade, mpic2); - } -#if defined(CONFIG_XMON) && defined(CONFIG_PPC32) - { - struct device_node* pswitch; - int nmi_irq; - - pswitch = find_devices("programmer-switch"); - if (pswitch && pswitch->n_intrs) { - nmi_irq = pswitch->intrs[0].line; - mpic_irq_set_priority(nmi_irq, 9); - setup_irq(nmi_irq, &xmon_action); - } - } -#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */ - return; - } - irqctrler = NULL; + /* Set our get_irq function */ + ppc_md.get_irq = pmac_get_irq; -#ifdef CONFIG_PPC32 - /* Get the level/edge settings, assume if it's not - * a Grand Central nor an OHare, then it's an Heathrow - * (or Paddington). + /* + * Find the interrupt controller type & node */ - ppc_md.get_irq = pmac_get_irq; - if (find_devices("gc")) + + if ((master = of_find_node_by_name(NULL, "gc")) != NULL) { + max_irqs = max_real_irqs = 32; level_mask[0] = GC_LEVEL_MASK; - else if (find_devices("ohare")) { + } else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) { + max_irqs = max_real_irqs = 32; level_mask[0] = OHARE_LEVEL_MASK; + /* We might have a second cascaded ohare */ - level_mask[1] = OHARE_LEVEL_MASK; - } else { + slave = of_find_node_by_name(NULL, "pci106b,7"); + if (slave) { + max_irqs = 64; + level_mask[1] = OHARE_LEVEL_MASK; + enable_second_ohare(slave); + } + } else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) { + max_irqs = max_real_irqs = 64; level_mask[0] = HEATHROW_LEVEL_MASK; level_mask[1] = 0; + /* We might have a second cascaded heathrow */ - level_mask[2] = HEATHROW_LEVEL_MASK; - level_mask[3] = 0; - } + slave = of_find_node_by_name(master, "mac-io"); + + /* Check ordering of master & slave */ + if (device_is_compatible(master, "gatwick")) { + struct device_node *tmp; + BUG_ON(slave == NULL); + tmp = master; + master = slave; + slave = tmp; + } - /* - * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, - * 1998 G3 Series PowerBooks have 128, - * other powermacs have 32. - * The combo ethernet/modem card for the Powerstar powerbooks - * (2400/3400/3500, ohare based) has a second ohare chip - * effectively making a total of 64. - */ - max_irqs = max_real_irqs = 32; - irqctrler = find_devices("mac-io"); - if (irqctrler) - { - max_real_irqs = 64; - if (irqctrler->next) + /* We found a slave */ + if (slave) { max_irqs = 128; - else - max_irqs = 64; + level_mask[2] = HEATHROW_LEVEL_MASK; + level_mask[3] = 0; + pmac_fix_gatwick_interrupts(slave, max_real_irqs); + } } + BUG_ON(master == NULL); + + /* Set the handler for the main PIC */ for ( i = 0; i < max_real_irqs ; i++ ) irq_desc[i].handler = &pmac_pic; - /* get addresses of first controller */ - if (irqctrler) { - if (irqctrler->n_addrs > 0) { - addr = (unsigned long) - ioremap(irqctrler->addrs[0].address, 0x40); - for (i = 0; i < 2; ++i) - pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) - (addr + (2 - i) * 0x10); - } + /* Get addresses of first controller if we have a node for it */ + BUG_ON(of_address_to_resource(master, 0, &r)); - /* get addresses of second controller */ - irqctrler = irqctrler->next; - if (irqctrler && irqctrler->n_addrs > 0) { - addr = (unsigned long) - ioremap(irqctrler->addrs[0].address, 0x40); - for (i = 2; i < 4; ++i) - pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) - (addr + (4 - i) * 0x10); - irq_cascade = irqctrler->intrs[0].line; - if (device_is_compatible(irqctrler, "gatwick")) - pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); - } - } else { - /* older powermacs have a GC (grand central) or ohare at - f3000000, with interrupt control registers at f3000020. */ - addr = (unsigned long) ioremap(0xf3000000, 0x40); - pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); + /* Map interrupts of primary controller */ + addr = (u8 __iomem *) ioremap(r.start, 0x40); + i = 0; + pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *) + (addr + 0x20); + if (max_real_irqs > 32) + pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *) + (addr + 0x10); + of_node_put(master); + + printk(KERN_INFO "irq: Found primary Apple PIC %s for %d irqs\n", + master->full_name, max_real_irqs); + + /* Map interrupts of cascaded controller */ + if (slave && !of_address_to_resource(slave, 0, &r)) { + addr = (u8 __iomem *)ioremap(r.start, 0x40); + pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *) + (addr + 0x20); + if (max_irqs > 64) + pmac_irq_hw[i++] = + (volatile struct pmac_irq_hw __iomem *) + (addr + 0x10); + irq_cascade = slave->intrs[0].line; + + printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs" + " cascade: %d\n", slave->full_name, + max_irqs - max_real_irqs, irq_cascade); } - - /* PowerBooks 3400 and 3500 can have a second controller in a second - ohare chip, on the combo ethernet/modem card */ - if (machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500")) - irq_cascade = enable_second_ohare(); + of_node_put(slave); /* disable all interrupts in all controllers */ for (i = 0; i * 32 < max_irqs; ++i) out_le32(&pmac_irq_hw[i]->enable, 0); + /* mark level interrupts */ for (i = 0; i < max_irqs; i++) if (level_mask[i >> 5] & (1UL << (i & 0x1f))) irq_desc[i].status = IRQ_LEVEL; - /* get interrupt line of secondary interrupt controller */ - if (irq_cascade >= 0) { - printk(KERN_INFO "irq: secondary controller on irq %d\n", - (int)irq_cascade); + /* Setup handlers for secondary controller and hook cascade irq*/ + if (slave) { for ( i = max_real_irqs ; i < max_irqs ; i++ ) irq_desc[i].handler = &gatwick_pic; setup_irq(irq_cascade, &gatwick_cascade_action); } - printk("System has %d possible interrupts\n", max_irqs); - if (max_irqs != max_real_irqs) - printk(KERN_DEBUG "%d interrupts on main controller\n", - max_real_irqs); - + printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); #ifdef CONFIG_XMON setup_irq(20, &xmon_action); -#endif /* CONFIG_XMON */ -#endif /* CONFIG_PPC32 */ +#endif +} +#endif /* CONFIG_PPC32 */ + +static int pmac_u3_cascade(struct pt_regs *regs, void *data) +{ + return mpic_get_one_irq((struct mpic *)data, regs); +} + +static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) +{ +#if defined(CONFIG_XMON) && defined(CONFIG_PPC32) + struct device_node* pswitch; + int nmi_irq; + + pswitch = of_find_node_by_name(NULL, "programmer-switch"); + if (pswitch && pswitch->n_intrs) { + nmi_irq = pswitch->intrs[0].line; + mpic_irq_set_priority(nmi_irq, 9); + setup_irq(nmi_irq, &xmon_action); + } + of_node_put(pswitch); +#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */ +} + +static int __init pmac_pic_probe_mpic(void) +{ + struct mpic *mpic1, *mpic2; + struct device_node *np, *master = NULL, *slave = NULL; + unsigned char senses[128]; + struct resource r; + + /* We can have up to 2 MPICs cascaded */ + for (np = NULL; (np = of_find_node_by_type(np, "open-pic")) + != NULL;) { + if (master == NULL && + get_property(np, "interrupt-parent", NULL) != NULL) + master = of_node_get(np); + else if (slave == NULL) + slave = of_node_get(np); + if (master && slave) + break; + } + + /* Check for bogus setups */ + if (master == NULL && slave != NULL) { + master = slave; + slave = NULL; + } + + /* Not found, default to good old pmac pic */ + if (master == NULL) + return -ENODEV; + + /* Set master handler */ + ppc_md.get_irq = mpic_get_irq; + + /* Setup master */ + BUG_ON(of_address_to_resource(master, 0, &r)); + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, master, 0, 0); + prom_get_irq_senses(senses, 0, 128); + mpic1 = mpic_alloc(r.start, MPIC_PRIMARY | MPIC_WANTS_RESET, + 0, 0, 128, 252, senses, 128, " OpenPIC "); + BUG_ON(mpic1 == NULL); + mpic_init(mpic1); + + /* Install NMI if any */ + pmac_pic_setup_mpic_nmi(mpic1); + + of_node_put(master); + + /* No slave, let's go out */ + if (slave == NULL || slave->n_intrs < 1) + return 0; + + /* Setup slave, failures are non-fatal */ + if (of_address_to_resource(slave, 0, &r)) { + printk(KERN_ERR "Can't get address of MPIC %s\n", + slave->full_name); + return 0; + } + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, slave, 0, 0); + prom_get_irq_senses(senses, 128, 128 + 124); + + /* We don't need to set MPIC_BROKEN_U3 here since we don't have + * hypertransport interrupts routed to it, at least not on currently + * supported machines, that may change. + */ + mpic2 = mpic_alloc(r.start, MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, + 0, 128, 124, 0, senses, 124, " U3-MPIC "); + if (mpic2 == NULL) { + printk(KERN_ERR "Can't create slave MPIC %s\n", + slave->full_name); + return 0; + } + mpic_init(mpic2); + mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2); + + of_node_put(slave); + return 0; +} + + +void __init pmac_pic_init(void) +{ + /* We first try to detect Apple's new Core99 chipset, since mac-io + * is quite different on those machines and contains an IBM MPIC2. + */ + if (pmac_pic_probe_mpic() == 0) + return; + +#ifdef CONFIG_PPC32 + pmac_pic_probe_oldstyle(); +#endif } #if defined(CONFIG_PM) && defined(CONFIG_PPC32) diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 2ad25e13423e..21c7b0f8f329 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -42,10 +42,6 @@ extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq); extern int pmac_nvram_init(void); - -extern struct hw_interrupt_type pmac_pic; - -void pmac_pic_init(void); -int pmac_get_irq(struct pt_regs *regs); +extern void pmac_pic_init(void); #endif /* __PMAC_H__ */ diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index c0638e47c298..18c5620f87fa 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -75,7 +75,6 @@ #include #include #include -#include #include #include @@ -751,7 +750,7 @@ struct machdep_calls __initdata pmac_md = { .init_early = pmac_init_early, .show_cpuinfo = pmac_show_cpuinfo, .init_IRQ = pmac_pic_init, - .get_irq = mpic_get_irq, /* changed later */ + .get_irq = NULL, /* changed later */ .pcibios_fixup = pmac_pcibios_fixup, .restart = pmac_restart, .power_off = pmac_power_off, diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index feb0a94e7819..5d9afa1fa02d 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -258,15 +258,20 @@ int __init via_calibrate_decr(void) volatile unsigned char __iomem *via; int count = VIA_TIMER_FREQ_6 / 100; unsigned int dstart, dend; + struct resource rsrc; - vias = find_devices("via-cuda"); + vias = of_find_node_by_name(NULL, "via-cuda"); if (vias == 0) - vias = find_devices("via-pmu"); + vias = of_find_node_by_name(NULL, "via-pmu"); if (vias == 0) - vias = find_devices("via"); - if (vias == 0 || vias->n_addrs == 0) + vias = of_find_node_by_name(NULL, "via"); + if (vias == 0 || of_address_to_resource(vias, 0, &rsrc)) return 0; - via = ioremap(vias->addrs[0].address, vias->addrs[0].size); + via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); + if (via == NULL) { + printk(KERN_ERR "Failed to map VIA for timer calibration !\n"); + return 0; + } /* set timer 1 for continuous interrupts */ out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index af7cb2bfd670..01f042f6f1c4 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -1083,23 +1083,33 @@ static int swim3_add_device(struct device_node *swim) { struct device_node *mediabay; struct floppy_state *fs = &floppy_states[floppy_count]; + struct resource res_reg, res_dma; - if (swim->n_addrs < 2) - { - printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n", - swim->n_addrs, swim->n_intrs); + if (of_address_to_resource(swim, 0, &res_reg) || + of_address_to_resource(swim, 1, &res_dma)) { + printk(KERN_ERR "swim3: Can't get addresses\n"); return -EINVAL; } - - if (swim->n_intrs < 2) - { - printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n", - swim->n_addrs, swim->n_intrs); + if (request_mem_region(res_reg.start, res_reg.end - res_reg.start + 1, + " (reg)") == NULL) { + printk(KERN_ERR "swim3: Can't request register space\n"); + return -EINVAL; + } + if (request_mem_region(res_dma.start, res_dma.end - res_dma.start + 1, + " (dma)") == NULL) { + release_mem_region(res_reg.start, + res_reg.end - res_reg.start + 1); + printk(KERN_ERR "swim3: Can't request DMA space\n"); return -EINVAL; } - if (!request_OF_resource(swim, 0, NULL)) { - printk(KERN_INFO "swim3: can't request IO resource !\n"); + if (swim->n_intrs < 2) { + printk(KERN_INFO "swim3: expecting 2 intrs (n_intrs:%d)\n", + swim->n_intrs); + release_mem_region(res_reg.start, + res_reg.end - res_reg.start + 1); + release_mem_region(res_dma.start, + res_dma.end - res_dma.start + 1); return -EINVAL; } @@ -1110,10 +1120,8 @@ static int swim3_add_device(struct device_node *swim) memset(fs, 0, sizeof(*fs)); spin_lock_init(&fs->lock); fs->state = idle; - fs->swim3 = (struct swim3 __iomem *) - ioremap(swim->addrs[0].address, 0x200); - fs->dma = (struct dbdma_regs __iomem *) - ioremap(swim->addrs[1].address, 0x200); + fs->swim3 = (struct swim3 __iomem *)ioremap(res_reg.start, 0x200); + fs->dma = (struct dbdma_regs __iomem *)ioremap(res_dma.start, 0x200); fs->swim3_intr = swim->intrs[0].line; fs->dma_intr = swim->intrs[1].line; fs->cur_cyl = -1; diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 16b28357885b..a8d3bc0a9c5c 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1271,7 +1271,7 @@ static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) { struct device_node *np = pmif->node; - int *bidp, i; + int *bidp; pmif->cable_80 = 0; pmif->broken_dma = pmif->broken_dma_warn = 0; @@ -1430,7 +1430,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) pmif = &pmac_ide[i]; hwif = &ide_hwifs[i]; - if (mdev->ofdev.node->n_addrs == 0) { + if (macio_resource_count(mdev) == 0) { printk(KERN_WARNING "ide%d: no address for %s\n", i, mdev->ofdev.node->full_name); return -ENXIO; diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 0137ff239f13..2a545ceb523b 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -256,42 +256,42 @@ static int macio_resource_quirks(struct device_node *np, struct resource *res, { if (res->flags & IORESOURCE_MEM) { /* Grand Central has too large resource 0 on some machines */ - if (index == 0 && !strcmp(np->name, "gc")) { - np->addrs[0].size = 0x20000; + if (index == 0 && !strcmp(np->name, "gc")) res->end = res->start + 0x1ffff; - } + /* Airport has bogus resource 2 */ if (index >= 2 && !strcmp(np->name, "radio")) return 1; + +#ifndef CONFIG_PPC64 /* DBDMAs may have bogus sizes */ - if ((res->start & 0x0001f000) == 0x00008000) { - np->addrs[index].size = 0x100; + if ((res->start & 0x0001f000) == 0x00008000) res->end = res->start + 0xff; - } +#endif /* CONFIG_PPC64 */ + /* ESCC parent eats child resources. We could have added a * level of hierarchy, but I don't really feel the need * for it */ if (!strcmp(np->name, "escc")) return 1; + /* ESCC has bogus resources >= 3 */ if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b"))) return 1; + /* Media bay has too many resources, keep only first one */ if (index > 0 && !strcmp(np->name, "media-bay")) return 1; + /* Some older IDE resources have bogus sizes */ if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") && strcmp(np->type, "ide") && strcmp(np->type, "ata"))) { - if (index == 0 && np->addrs[0].size > 0x1000) { - np->addrs[0].size = 0x1000; + if (index == 0 && (res->end - res->start) > 0xfff) res->end = res->start + 0xfff; - } - if (index == 1 && np->addrs[1].size > 0x100) { - np->addrs[1].size = 0x100; + if (index == 1 && (res->end - res->start) > 0xff) res->end = res->start + 0xff; - } } } return 0; @@ -349,7 +349,7 @@ static void macio_setup_resources(struct macio_dev *dev, /* Currently, we consider failure as harmless, this may * change in the future, once I've found all the device * tree bugs in older machines & worked around them -l */ + */ if (insert_resource(parent_res, res)) { printk(KERN_WARNING "Can't request resource " "%d for MacIO device %s\n", diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index b856bb67169c..8dbf2852bae0 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -647,6 +647,7 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de struct media_bay_info* bay; u32 __iomem *regbase; struct device_node *ofnode; + unsigned long base; int i; ofnode = mdev->ofdev.node; @@ -656,10 +657,11 @@ static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_de if (macio_request_resources(mdev, "media-bay")) return -EBUSY; /* Media bay registers are located at the beginning of the - * mac-io chip, we get the parent address for now (hrm...) + * mac-io chip, for now, we trick and align down the first + * resource passed in */ - regbase = (u32 __iomem *) - ioremap(ofnode->parent->addrs[0].address, 0x100); + base = macio_resource_start(mdev, 0) & 0xffff0000u; + regbase = (u32 __iomem *)ioremap(base, 0x100); if (regbase == NULL) { macio_release_resources(mdev); return -ENOMEM; diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 18ff770ea668..2d9d79150403 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -193,10 +193,6 @@ static int __init via_cuda_start(void) if (via == NULL) return -ENODEV; -#ifdef CONFIG_PPC - request_OF_resource(vias, 0, NULL); -#endif - if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); return -EAGAIN; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index d6dabee55f2f..79c7b44a94ee 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -298,7 +298,7 @@ static struct backlight_controller pmu_backlight_controller = { int __init find_via_pmu(void) { - phys_addr_t taddr; + u64 taddr; u32 *reg; if (via != 0) @@ -337,7 +337,7 @@ int __init find_via_pmu(void) else if (device_is_compatible(vias->parent, "Keylargo") || device_is_compatible(vias->parent, "K2-Keylargo")) { struct device_node *gpiop; - phys_addr_t gaddr = 0; + u64 gaddr = OF_BAD_ADDR; pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); @@ -352,7 +352,7 @@ int __init find_via_pmu(void) reg = (u32 *)get_property(gpiop, "reg", NULL); if (reg) gaddr = of_translate_address(gpiop, reg); - if (gaddr != 0) + if (gaddr != OF_BAD_ADDR) gpio_reg = ioremap(gaddr, 0x10); } if (gpio_reg == NULL) @@ -479,9 +479,6 @@ static int __init via_pmu_dev_init(void) if (vias == NULL) return -ENODEV; -#ifndef CONFIG_PPC64 - request_OF_resource(vias, 0, NULL); -#endif #ifdef CONFIG_PMAC_BACKLIGHT /* Enable backlight */ register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 932dcf0366eb..311a4122bd70 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -432,11 +432,12 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat struct Scsi_Host *host; void *dma_cmd_space; unsigned char *clkprop; - int proplen; + int proplen, rc = -ENODEV; if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) { - printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n", - node->n_addrs, node->n_intrs); + printk(KERN_ERR "mac53c94: expected 2 addrs and intrs" + " (got %d/%d)\n", + macio_resource_count(mdev), macio_irq_count(mdev)); return -ENODEV; } @@ -448,6 +449,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state)); if (host == NULL) { printk(KERN_ERR "mac53c94: couldn't register host"); + rc = -ENOMEM; goto out_release; } @@ -486,6 +488,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat if (dma_cmd_space == 0) { printk(KERN_ERR "mac53c94: couldn't allocate dma " "command space for %s\n", node->full_name); + rc = -ENOMEM; goto out_free; } state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space); @@ -495,18 +498,21 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat mac53c94_init(state); - if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) { + if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94",state)) { printk(KERN_ERR "mac53C94: can't get irq %d for %s\n", state->intr, node->full_name); goto out_free_dma; } - /* XXX FIXME: handle failure */ - scsi_add_host(host, &mdev->ofdev.dev); - scsi_scan_host(host); + rc = scsi_add_host(host, &mdev->ofdev.dev); + if (rc != 0) + goto out_release_irq; + scsi_scan_host(host); return 0; + out_release_irq: + free_irq(state->intr, state); out_free_dma: kfree(state->dma_cmd_space); out_free: @@ -518,7 +524,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat out_release: macio_release_resources(mdev); - return -ENODEV; + return rc; } static int mac53c94_remove(struct macio_dev *mdev) diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index bdccf73cf9fe..d6d2125f9044 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1869,7 +1869,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) { printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs" - " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs); + " (got %d,%d)\n", macio_resource_count(mdev), + macio_irq_count(mdev)); return -ENODEV; } diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 5ddd8ab1f108..ea24129eb6b9 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1431,11 +1431,14 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) char name[1]; } *slots; int len; + struct resource r_ports, r_rxdma, r_txdma; /* * Request & map chip registers */ - uap->port.mapbase = np->addrs[0].address; + if (of_address_to_resource(np, 0, &r_ports)) + return -ENODEV; + uap->port.mapbase = r_ports.start; uap->port.membase = ioremap(uap->port.mapbase, 0x1000); uap->control_reg = uap->port.membase; @@ -1445,16 +1448,20 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) * Request & map DBDMA registers */ #ifdef HAS_DBDMA - if (np->n_addrs >= 3 && np->n_intrs >= 3) + if (of_address_to_resource(np, 1, &r_txdma) == 0 && + of_address_to_resource(np, 2, &r_rxdma) == 0) uap->flags |= PMACZILOG_FLAG_HAS_DMA; +#else + memset(&r_txdma, 0, sizeof(struct resource)); + memset(&r_rxdma, 0, sizeof(struct resource)); #endif if (ZS_HAS_DMA(uap)) { - uap->tx_dma_regs = ioremap(np->addrs[np->n_addrs - 2].address, 0x1000); + uap->tx_dma_regs = ioremap(r_txdma.start, 0x100); if (uap->tx_dma_regs == NULL) { uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; goto no_dma; } - uap->rx_dma_regs = ioremap(np->addrs[np->n_addrs - 1].address, 0x1000); + uap->rx_dma_regs = ioremap(r_rxdma.start, 0x100); if (uap->rx_dma_regs == NULL) { iounmap(uap->tx_dma_regs); uap->tx_dma_regs = NULL; diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 403d17377f8d..03798e9c882d 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -133,12 +133,6 @@ static int controlfb_mmap(struct fb_info *info, struct file *file, static int controlfb_set_par (struct fb_info *info); static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info); -/* - * inititialization - */ -int control_init(void); -void control_setup(char *); - /******************** Prototypes for internal functions **********************/ static void set_control_clock(unsigned char *params); @@ -550,9 +544,46 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro /* - * Called from fbmem.c for probing & initializing + * Parse user speficied options (`video=controlfb:') */ -int __init control_init(void) +static void __init control_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "vmode:", 6)) { + int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX && + control_mac_modes[vmode - 1].m[1] >= 0) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + int depth = simple_strtoul(this_opt+6, NULL, 0); + switch (depth) { + case CMODE_8: + case CMODE_16: + case CMODE_32: + default_cmode = depth; + break; + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } + } +} + +static int __init control_init(void) { struct device_node *dp; char *option = NULL; @@ -651,15 +682,16 @@ static void __init find_vram_size(struct fb_info_control *p) static int __init control_of_init(struct device_node *dp) { struct fb_info_control *p; - unsigned long addr; - int i; + struct resource fb_res, reg_res; if (control_fb) { printk(KERN_ERR "controlfb: only one control is supported\n"); return -ENXIO; } - if(dp->n_addrs != 2) { - printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs); + + if (of_pci_address_to_resource(dp, 2, &fb_res) || + of_pci_address_to_resource(dp, 1, ®_res)) { + printk(KERN_ERR "can't get 2 addresses for control\n"); return -ENXIO; } p = kmalloc(sizeof(*p), GFP_KERNEL); @@ -669,18 +701,12 @@ static int __init control_of_init(struct device_node *dp) memset(p, 0, sizeof(*p)); /* Map in frame buffer and registers */ - for (i = 0; i < dp->n_addrs; ++i) { - addr = dp->addrs[i].address; - if (dp->addrs[i].size >= 0x800000) { - p->fb_orig_base = addr; - p->fb_orig_size = dp->addrs[i].size; - /* use the big-endian aperture (??) */ - p->frame_buffer_phys = addr + 0x800000; - } else { - p->control_regs_phys = addr; - p->control_regs_size = dp->addrs[i].size; - } - } + p->fb_orig_base = fb_res.start; + p->fb_orig_size = fb_res.end - fb_res.start + 1; + /* use the big-endian aperture (??) */ + p->frame_buffer_phys = fb_res.start + 0x800000; + p->control_regs_phys = reg_res.start; + p->control_regs_size = reg_res.end - reg_res.start + 1; if (!p->fb_orig_base || !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) { @@ -1059,43 +1085,3 @@ static void control_cleanup(void) } -/* - * Parse user speficied options (`video=controlfb:') - */ -void __init control_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!strncmp(this_opt, "vmode:", 6)) { - int vmode = simple_strtoul(this_opt+6, NULL, 0); - if (vmode > 0 && vmode <= VMODE_MAX && - control_mac_modes[vmode - 1].m[1] >= 0) - default_vmode = vmode; - } else if (!strncmp(this_opt, "cmode:", 6)) { - int depth = simple_strtoul(this_opt+6, NULL, 0); - switch (depth) { - case CMODE_8: - case CMODE_16: - case CMODE_32: - default_cmode = depth; - break; - case 8: - default_cmode = CMODE_8; - break; - case 15: - case 16: - default_cmode = CMODE_16; - break; - case 24: - case 32: - default_cmode = CMODE_32; - break; - } - } - } -} - diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 00d87f5bb7be..ad1434e3f227 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -223,6 +223,7 @@ static int offb_blank(int blank, struct fb_info *info) int __init offb_init(void) { struct device_node *dp = NULL, *boot_disp = NULL; + #if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) struct device_node *macos_display = NULL; #endif @@ -234,60 +235,54 @@ int __init offb_init(void) if (boot_infos != 0) { unsigned long addr = (unsigned long) boot_infos->dispDeviceBase; + u32 *addrp; + u64 daddr, dsize; + unsigned int flags; + /* find the device node corresponding to the macos display */ while ((dp = of_find_node_by_type(dp, "display"))) { int i; - /* - * Grrr... It looks like the MacOS ATI driver - * munges the assigned-addresses property (but - * the AAPL,address value is OK). - */ - if (strncmp(dp->name, "ATY,", 4) == 0 - && dp->n_addrs == 1) { - unsigned int *ap = - (unsigned int *) get_property(dp, - "AAPL,address", - NULL); - if (ap != NULL) { - dp->addrs[0].address = *ap; - dp->addrs[0].size = 0x01000000; - } - } /* - * The LTPro on the Lombard powerbook has no addresses - * on the display nodes, they are on their parent. + * Look for an AAPL,address property first. */ - if (dp->n_addrs == 0 - && device_is_compatible(dp, "ATY,264LTPro")) { - int na; - unsigned int *ap = (unsigned int *) - get_property(dp, "AAPL,address", &na); - if (ap != 0) - for (na /= sizeof(unsigned int); - na > 0; --na, ++ap) - if (*ap <= addr - && addr < - *ap + 0x1000000) - goto foundit; + unsigned int na; + unsigned int *ap = + (unsigned int *)get_property(dp, "AAPL,address", + &na); + if (ap != 0) { + for (na /= sizeof(unsigned int); na > 0; + --na, ++ap) + if (*ap <= addr && + addr < *ap + 0x1000000) { + macos_display = dp; + goto foundit; + } } /* * See if the display address is in one of the address * ranges for this display. */ - for (i = 0; i < dp->n_addrs; ++i) { - if (dp->addrs[i].address <= addr - && addr < - dp->addrs[i].address + - dp->addrs[i].size) + i = 0; + for (;;) { + addrp = of_get_address(dp, i++, &dsize, &flags); + if (addrp == NULL) break; + if (!(flags & IORESOURCE_MEM)) + continue; + daddr = of_translate_address(dp, addrp); + if (daddr == OF_BAD_ADDR) + continue; + if (daddr <= addr && addr < (daddr + dsize)) { + macos_display = dp; + goto foundit; + } } - if (i < dp->n_addrs) { - foundit: + foundit: + if (macos_display) { printk(KERN_INFO "MacOS display is %s\n", dp->full_name); - macos_display = dp; break; } } @@ -326,8 +321,10 @@ static void __init offb_init_nodriver(struct device_node *dp) int *pp, i; unsigned int len; int width = 640, height = 480, depth = 8, pitch; - unsigned int rsize, *up; - unsigned long address = 0; + unsigned int flags, rsize, *up; + u64 address = OF_BAD_ADDR; + u32 *addrp; + u64 asize; if ((pp = (int *) get_property(dp, "depth", &len)) != NULL && len == sizeof(int)) @@ -363,7 +360,7 @@ static void __init offb_init_nodriver(struct device_node *dp) break; } if (pdev) { - for (i = 0; i < 6 && address == 0; i++) { + for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) { if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) && (pci_resource_len(pdev, i) >= rsize)) @@ -374,27 +371,33 @@ static void __init offb_init_nodriver(struct device_node *dp) } #endif /* CONFIG_PCI */ - if (address == 0 && - (up = (unsigned *) get_property(dp, "address", &len)) != NULL && - len == sizeof(unsigned)) - address = (u_long) * up; - if (address == 0) { - for (i = 0; i < dp->n_addrs; ++i) - if (dp->addrs[i].size >= - pitch * height * depth / 8) - break; - if (i >= dp->n_addrs) { + /* This one is dodgy, we may drop it ... */ + if (address == OF_BAD_ADDR && + (up = (unsigned *) get_property(dp, "address", &len)) != NULL && + len == sizeof(unsigned int)) + address = (u64) * up; + + if (address == OF_BAD_ADDR) { + for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags)) + != NULL; i++) { + if (!(flags & IORESOURCE_MEM)) + continue; + if (asize >= pitch * height * depth / 8) + break; + } + if (addrp == NULL) { printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name); return; } - - address = (u_long) dp->addrs[i].address; - -#ifdef CONFIG_PPC64 - address += ((struct pci_dn *)dp->data)->phb->pci_mem_offset; -#endif + address = of_translate_address(dp, addrp); + if (address == OF_BAD_ADDR) { + printk(KERN_ERR + "can't translate framebuffer address for %s\n", + dp->full_name); + return; + } /* kludge for valkyrie */ if (strcmp(dp->name, "valkyrie") == 0) @@ -459,7 +462,9 @@ static void __init offb_init_fb(const char *name, const char *full_name, par->cmap_type = cmap_unknown; if (depth == 8) { - /* XXX kludge for ati */ + + /* Palette hacks disabled for now */ +#if 0 if (dp && !strncmp(name, "ATY,Rage128", 11)) { unsigned long regbase = dp->addrs[2].address; par->cmap_adr = ioremap(regbase, 0x1FFF); @@ -490,6 +495,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, par->cmap_adr = ioremap(regbase + 0x6000, 0x1000); par->cmap_type = cmap_gxt2000; } +#endif fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; } else diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index ba0af1b66bb6..335e37465559 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -69,6 +69,8 @@ struct fb_info_platinum { unsigned long total_vram; int clktype; int dactype; + + struct resource rsrc_fb, rsrc_reg; }; /* @@ -97,9 +99,6 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var, * Interface used by the world */ -int platinumfb_init(void); -int platinumfb_setup(char*); - static struct fb_ops platinumfb_ops = { .owner = THIS_MODULE, .fb_check_var = platinumfb_check_var, @@ -485,7 +484,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var, /* * Parse user speficied options (`video=platinumfb:') */ -int __init platinumfb_setup(char *options) +static int __init platinumfb_setup(char *options) { char *this_opt; @@ -526,19 +525,15 @@ int __init platinumfb_setup(char *options) #define invalidate_cache(addr) #endif -static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match) +static int __devinit platinumfb_probe(struct of_device* odev, + const struct of_device_id *match) { struct device_node *dp = odev->node; struct fb_info *info; struct fb_info_platinum *pinfo; - unsigned long addr, size; volatile __u8 *fbuffer; - int i, bank0, bank1, bank2, bank3, rc; + int bank0, bank1, bank2, bank3, rc; - if (dp->n_addrs != 2) { - printk(KERN_ERR "expecting 2 address for platinum (got %d)", dp->n_addrs); - return -ENXIO; - } printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n"); info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); @@ -546,26 +541,39 @@ static int __devinit platinumfb_probe(struct of_device* odev, const struct of_de return -ENOMEM; pinfo = info->par; - /* Map in frame buffer and registers */ - for (i = 0; i < dp->n_addrs; ++i) { - addr = dp->addrs[i].address; - size = dp->addrs[i].size; - /* Let's assume we can request either all or nothing */ - if (!request_mem_region(addr, size, "platinumfb")) { - framebuffer_release(info); - return -ENXIO; - } - if (size >= 0x400000) { - /* frame buffer - map only 4MB */ - pinfo->frame_buffer_phys = addr; - pinfo->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU); - pinfo->base_frame_buffer = pinfo->frame_buffer; - } else { - /* registers */ - pinfo->platinum_regs_phys = addr; - pinfo->platinum_regs = ioremap(addr, size); - } + if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) || + of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) { + printk(KERN_ERR "platinumfb: Can't get resources\n"); + framebuffer_release(info); + return -ENXIO; } + if (!request_mem_region(pinfo->rsrc_reg.start, + pinfo->rsrc_reg.start - + pinfo->rsrc_reg.end + 1, + "platinumfb registers")) { + framebuffer_release(info); + return -ENXIO; + } + if (!request_mem_region(pinfo->rsrc_fb.start, + pinfo->rsrc_fb.start + - pinfo->rsrc_fb.end + 1, + "platinumfb framebuffer")) { + release_mem_region(pinfo->rsrc_reg.start, + pinfo->rsrc_reg.end - + pinfo->rsrc_reg.start + 1); + framebuffer_release(info); + return -ENXIO; + } + + /* frame buffer - map only 4MB */ + pinfo->frame_buffer_phys = pinfo->rsrc_fb.start; + pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000, + _PAGE_WRITETHRU); + pinfo->base_frame_buffer = pinfo->frame_buffer; + + /* registers */ + pinfo->platinum_regs_phys = pinfo->rsrc_reg.start; + pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000); pinfo->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap"); @@ -628,18 +636,16 @@ static int __devexit platinumfb_remove(struct of_device* odev) { struct fb_info *info = dev_get_drvdata(&odev->dev); struct fb_info_platinum *pinfo = info->par; - struct device_node *dp = odev->node; - unsigned long addr, size; - int i; unregister_framebuffer (info); /* Unmap frame buffer and registers */ - for (i = 0; i < dp->n_addrs; ++i) { - addr = dp->addrs[i].address; - size = dp->addrs[i].size; - release_mem_region(addr, size); - } + release_mem_region(pinfo->rsrc_fb.start, + pinfo->rsrc_fb.end - + pinfo->rsrc_fb.start + 1); + release_mem_region(pinfo->rsrc_reg.start, + pinfo->rsrc_reg.end - + pinfo->rsrc_reg.start + 1); iounmap(pinfo->frame_buffer); iounmap(pinfo->platinum_regs); release_mem_region(pinfo->cmap_regs_phys, 0x1000); @@ -666,7 +672,7 @@ static struct of_platform_driver platinum_driver = .remove = platinumfb_remove, }; -int __init platinumfb_init(void) +static int __init platinumfb_init(void) { #ifndef MODULE char *option = NULL; @@ -680,7 +686,7 @@ int __init platinumfb_init(void) return 0; } -void __exit platinumfb_exit(void) +static void __exit platinumfb_exit(void) { of_unregister_driver(&platinum_driver); } diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index ce97ec8eae97..2bdeb4baa952 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -342,19 +342,19 @@ int __init valkyriefb_init(void) #else /* ppc (!CONFIG_MAC) */ { struct device_node *dp; + struct resource r; - dp = find_devices("valkyrie"); + dp = of_find_node_by_name(NULL, "valkyrie"); if (dp == 0) return 0; - if (dp->n_addrs != 1) { - printk(KERN_ERR "expecting 1 address for valkyrie (got %d)\n", - dp->n_addrs); + if (of_address_to_resource(dp, 0, &r)) { + printk(KERN_ERR "can't find address for valkyrie\n"); return 0; } - frame_buffer_phys = dp->addrs[0].address; - cmap_regs_phys = dp->addrs[0].address+0x304000; + frame_buffer_phys = r.start; + cmap_regs_phys = r.start + 0x304000; flags = _PAGE_WRITETHRU; } #endif /* ppc (!CONFIG_MAC) */ diff --git a/include/asm-powerpc/keylargo.h b/include/asm-powerpc/keylargo.h index a669a3f0f5a2..334d4c9356f3 100644 --- a/include/asm-powerpc/keylargo.h +++ b/include/asm-powerpc/keylargo.h @@ -232,10 +232,12 @@ #define K2_FCR1_I2S0_RESET 0x00000800 #define K2_FCR1_I2S0_CLK_ENABLE_BIT 0x00001000 #define K2_FCR1_I2S0_ENABLE 0x00002000 - #define K2_FCR1_PCI1_CLK_ENABLE 0x00004000 #define K2_FCR1_FW_CLK_ENABLE 0x00008000 #define K2_FCR1_FW_RESET_N 0x00010000 +#define K2_FCR1_I2S1_CELL_ENABLE 0x00020000 +#define K2_FCR1_I2S1_CLK_ENABLE_BIT 0x00080000 +#define K2_FCR1_I2S1_ENABLE 0x00100000 #define K2_FCR1_GMAC_CLK_ENABLE 0x00400000 #define K2_FCR1_GMAC_POWER_DOWN 0x00800000 #define K2_FCR1_GMAC_RESET_N 0x01000000 @@ -246,3 +248,9 @@ #define K2_FCR1_UATA_RESET_N 0x40000000 #define K2_FCR1_UATA_CHOOSE_CLK66 0x80000000 +/* Shasta definitions */ +#define SH_FCR1_I2S2_CELL_ENABLE 0x00000010 +#define SH_FCR1_I2S2_CLK_ENABLE_BIT 0x00000040 +#define SH_FCR1_I2S2_ENABLE 0x00000080 +#define SH_FCR3_I2S2_CLK18_ENABLE 0x00008000 + diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 73d27bad55fa..329e9bf62260 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -65,49 +65,11 @@ struct boot_param_header typedef u32 phandle; typedef u32 ihandle; -struct address_range { - unsigned long space; - unsigned long address; - unsigned long size; -}; - struct interrupt_info { int line; int sense; /* +ve/-ve logic, edge or level, etc. */ }; -struct pci_address { - u32 a_hi; - u32 a_mid; - u32 a_lo; -}; - -struct isa_address { - u32 a_hi; - u32 a_lo; -}; - -struct isa_range { - struct isa_address isa_addr; - struct pci_address pci_addr; - unsigned int size; -}; - -struct reg_property { - unsigned long address; - unsigned long size; -}; - -struct reg_property32 { - unsigned int address; - unsigned int size; -}; - -struct reg_property64 { - u64 address; - u64 size; -}; - struct property { char *name; int length; @@ -120,8 +82,6 @@ struct device_node { char *type; phandle node; phandle linux_phandle; - int n_addrs; - struct address_range *addrs; int n_intrs; struct interrupt_info *intrs; char *full_name; diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index cebd881b91ae..74f975676ccb 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -125,6 +125,7 @@ static int awacs_rate_index; static int awacs_subframe; static struct device_node* awacs_node; static struct device_node* i2s_node; +static struct resource awacs_rsrc[3]; static char awacs_name[64]; static int awacs_revision; @@ -667,9 +668,12 @@ static void PMacIrqCleanup(void) iounmap(awacs_txdma); iounmap(awacs_rxdma); - release_OF_resource(awacs_node, 0); - release_OF_resource(awacs_node, 1); - release_OF_resource(awacs_node, 2); + release_mem_region(awacs_rsrc[0].start, + awacs_rsrc[0].end - awacs_rsrc[0].start + 1); + release_mem_region(awacs_rsrc[1].start, + awacs_rsrc[1].end - awacs_rsrc[1].start + 1); + release_mem_region(awacs_rsrc[2].start, + awacs_rsrc[2].end - awacs_rsrc[2].start + 1); kfree(awacs_tx_cmd_space); kfree(awacs_rx_cmd_space); @@ -2863,46 +2867,58 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n"); * other info if necessary (early AWACS we want to read chip ids) */ - if (io->n_addrs < 3 || io->n_intrs < 3) { + if (of_get_address(io, 2, NULL, NULL) == NULL || io->n_intrs < 3) { /* OK - maybe we need to use the 'awacs' node (on earlier * machines). - */ + */ if (awacs_node) { io = awacs_node ; - if (io->n_addrs < 3 || io->n_intrs < 3) { - printk("dmasound_pmac: can't use %s" - " (%d addrs, %d intrs)\n", - io->full_name, io->n_addrs, io->n_intrs); + if (of_get_address(io, 2, NULL, NULL) == NULL || + io->n_intrs < 3) { + printk("dmasound_pmac: can't use %s\n", + io->full_name); return -ENODEV; } - } else { - printk("dmasound_pmac: can't use %s (%d addrs, %d intrs)\n", - io->full_name, io->n_addrs, io->n_intrs); - } + } else + printk("dmasound_pmac: can't use %s\n", io->full_name); } - if (!request_OF_resource(io, 0, NULL)) { + if (of_address_to_resource(io, 0, &awacs_rsrc[0]) || + request_mem_region(awacs_rsrc[0].start, + awacs_rsrc[0].end - awacs_rsrc[0].start + 1, + " (IO)") == NULL) { printk(KERN_ERR "dmasound: can't request IO resource !\n"); return -ENODEV; } - if (!request_OF_resource(io, 1, " (tx dma)")) { - release_OF_resource(io, 0); - printk(KERN_ERR "dmasound: can't request TX DMA resource !\n"); + if (of_address_to_resource(io, 1, &awacs_rsrc[1]) || + request_mem_region(awacs_rsrc[1].start, + awacs_rsrc[1].end - awacs_rsrc[1].start + 1, + " (tx dma)") == NULL) { + release_mem_region(awacs_rsrc[0].start, + awacs_rsrc[0].end - awacs_rsrc[0].start + 1); + printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n"); return -ENODEV; } - - if (!request_OF_resource(io, 2, " (rx dma)")) { - release_OF_resource(io, 0); - release_OF_resource(io, 1); - printk(KERN_ERR "dmasound: can't request RX DMA resource !\n"); + if (of_address_to_resource(io, 2, &awacs_rsrc[2]) || + request_mem_region(awacs_rsrc[2].start, + awacs_rsrc[2].end - awacs_rsrc[2].start + 1, + " (rx dma)") == NULL) { + release_mem_region(awacs_rsrc[0].start, + awacs_rsrc[0].end - awacs_rsrc[0].start + 1); + release_mem_region(awacs_rsrc[1].start, + awacs_rsrc[1].end - awacs_rsrc[1].start + 1); + printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n"); return -ENODEV; } awacs_beep_dev = input_allocate_device(); if (!awacs_beep_dev) { - release_OF_resource(io, 0); - release_OF_resource(io, 1); - release_OF_resource(io, 2); + release_mem_region(awacs_rsrc[0].start, + awacs_rsrc[0].end - awacs_rsrc[0].start + 1); + release_mem_region(awacs_rsrc[1].start, + awacs_rsrc[1].end - awacs_rsrc[1].start + 1); + release_mem_region(awacs_rsrc[2].start, + awacs_rsrc[2].end - awacs_rsrc[2].start + 1); printk(KERN_ERR "dmasound: can't allocate input device !\n"); return -ENOMEM; } @@ -2916,11 +2932,11 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n"); /* all OF versions I've seen use this value */ if (i2s_node) - i2s = ioremap(io->addrs[0].address, 0x1000); + i2s = ioremap(awacs_rsrc[0].start, 0x1000); else - awacs = ioremap(io->addrs[0].address, 0x1000); - awacs_txdma = ioremap(io->addrs[1].address, 0x100); - awacs_rxdma = ioremap(io->addrs[2].address, 0x100); + awacs = ioremap(awacs_rsrc[0].start, 0x1000); + awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100); + awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100); /* first of all make sure that the chip is powered up....*/ pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1); @@ -3083,9 +3099,10 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); struct device_node* mio; macio_base = NULL; for (mio = io->parent; mio; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0 - && mio->n_addrs > 0) { - macio_base = ioremap(mio->addrs[0].address, 0x40); + if (strcmp(mio->name, "mac-io") == 0) { + struct resource r; + if (of_address_to_resource(mio, 0, &r) == 0) + macio_base = ioremap(r.start, 0x40); break; } } diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 9b2b00fdc1ae..a642e4cfcf45 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -803,21 +803,17 @@ static int snd_pmac_free(struct snd_pmac *chip) iounmap(chip->playback.dma); if (chip->capture.dma) iounmap(chip->capture.dma); -#ifndef CONFIG_PPC64 + if (chip->node) { int i; - for (i = 0; i < 3; i++) { - if (chip->of_requested & (1 << i)) { - if (chip->is_k2) - release_OF_resource(chip->node->parent, - i); - else - release_OF_resource(chip->node, i); - } + if (chip->requested & (1 << i)) + release_mem_region(chip->rsrc[i].start, + chip->rsrc[i].end - + chip->rsrc[i].start + 1); } } -#endif /* CONFIG_PPC64 */ + if (chip->pdev) pci_dev_put(chip->pdev); kfree(chip); @@ -991,6 +987,11 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) chip->can_byte_swap = 0; /* FIXME: check this */ chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ break; + default: + printk(KERN_ERR "snd: Unknown layout ID 0x%x\n", + layout_id); + return -ENODEV; + } } prop = (unsigned int *)get_property(sound, "device-id", NULL); @@ -1175,46 +1176,69 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) } np = chip->node; + chip->requested = 0; if (chip->is_k2) { - if (np->parent->n_addrs < 2 || np->n_intrs < 3) { + static char *rnames[] = { + "Sound Control", "Sound DMA" }; + if (np->n_intrs < 3) { err = -ENODEV; goto __error; } - for (i = 0; i < 2; i++) { -#ifndef CONFIG_PPC64 - static char *name[2] = { "- Control", "- DMA" }; - if (! request_OF_resource(np->parent, i, name[i])) { - snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i); + for (i = 0; i < 2; i ++) { + if (of_address_to_resource(np->parent, i, + &chip->rsrc[i])) { + printk(KERN_ERR "snd: can't translate rsrc " + " %d (%s)\n", i, rnames[i]); + err = -ENODEV; + goto __error; + } + if (request_mem_region(chip->rsrc[i].start, + chip->rsrc[i].end - + chip->rsrc[i].start + 1, + rnames[i]) == NULL) { + printk(KERN_ERR "snd: can't request rsrc " + " %d (%s: 0x%08lx:%08lx)\n", + i, rnames[i], chip->rsrc[i].start, + chip->rsrc[i].end); err = -ENODEV; goto __error; } - chip->of_requested |= (1 << i); -#endif /* CONFIG_PPC64 */ - ctrl_addr = np->parent->addrs[0].address; - txdma_addr = np->parent->addrs[1].address; - rxdma_addr = txdma_addr + 0x100; + chip->requested |= (1 << i); } - + ctrl_addr = chip->rsrc[0].start; + txdma_addr = chip->rsrc[1].start; + rxdma_addr = txdma_addr + 0x100; } else { - if (np->n_addrs < 3 || np->n_intrs < 3) { + static char *rnames[] = { + "Sound Control", "Sound Tx DMA", "Sound Rx DMA" }; + if (np->n_intrs < 3) { err = -ENODEV; goto __error; } - - for (i = 0; i < 3; i++) { -#ifndef CONFIG_PPC64 - static char *name[3] = { "- Control", "- Tx DMA", "- Rx DMA" }; - if (! request_OF_resource(np, i, name[i])) { - snd_printk(KERN_ERR "pmac: can't request resource %d!\n", i); + for (i = 0; i < 3; i ++) { + if (of_address_to_resource(np->parent, i, + &chip->rsrc[i])) { + printk(KERN_ERR "snd: can't translate rsrc " + " %d (%s)\n", i, rnames[i]); + err = -ENODEV; + goto __error; + } + if (request_mem_region(chip->rsrc[i].start, + chip->rsrc[i].end - + chip->rsrc[i].start + 1, + rnames[i]) == NULL) { + printk(KERN_ERR "snd: can't request rsrc " + " %d (%s: 0x%08lx:%08lx)\n", + i, rnames[i], chip->rsrc[i].start, + chip->rsrc[i].end); err = -ENODEV; goto __error; } - chip->of_requested |= (1 << i); -#endif /* CONFIG_PPC64 */ - ctrl_addr = np->addrs[0].address; - txdma_addr = np->addrs[1].address; - rxdma_addr = np->addrs[2].address; + chip->requested |= (1 << i); } + ctrl_addr = chip->rsrc[0].start; + txdma_addr = chip->rsrc[1].start; + rxdma_addr = chip->rsrc[2].start; } chip->awacs = ioremap(ctrl_addr, 0x1000); @@ -1266,9 +1290,11 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) } else if (chip->is_pbook_G3) { struct device_node* mio; for (mio = chip->node->parent; mio; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0 - && mio->n_addrs > 0) { - chip->macio_base = ioremap(mio->addrs[0].address, 0x40); + if (strcmp(mio->name, "mac-io") == 0) { + struct resource r; + if (of_address_to_resource(mio, 0, &r) == 0) + chip->macio_base = + ioremap(r.start, 0x40); break; } } diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h index 086da7a18909..3a9bd4dbb9a6 100644 --- a/sound/ppc/pmac.h +++ b/sound/ppc/pmac.h @@ -113,7 +113,8 @@ struct snd_pmac { unsigned int initialized : 1; unsigned int feature_is_set : 1; - unsigned int of_requested; + unsigned int requested; + struct resource rsrc[3]; int num_freqs; int *freq_table; -- cgit v1.2.3 From c4b22f268914ff824a6334b62afd23f7ad79df11 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 13 Dec 2005 18:04:29 +1100 Subject: [PATCH] powerpc: Update MPIC workarounds Cleanup the MPIC IO-APIC workarounds, make them a bit more generic, smaller and faster. Signed-off-by: Segher Boessenkool Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpic.c | 84 ++++++++++++++++++++-------------------------- include/asm-powerpc/mpic.h | 3 +- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index ae24e2b82c5a..9513ea78e6c1 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -175,57 +175,57 @@ static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no return mpic->fixups[source_no].base != NULL; } + static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) { struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; - u32 tmp; spin_lock(&mpic->fixup_lock); - writeb(0x11 + 2 * fixup->irq, fixup->base); - tmp = readl(fixup->base + 2); - writel(tmp | 0x80000000ul, fixup->base + 2); - /* config writes shouldn't be posted but let's be safe ... */ - (void)readl(fixup->base + 2); + writeb(0x11 + 2 * fixup->irq, fixup->base + 2); + writel(fixup->data, fixup->base + 4); spin_unlock(&mpic->fixup_lock); } -static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase) +static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) { - int i, irq; + int i, irq, n; u32 tmp; + u8 pos; - printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase); + for (pos = readb(devbase + 0x34); pos; pos = readb(devbase + pos + 1)) { + u8 id = readb(devbase + pos); - for (i=0; i < 24; i++) { - writeb(0x10 + 2*i, devbase + 0xf2); - tmp = readl(devbase + 0xf4); - if ((tmp & 0x1) || !(tmp & 0x20)) - continue; - irq = (tmp >> 16) & 0xff; - mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase + 0xf2; + if (id == 0x08) { + id = readb(devbase + pos + 3); + if (id == 0x80) + break; + } } -} - -static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase) -{ - int i, irq; - u32 tmp; + if (pos == 0) + return; + + printk(KERN_INFO "mpic: - Workarounds @ %p, pos = 0x%02x\n", devbase, pos); - printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase); + devbase += pos; - for (i=0; i < 4; i++) { - writeb(0x10 + 2*i, devbase + 0xba); - tmp = readl(devbase + 0xbc); - if ((tmp & 0x1) || !(tmp & 0x20)) + writeb(0x01, devbase + 2); + n = (readl(devbase + 4) >> 16) & 0xff; + + for (i = 0; i <= n; i++) { + writeb(0x10 + 2 * i, devbase + 2); + tmp = readl(devbase + 4); + if ((tmp & 0x21) != 0x20) continue; irq = (tmp >> 16) & 0xff; mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase + 0xba; + mpic->fixups[irq].base = devbase; + writeb(0x11 + 2 * i, devbase + 2); + mpic->fixups[irq].data = readl(devbase + 4) | 0x80000000; } } + static void __init mpic_scan_ioapics(struct mpic *mpic) { unsigned int devfn; @@ -241,21 +241,19 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) /* Init spinlock */ spin_lock_init(&mpic->fixup_lock); - /* Map u3 config space. We assume all IO-APICs are on the primary bus - * and slot will never be above "0xf" so we only need to map 32k + /* Map U3 config space. We assume all IO-APICs are on the primary bus + * so we only need to map 64kB. */ - cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000); + cfgspace = ioremap(0xf2000000, 0x10000); BUG_ON(cfgspace == NULL); /* Now we scan all slots. We do a very quick scan, we read the header type, * vendor ID and device ID only, that's plenty enough */ - for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) { + for (devfn = 0; devfn < 0x100; devfn++) { u8 __iomem *devbase = cfgspace + (devfn << 8); u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); u32 l = readl(devbase + PCI_VENDOR_ID); - u16 vendor_id, device_id; - int multifunc = 0; DBG("devfn %x, l: %x\n", devfn, l); @@ -264,21 +262,11 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) l == 0x0000ffff || l == 0xffff0000) goto next; - /* Check if it's a multifunction device (only really used - * to function 0 though - */ - multifunc = !!(hdr_type & 0x80); - vendor_id = l & 0xffff; - device_id = (l >> 16) & 0xffff; - - /* If a known device, go to fixup setup code */ - if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460) - mpic_amd8111_read_irq(mpic, devbase); - if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450) - mpic_amd8131_read_irq(mpic, devbase); + mpic_scan_ioapic(mpic, devbase); + next: /* next device, if function 0 */ - if ((PCI_FUNC(devfn) == 0) && !multifunc) + if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) devfn += 7; } } diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index 7083d1f74260..6ce27e1b5646 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -117,7 +117,8 @@ typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data); struct mpic_irq_fixup { u8 __iomem *base; - unsigned int irq; + u32 data; + unsigned int irq; }; #endif /* CONFIG_MPIC_BROKEN_U3 */ -- cgit v1.2.3 From 31087d7d49bf5fc9cbc2c4852a079213755e8733 Mon Sep 17 00:00:00 2001 From: linas Date: Tue, 13 Dec 2005 13:46:36 -0600 Subject: [PATCH] powerpc: export PCI fixup routine There is code in the RPAPHP directory that is identical to this routine; I'll be removing that code in an upcoming patch, but this patch is needed to expose the function to make it callable. Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/pci_dlpar.c | 2 +- include/asm-powerpc/pci-bridge.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 283377a536bd..21934784f936 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -77,7 +77,7 @@ pcibios_remove_pci_devices(struct pci_bus *bus) } /* Must be called before pci_bus_add_devices */ -static void +void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) { struct pci_dev *dev; diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 01132bb602e3..3d94e55f25d6 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -136,6 +136,7 @@ void pcibios_remove_pci_devices(struct pci_bus *bus); /** Discover new pci devices under this bus, and add them */ void pcibios_add_pci_devices(struct pci_bus * bus); +void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus); extern int pcibios_remove_root_bus(struct pci_controller *phb); -- cgit v1.2.3 From cd0c7f06803be06a5cf4564aa5a900f4b6aea603 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 13 Dec 2005 14:46:29 -0600 Subject: [PATCH] powerpc: Detect prefetchable windows in pci_process_bridge_OF_ranges Added the ability to determine if an outbound window in the PCI host controller is for prefetchable memory and report it as such. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index af364003880b..8de320308e87 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -941,7 +941,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { res = NULL; size = ranges[na+4]; - switch (ranges[0] >> 24) { + switch ((ranges[0] >> 24) & 0x3) { case 1: /* I/O space */ if (ranges[2] != 0) break; @@ -955,6 +955,8 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, res = &hose->io_resource; res->flags = IORESOURCE_IO; res->start = ranges[2]; + DBG("PCI: IO 0x%lx -> 0x%lx\n", + res->start, res->start + size - 1); break; case 2: /* memory space */ memno = 0; @@ -972,7 +974,11 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, if (memno < 3) { res = &hose->mem_resources[memno]; res->flags = IORESOURCE_MEM; + if(ranges[0] & 0x40000000) + res->flags |= IORESOURCE_PREFETCH; res->start = ranges[na+2]; + DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno, + res->start, res->start + size - 1); } break; } -- cgit v1.2.3 From 1beb6a7d6cbed3ac03500ce9b5b9bb632c512039 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 14 Dec 2005 13:10:10 +1100 Subject: [PATCH] powerpc: Experimental support for new G5 Macs (#2) This adds some very basic support for the new machines, including the Quad G5 (tested), and other new dual core based machines and iMac G5 iSight (untested). This is still experimental ! There is no thermal control yet, there is no proper handing of MSIs, etc.. but it boots, I have all 4 cores up on my machine. Compared to the previous version of this patch, this one adds DART IOMMU support for the U4 chipset and thus should work fine on setups with more than 2Gb of RAM. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/pci_64.c | 35 ++- arch/powerpc/kernel/prom.c | 26 ++- arch/powerpc/kernel/udbg.c | 2 + arch/powerpc/platforms/maple/setup.c | 4 +- arch/powerpc/platforms/powermac/feature.c | 65 ++++-- arch/powerpc/platforms/powermac/pci.c | 210 +++++++++++++++--- arch/powerpc/platforms/powermac/pic.c | 72 +++--- arch/powerpc/platforms/powermac/setup.c | 13 +- arch/powerpc/platforms/powermac/smp.c | 319 ++++++++++++++------------- arch/powerpc/sysdev/Makefile | 2 +- arch/powerpc/sysdev/dart.h | 41 ++-- arch/powerpc/sysdev/dart_iommu.c | 350 ++++++++++++++++++++++++++++++ arch/powerpc/sysdev/mpic.c | 199 +++++++++++++---- arch/powerpc/sysdev/u3_iommu.c | 327 ---------------------------- drivers/ide/ppc/pmac.c | 2 +- drivers/macintosh/smu.c | 8 +- include/asm-powerpc/iommu.h | 6 +- include/asm-powerpc/mpic.h | 3 +- include/asm-powerpc/pmac_feature.h | 2 + include/linux/pci_regs.h | 1 + 21 files changed, 1059 insertions(+), 629 deletions(-) create mode 100644 arch/powerpc/sysdev/dart_iommu.c delete mode 100644 arch/powerpc/sysdev/u3_iommu.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 773b880d5577..5692edb3491e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -300,6 +300,7 @@ config PPC_PMAC64 bool depends on PPC_PMAC && POWER4 select U3_DART + select MPIC_BROKEN_U3 select GENERIC_TBSYNC default y diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 523f35087e81..f73a16e9867a 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -34,7 +34,7 @@ #ifdef DEBUG #include -#define DBG(fmt...) udbg_printf(fmt) +#define DBG(fmt...) printk(fmt) #else #define DBG(fmt...) #endif @@ -323,6 +323,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); if (!addrs) return; + DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs); for (; proplen >= 20; proplen -= 20, addrs += 5) { flags = pci_parse_of_flags(addrs[0]); if (!flags) @@ -332,6 +333,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) if (!size) continue; i = addrs[0] & 0xff; + DBG(" base: %llx, size: %llx, i: %x\n", + (unsigned long long)base, (unsigned long long)size, i); + if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; } else if (i == dev->rom_base_reg) { @@ -362,6 +366,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, if (type == NULL) type = ""; + DBG(" create device, devfn: %x, type: %s\n", devfn, type); + memset(dev, 0, sizeof(struct pci_dev)); dev->bus = bus; dev->sysdata = node; @@ -381,6 +387,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); dev->class = get_int_prop(node, "class-code", 0); + DBG(" class: 0x%x\n", dev->class); + dev->current_state = 4; /* unknown power state */ if (!strcmp(type, "pci")) { @@ -402,6 +410,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, pci_parse_of_addrs(node, dev); + DBG(" adding to system ...\n"); + pci_device_add(dev, bus); /* XXX pci_scan_msi_device(dev); */ @@ -418,15 +428,21 @@ void __devinit of_scan_bus(struct device_node *node, int reglen, devfn; struct pci_dev *dev; + DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); + while ((child = of_get_next_child(node, child)) != NULL) { + DBG(" * %s\n", child->full_name); reg = (u32 *) get_property(child, "reg", ®len); if (reg == NULL || reglen < 20) continue; devfn = (reg[0] >> 8) & 0xff; + /* create a new pci_dev for this device */ dev = of_create_pci_dev(child, bus, devfn); if (!dev) continue; + DBG("dev header type: %x\n", dev->hdr_type); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) of_scan_pci_bridge(child, dev); @@ -446,16 +462,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node, unsigned int flags; u64 size; + DBG("of_scan_pci_bridge(%s)\n", node->full_name); + /* parse bus-range property */ busrange = (u32 *) get_property(node, "bus-range", &len); if (busrange == NULL || len != 8) { - printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", + printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n", node->full_name); return; } ranges = (u32 *) get_property(node, "ranges", &len); if (ranges == NULL) { - printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", + printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", node->full_name); return; } @@ -509,10 +527,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node, } sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); + DBG(" bus name: %s\n", bus->name); mode = PCI_PROBE_NORMAL; if (ppc_md.pci_probe_mode) mode = ppc_md.pci_probe_mode(bus); + DBG(" probe mode: %d\n", mode); + if (mode == PCI_PROBE_DEVTREE) of_scan_bus(node, bus); else if (mode == PCI_PROBE_NORMAL) @@ -528,6 +549,8 @@ void __devinit scan_phb(struct pci_controller *hose) int i, mode; struct resource *res; + DBG("Scanning PHB %s\n", node ? node->full_name : ""); + bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); if (bus == NULL) { printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", @@ -552,8 +575,9 @@ void __devinit scan_phb(struct pci_controller *hose) mode = PCI_PROBE_NORMAL; #ifdef CONFIG_PPC_MULTIPLATFORM - if (ppc_md.pci_probe_mode) + if (node && ppc_md.pci_probe_mode) mode = ppc_md.pci_probe_mode(bus); + DBG(" probe mode: %d\n", mode); if (mode == PCI_PROBE_DEVTREE) { bus->subordinate = hose->last_busno; of_scan_bus(node, bus); @@ -842,8 +866,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, * Returns a negative error code on failure, zero on success. */ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, - int write_combine) + enum pci_mmap_state mmap_state, int write_combine) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct resource *rp; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1b97e13657e5..977ee3adaf2d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -298,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np, int i, j, n, sense; unsigned int *irq, virq; struct device_node *ic; + int trace = 0; + + //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0) +#define TRACE(fmt...) + + if (!strcmp(np->name, "smu-doorbell")) + trace = 1; + + TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n", + num_interrupt_controllers); if (num_interrupt_controllers == 0) { /* @@ -332,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np, } ints = (unsigned int *) get_property(np, "interrupts", &intlen); + TRACE("ints=%p, intlen=%d\n", ints, intlen); if (ints == NULL) return 0; intrcells = prom_n_intr_cells(np); intlen /= intrcells * sizeof(unsigned int); - + TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen); np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); if (!np->intrs) return -ENOMEM; @@ -347,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, intrcount = 0; for (i = 0; i < intlen; ++i, ints += intrcells) { n = map_interrupt(&irq, &ic, np, ints, intrcells); + TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n); if (n <= 0) continue; @@ -357,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, np->intrs[intrcount].sense = map_isa_senses[sense]; } else { virq = virt_irq_create_mapping(irq[0]); + TRACE("virq=%d\n", virq); #ifdef CONFIG_PPC64 if (virq == NO_IRQ) { printk(KERN_CRIT "Could not allocate interrupt" @@ -366,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np, #endif np->intrs[intrcount].line = irq_offset_up(virq); sense = (n > 1)? (irq[1] & 3): 1; + + /* Apple uses bits in there in a different way, let's + * only keep the real sense bit on macs + */ + if (_machine == PLATFORM_POWERMAC) + sense &= 0x1; np->intrs[intrcount].sense = map_mpic_senses[sense]; } @@ -375,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np, char *name = get_property(ic->parent, "name", NULL); if (name && !strcmp(name, "u3")) np->intrs[intrcount].line += 128; - else if (!(name && !strcmp(name, "mac-io"))) + else if (!(name && (!strcmp(name, "mac-io") || + !strcmp(name, "u4")))) /* ignore other cascaded controllers, such as the k2-sata-root */ break; } -#endif +#endif /* CONFIG_PPC64 */ if (n > 2) { printk("hmmm, got %d intr cells for %s:", n, np->full_name); diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index a058285a70e7..9567d9474c80 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -110,10 +110,12 @@ static int early_console_initialized; void __init disable_early_printk(void) { +#if 1 if (!early_console_initialized) return; unregister_console(&udbg_console); early_console_initialized = 0; +#endif } /* called by setup_system */ diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 65fe4c166a68..dd73e38bfb7d 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -195,7 +195,7 @@ static void __init maple_init_early(void) /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; - iommu_init_early_u3(); + iommu_init_early_dart(); DBG(" <- maple_init_early\n"); } @@ -257,7 +257,7 @@ static int __init maple_probe(int platform) * occupies having to be broken up so the DART itself is not * part of the cacheable linar mapping */ - alloc_u3_dart_table(); + alloc_dart_table(); return 1; } diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index b1f896952b1b..d2915d64d45e 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -101,7 +101,8 @@ static const char *macio_names[] = "Keylargo", "Pangea", "Intrepid", - "K2" + "K2", + "Shasta", }; @@ -119,7 +120,7 @@ static const char *macio_names[] = static struct device_node *uninorth_node; static u32 __iomem *uninorth_base; static u32 uninorth_rev; -static int uninorth_u3; +static int uninorth_maj; static void __iomem *u3_ht; /* @@ -1399,8 +1400,15 @@ static long g5_fw_enable(struct device_node *node, long param, long value) static long g5_mpic_enable(struct device_node *node, long param, long value) { unsigned long flags; + struct device_node *parent = of_get_parent(node); + int is_u3; - if (node->parent == NULL || strcmp(node->parent->name, "u3")) + if (parent == NULL) + return 0; + is_u3 = strcmp(parent->name, "u3") == 0 || + strcmp(parent->name, "u4") == 0; + of_node_put(parent); + if (!is_u3) return 0; LOCK(flags); @@ -1464,7 +1472,7 @@ static long g5_i2s_enable(struct device_node *node, long param, long value) }, }; - if (macio->type != macio_keylargo2 /* && macio->type != macio_shasta*/) + if (macio->type != macio_keylargo2 && macio->type != macio_shasta) return -ENODEV; if (strncmp(node->name, "i2s-", 4)) return -ENODEV; @@ -1473,11 +1481,9 @@ static long g5_i2s_enable(struct device_node *node, long param, long value) case 0: case 1: break; -#if 0 case 2: if (macio->type == macio_shasta) break; -#endif default: return -ENODEV; } @@ -1508,7 +1514,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) struct device_node *np; macio = &macio_chips[0]; - if (macio->type != macio_keylargo2) + if (macio->type != macio_keylargo2 && macio->type != macio_shasta) return -ENODEV; np = find_path_device("/cpus"); @@ -1547,7 +1553,8 @@ static long g5_reset_cpu(struct device_node *node, long param, long value) */ void g5_phy_disable_cpu1(void) { - UN_OUT(U3_API_PHY_CONFIG_1, 0); + if (uninorth_maj == 3) + UN_OUT(U3_API_PHY_CONFIG_1, 0); } #endif /* CONFIG_POWER4 */ @@ -2462,6 +2469,14 @@ static struct pmac_mb_def pmac_mb_defs[] = { PMAC_TYPE_POWERMAC_G5_U3L, g5_features, 0, }, + { "PowerMac11,2", "PowerMac G5 Dual Core", + PMAC_TYPE_POWERMAC_G5_U3L, g5_features, + 0, + }, + { "PowerMac12,1", "iMac G5 (iSight)", + PMAC_TYPE_POWERMAC_G5_U3L, g5_features, + 0, + }, { "RackMac3,1", "XServe G5", PMAC_TYPE_XSERVE_G5, g5_features, 0, @@ -2574,6 +2589,11 @@ static int __init probe_motherboard(void) pmac_mb.model_name = "Unknown K2-based"; pmac_mb.features = g5_features; break; + case macio_shasta: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA; + pmac_mb.model_name = "Unknown Shasta-based"; + pmac_mb.features = g5_features; + break; #endif /* CONFIG_POWER4 */ default: return -ENODEV; @@ -2651,7 +2671,12 @@ static void __init probe_uninorth(void) /* Locate G5 u3 */ if (uninorth_node == NULL) { uninorth_node = of_find_node_by_name(NULL, "u3"); - uninorth_u3 = 1; + uninorth_maj = 3; + } + /* Locate G5 u4 */ + if (uninorth_node == NULL) { + uninorth_node = of_find_node_by_name(NULL, "u4"); + uninorth_maj = 4; } if (uninorth_node == NULL) return; @@ -2664,12 +2689,13 @@ static void __init probe_uninorth(void) return; uninorth_base = ioremap(address, 0x40000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); - if (uninorth_u3) + if (uninorth_maj == 3 || uninorth_maj == 4) u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); - printk(KERN_INFO "Found %s memory controller & host bridge," - " revision: %d\n", uninorth_u3 ? "U3" : "UniNorth", - uninorth_rev); + printk(KERN_INFO "Found %s memory controller & host bridge" + " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" : + uninorth_maj == 4 ? "U4" : "UniNorth", + (unsigned int)address, uninorth_rev); printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); /* Set the arbitrer QAck delay according to what Apple does @@ -2677,7 +2703,8 @@ static void __init probe_uninorth(void) if (uninorth_rev < 0x11) { actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : - UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UNI_N_ARB_CTRL_QACK_DELAY) << + UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; UN_OUT(UNI_N_ARB_CTRL, actrl); } @@ -2685,7 +2712,8 @@ static void __init probe_uninorth(void) * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI * memory timeout */ - if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0) + if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || + uninorth_rev == 0xc0) UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff); } @@ -2736,12 +2764,14 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ node->full_name); return; } - if (type == macio_keylargo) { + if (type == macio_keylargo || type == macio_keylargo2) { u32 *did = (u32 *)get_property(node, "device-id", NULL); if (*did == 0x00000025) type = macio_pangea; if (*did == 0x0000003e) type = macio_intrepid; + if (*did == 0x0000004f) + type = macio_shasta; } macio_chips[i].of_node = node; macio_chips[i].type = type; @@ -2840,7 +2870,8 @@ set_initial_features(void) } #ifdef CONFIG_POWER4 - if (macio_chips[0].type == macio_keylargo2) { + if (macio_chips[0].type == macio_keylargo2 || + macio_chips[0].type == macio_shasta) { #ifndef CONFIG_SMP /* On SMP machines running UP, we have the second CPU eating * bus cycles. We need to take it off the bus. This is done diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 5aab261075de..f671ed253901 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1,7 +1,7 @@ /* * Support for PCI bridges found on Power Macintoshes. * - * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) + * Copyright (C) 2003-2005 Benjamin Herrenschmuidt (benh@kernel.crashing.org) * Copyright (C) 1997 Paul Mackerras (paulus@samba.org) * * This program is free software; you can redistribute it and/or @@ -25,7 +25,7 @@ #include #include #ifdef CONFIG_PPC64 -#include +//#include #include #endif @@ -44,6 +44,7 @@ static int add_bridge(struct device_node *dev); static int has_uninorth; #ifdef CONFIG_PPC64 static struct pci_controller *u3_agp; +static struct pci_controller *u4_pcie; static struct pci_controller *u3_ht; #endif /* CONFIG_PPC64 */ @@ -97,11 +98,8 @@ static void __init fixup_bus_range(struct device_node *bridge) /* Lookup the "bus-range" property for the hose */ bus_range = (int *) get_property(bridge, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - bridge->full_name); + if (bus_range == NULL || len < 2 * sizeof(int)) return; - } bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); } @@ -128,14 +126,14 @@ static void __init fixup_bus_range(struct device_node *bridge) */ #define MACRISC_CFA0(devfn, off) \ - ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ - | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ - | (((unsigned long)(off)) & 0xFCUL)) + ((1 << (unsigned int)PCI_SLOT(dev_fn)) \ + | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \ + | (((unsigned int)(off)) & 0xFCUL)) #define MACRISC_CFA1(bus, devfn, off) \ - ((((unsigned long)(bus)) << 16) \ - |(((unsigned long)(devfn)) << 8) \ - |(((unsigned long)(off)) & 0xFCUL) \ + ((((unsigned int)(bus)) << 16) \ + |(((unsigned int)(devfn)) << 8) \ + |(((unsigned int)(off)) & 0xFCUL) \ |1UL) static unsigned long macrisc_cfg_access(struct pci_controller* hose, @@ -168,7 +166,8 @@ static int macrisc_read_config(struct pci_bus *bus, unsigned int devfn, hose = pci_bus_to_host(bus); if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; - + if (offset >= 0x100) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = macrisc_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -199,7 +198,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, hose = pci_bus_to_host(bus); if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; - + if (offset >= 0x100) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = macrisc_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -234,12 +234,13 @@ static struct pci_ops macrisc_pci_ops = /* * Verify that a specific (bus, dev_fn) exists on chaos */ -static int -chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) +static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset) { struct device_node *np; u32 *vendor, *device; + if (offset >= 0x100) + return PCIBIOS_BAD_REGISTER_NUMBER; np = pci_busdev_to_OF_node(bus, devfn); if (np == NULL) return PCIBIOS_DEVICE_NOT_FOUND; @@ -341,10 +342,10 @@ static int u3_ht_skip_device(struct pci_controller *hose, } #define U3_HT_CFA0(devfn, off) \ - ((((unsigned long)devfn) << 8) | offset) + ((((unsigned int)devfn) << 8) | offset) #define U3_HT_CFA1(bus, devfn, off) \ (U3_HT_CFA0(devfn, off) \ - + (((unsigned long)bus) << 16) \ + + (((unsigned int)bus) << 16) \ + 0x01000000UL) static unsigned long u3_ht_cfg_access(struct pci_controller* hose, @@ -370,7 +371,8 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, hose = pci_bus_to_host(bus); if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; - + if (offset >= 0x100) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -419,7 +421,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, hose = pci_bus_to_host(bus); if (hose == NULL) return PCIBIOS_DEVICE_NOT_FOUND; - + if (offset >= 0x100) + return PCIBIOS_BAD_REGISTER_NUMBER; addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; @@ -459,6 +462,112 @@ static struct pci_ops u3_ht_pci_ops = u3_ht_read_config, u3_ht_write_config }; + +#define U4_PCIE_CFA0(devfn, off) \ + ((1 << ((unsigned int)PCI_SLOT(dev_fn))) \ + | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \ + | ((((unsigned int)(off)) >> 8) << 28) \ + | (((unsigned int)(off)) & 0xfcU)) + +#define U4_PCIE_CFA1(bus, devfn, off) \ + ((((unsigned int)(bus)) << 16) \ + |(((unsigned int)(devfn)) << 8) \ + | ((((unsigned int)(off)) >> 8) << 28) \ + |(((unsigned int)(off)) & 0xfcU) \ + |1UL) + +static unsigned long u4_pcie_cfg_access(struct pci_controller* hose, + u8 bus, u8 dev_fn, int offset) +{ + unsigned int caddr; + + if (bus == hose->first_busno) { + caddr = U4_PCIE_CFA0(dev_fn, offset); + } else + caddr = U4_PCIE_CFA1(bus, dev_fn, offset); + + /* Uninorth will return garbage if we don't read back the value ! */ + do { + out_le32(hose->cfg_addr, caddr); + } while (in_le32(hose->cfg_addr) != caddr); + + offset &= 0x03; + return ((unsigned long)hose->cfg_data) + offset; +} + +static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose; + unsigned long addr; + + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset >= 0x1000) + return PCIBIOS_BAD_REGISTER_NUMBER; + addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8((u8 *)addr); + break; + case 2: + *val = in_le16((u16 *)addr); + break; + default: + *val = in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 val) +{ + struct pci_controller *hose; + unsigned long addr; + + hose = pci_bus_to_host(bus); + if (hose == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset >= 0x1000) + return PCIBIOS_BAD_REGISTER_NUMBER; + addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + out_8((u8 *)addr, val); + (void) in_8((u8 *)addr); + break; + case 2: + out_le16((u16 *)addr, val); + (void) in_le16((u16 *)addr); + break; + default: + out_le32((u32 *)addr, val); + (void) in_le32((u32 *)addr); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops u4_pcie_pci_ops = +{ + u4_pcie_read_config, + u4_pcie_write_config +}; + #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC32 @@ -628,15 +737,36 @@ static void __init setup_u3_agp(struct pci_controller* hose) hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - u3_agp = hose; } +static void __init setup_u4_pcie(struct pci_controller* hose) +{ + /* We currently only implement the "non-atomic" config space, to + * be optimised later. + */ + hose->ops = &u4_pcie_pci_ops; + hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); + hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); + + /* The bus contains a bridge from root -> device, we need to + * make it visible on bus 0 so that we pick the right type + * of config cycles. If we didn't, we would have to force all + * config cycles to be type 1. So we override the "bus-range" + * property here + */ + hose->first_busno = 0x00; + hose->last_busno = 0xff; + u4_pcie = hose; +} + static void __init setup_u3_ht(struct pci_controller* hose) { struct device_node *np = (struct device_node *)hose->arch_data; + struct pci_controller *other = NULL; int i, cur; + hose->ops = &u3_ht_pci_ops; /* We hard code the address because of the different size of @@ -670,11 +800,20 @@ static void __init setup_u3_ht(struct pci_controller* hose) u3_ht = hose; - if (u3_agp == NULL) { - DBG("U3 has no AGP, using full resource range\n"); + if (u3_agp != NULL) + other = u3_agp; + else if (u4_pcie != NULL) + other = u4_pcie; + + if (other == NULL) { + DBG("U3/4 has no AGP/PCIE, using full resource range\n"); return; } + /* Fixup bus range vs. PCIE */ + if (u4_pcie) + hose->last_busno = u4_pcie->first_busno - 1; + /* We "remove" the AGP resources from the resources allocated to HT, * that is we create "holes". However, that code does assumptions * that so far happen to be true (cross fingers...), typically that @@ -682,7 +821,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) */ cur = 0; for (i=0; i<3; i++) { - struct resource *res = &u3_agp->mem_resources[i]; + struct resource *res = &other->mem_resources[i]; if (res->flags != IORESOURCE_MEM) continue; /* We don't care about "fine" resources */ @@ -777,9 +916,13 @@ static int __init add_bridge(struct device_node *dev) setup_u3_ht(hose); disp_name = "U3-HT"; primary = 1; + } else if (device_is_compatible(dev, "u4-pcie")) { + setup_u4_pcie(hose); + disp_name = "U4-PCIE"; + primary = 0; } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number:" + " %d->%d\n", disp_name, hose->first_busno, hose->last_busno); #endif /* CONFIG_PPC64 */ /* 32 bits only bridges */ @@ -900,6 +1043,8 @@ void __init pmac_pci_init(void) pci_setup_phb_io(u3_ht, 1); if (u3_agp) pci_setup_phb_io(u3_agp, 0); + if (u4_pcie) + pci_setup_phb_io(u4_pcie, 0); /* * On ppc64, fixup the IO resources on our host bridges as @@ -912,7 +1057,8 @@ void __init pmac_pci_init(void) /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We * assume there is no P2P bridge on the AGP bus, which should be a - * safe assumptions hopefully. + * safe assumptions for now. We should do something better in the + * future though */ if (u3_agp) { struct device_node *np = u3_agp->arch_data; @@ -920,7 +1066,6 @@ void __init pmac_pci_init(void) for (np = np->child; np; np = np->sibling) PCI_DN(np)->busno = 0xf0; } - /* pmac_check_ht_link(); */ /* Tell pci.c to not use the common resource allocation mechanism */ @@ -1127,7 +1272,8 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev) good: pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); if ((progif & 5) != 5) { - printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev)); + printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", + pci_name(dev)); (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) @@ -1153,7 +1299,8 @@ static void fixup_k2_sata(struct pci_dev* dev) for (i = 0; i < 6; i++) { dev->resource[i].start = dev->resource[i].end = 0; dev->resource[i].flags = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, + 0); } } else { pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -1162,7 +1309,8 @@ static void fixup_k2_sata(struct pci_dev* dev) for (i = 0; i < 5; i++) { dev->resource[i].start = dev->resource[i].end = 0; dev->resource[i].flags = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, + 0); } } } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index dbb524a851aa..18bf3011d1e3 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -524,18 +524,56 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) #endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */ } +static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, + int master) +{ + unsigned char senses[128]; + int offset = master ? 0 : 128; + int count = master ? 128 : 124; + const char *name = master ? " MPIC 1 " : " MPIC 2 "; + struct resource r; + struct mpic *mpic; + unsigned int flags = master ? MPIC_PRIMARY : 0; + int rc; + + rc = of_address_to_resource(np, 0, &r); + if (rc) + return NULL; + + pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); + + prom_get_irq_senses(senses, offset, offset + count); + + flags |= MPIC_WANTS_RESET; + if (get_property(np, "big-endian", NULL)) + flags |= MPIC_BIG_ENDIAN; + + /* Primary Big Endian means HT interrupts. This is quite dodgy + * but works until I find a better way + */ + if (master && (flags & MPIC_BIG_ENDIAN)) + flags |= MPIC_BROKEN_U3; + + mpic = mpic_alloc(r.start, flags, 0, offset, count, master ? 252 : 0, + senses, count, name); + if (mpic == NULL) + return NULL; + + mpic_init(mpic); + + return mpic; + } + static int __init pmac_pic_probe_mpic(void) { struct mpic *mpic1, *mpic2; struct device_node *np, *master = NULL, *slave = NULL; - unsigned char senses[128]; - struct resource r; /* We can have up to 2 MPICs cascaded */ for (np = NULL; (np = of_find_node_by_type(np, "open-pic")) != NULL;) { if (master == NULL && - get_property(np, "interrupt-parent", NULL) != NULL) + get_property(np, "interrupts", NULL) == NULL) master = of_node_get(np); else if (slave == NULL) slave = of_node_get(np); @@ -557,13 +595,8 @@ static int __init pmac_pic_probe_mpic(void) ppc_md.get_irq = mpic_get_irq; /* Setup master */ - BUG_ON(of_address_to_resource(master, 0, &r)); - pmac_call_feature(PMAC_FTR_ENABLE_MPIC, master, 0, 0); - prom_get_irq_senses(senses, 0, 128); - mpic1 = mpic_alloc(r.start, MPIC_PRIMARY | MPIC_WANTS_RESET, - 0, 0, 128, 252, senses, 128, " OpenPIC "); + mpic1 = pmac_setup_one_mpic(master, 1); BUG_ON(mpic1 == NULL); - mpic_init(mpic1); /* Install NMI if any */ pmac_pic_setup_mpic_nmi(mpic1); @@ -574,27 +607,12 @@ static int __init pmac_pic_probe_mpic(void) if (slave == NULL || slave->n_intrs < 1) return 0; - /* Setup slave, failures are non-fatal */ - if (of_address_to_resource(slave, 0, &r)) { - printk(KERN_ERR "Can't get address of MPIC %s\n", - slave->full_name); - return 0; - } - pmac_call_feature(PMAC_FTR_ENABLE_MPIC, slave, 0, 0); - prom_get_irq_senses(senses, 128, 128 + 124); - - /* We don't need to set MPIC_BROKEN_U3 here since we don't have - * hypertransport interrupts routed to it, at least not on currently - * supported machines, that may change. - */ - mpic2 = mpic_alloc(r.start, MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, - 0, 128, 124, 0, senses, 124, " U3-MPIC "); + mpic2 = pmac_setup_one_mpic(slave, 0); if (mpic2 == NULL) { - printk(KERN_ERR "Can't create slave MPIC %s\n", - slave->full_name); + printk(KERN_ERR "Failed to setup slave MPIC\n"); + of_node_put(slave); return 0; } - mpic_init(mpic2); mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2); of_node_put(slave); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 18c5620f87fa..1daa5a06e9ea 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -345,7 +345,7 @@ void __init pmac_setup_arch(void) #ifdef CONFIG_SMP /* Check for Core99 */ - if (find_devices("uni-n") || find_devices("u3")) + if (find_devices("uni-n") || find_devices("u3") || find_devices("u4")) smp_ops = &core99_smp_ops; #ifdef CONFIG_PPC32 else @@ -635,7 +635,7 @@ static void __init pmac_init_early(void) /* Setup interrupt mapping options */ ppc64_interrupt_controller = IC_OPEN_PIC; - iommu_init_early_u3(); + iommu_init_early_dart(); #endif } @@ -711,7 +711,7 @@ static int __init pmac_probe(int platform) * occupies having to be broken up so the DART itself is not * part of the cacheable linar mapping */ - alloc_u3_dart_table(); + alloc_dart_table(); #endif #ifdef CONFIG_PMAC_SMU @@ -733,10 +733,11 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) struct device_node *node = bus->sysdata; /* We need to use normal PCI probing for the AGP bus, - since the device for the AGP bridge isn't in the tree. */ - if (bus->self == NULL && device_is_compatible(node, "u3-agp")) + * since the device for the AGP bridge isn't in the tree. + */ + if (bus->self == NULL && (device_is_compatible(node, "u3-agp") || + device_is_compatible(node, "u4-pcie"))) return PCI_PROBE_NORMAL; - return PCI_PROBE_DEVTREE; } #endif diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 862f1e985c19..df01bb8feb16 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -361,7 +361,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr) set_dec(tb_ticks_per_jiffy); /* XXX fixme */ set_tb(0, 0); - last_jiffy_stamp(cpu_nr) = 0; if (cpu_nr > 0) { mb(); @@ -429,15 +428,62 @@ struct smp_ops_t psurge_smp_ops = { }; #endif /* CONFIG_PPC32 - actually powersurge support */ +/* + * Core 99 and later support + */ + +static void (*pmac_tb_freeze)(int freeze); +static unsigned long timebase; +static int tb_req; + +static void smp_core99_give_timebase(void) +{ + unsigned long flags; + + local_irq_save(flags); + + while(!tb_req) + barrier(); + tb_req = 0; + (*pmac_tb_freeze)(1); + mb(); + timebase = get_tb(); + mb(); + while (timebase) + barrier(); + mb(); + (*pmac_tb_freeze)(0); + mb(); + + local_irq_restore(flags); +} + + +static void __devinit smp_core99_take_timebase(void) +{ + unsigned long flags; + + local_irq_save(flags); + + tb_req = 1; + mb(); + while (!timebase) + barrier(); + mb(); + set_tb(timebase >> 32, timebase & 0xffffffff); + timebase = 0; + mb(); + set_dec(tb_ticks_per_jiffy/2); + + local_irq_restore(flags); +} + #ifdef CONFIG_PPC64 /* * G5s enable/disable the timebase via an i2c-connected clock chip. */ static struct device_node *pmac_tb_clock_chip_host; static u8 pmac_tb_pulsar_addr; -static void (*pmac_tb_freeze)(int freeze); -static DEFINE_SPINLOCK(timebase_lock); -static unsigned long timebase; static void smp_core99_cypress_tb_freeze(int freeze) { @@ -447,7 +493,8 @@ static void smp_core99_cypress_tb_freeze(int freeze) /* Strangely, the device-tree says address is 0xd2, but darwin * accesses 0xd0 ... */ - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); + pmac_low_i2c_setmode(pmac_tb_clock_chip_host, + pmac_low_i2c_mode_combined); rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, 0xd0 | pmac_low_i2c_read, 0x81, &data, 1); @@ -475,7 +522,8 @@ static void smp_core99_pulsar_tb_freeze(int freeze) u8 data; int rc; - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); + pmac_low_i2c_setmode(pmac_tb_clock_chip_host, + pmac_low_i2c_mode_combined); rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, pmac_tb_pulsar_addr | pmac_low_i2c_read, 0x2e, &data, 1); @@ -496,54 +544,14 @@ static void smp_core99_pulsar_tb_freeze(int freeze) } } - -static void smp_core99_give_timebase(void) -{ - /* Open i2c bus for synchronous access */ - if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) - panic("Can't open i2c for TB sync !\n"); - - spin_lock(&timebase_lock); - (*pmac_tb_freeze)(1); - mb(); - timebase = get_tb(); - spin_unlock(&timebase_lock); - - while (timebase) - barrier(); - - spin_lock(&timebase_lock); - (*pmac_tb_freeze)(0); - spin_unlock(&timebase_lock); - - /* Close i2c bus */ - pmac_low_i2c_close(pmac_tb_clock_chip_host); -} - - -static void __devinit smp_core99_take_timebase(void) -{ - while (!timebase) - barrier(); - spin_lock(&timebase_lock); - set_tb(timebase >> 32, timebase & 0xffffffff); - timebase = 0; - spin_unlock(&timebase_lock); -} - -static void __init smp_core99_setup(int ncpus) +static void __init smp_core99_setup_i2c_hwsync(int ncpus) { struct device_node *cc = NULL; struct device_node *p; + const char *name = NULL; u32 *reg; int ok; - /* HW sync only on these platforms */ - if (!machine_is_compatible("PowerMac7,2") && - !machine_is_compatible("PowerMac7,3") && - !machine_is_compatible("RackMac3,1")) - return; - /* Look for the clock chip */ while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { p = of_get_parent(cc); @@ -561,114 +569,64 @@ static void __init smp_core99_setup(int ncpus) if (device_is_compatible(cc, "pulsar-legacy-slewing")) { pmac_tb_freeze = smp_core99_pulsar_tb_freeze; pmac_tb_pulsar_addr = 0xd2; - printk(KERN_INFO "Timebase clock is Pulsar chip\n"); + name = "Pulsar"; } else if (device_is_compatible(cc, "cy28508")) { pmac_tb_freeze = smp_core99_cypress_tb_freeze; - printk(KERN_INFO "Timebase clock is Cypress chip\n"); + name = "Cypress"; } break; case 0xd4: pmac_tb_freeze = smp_core99_pulsar_tb_freeze; pmac_tb_pulsar_addr = 0xd4; - printk(KERN_INFO "Timebase clock is Pulsar chip\n"); + name = "Pulsar"; break; } - if (pmac_tb_freeze != NULL) { - pmac_tb_clock_chip_host = of_get_parent(cc); - of_node_put(cc); + if (pmac_tb_freeze != NULL) break; - } } - if (pmac_tb_freeze == NULL) { - smp_ops->give_timebase = smp_generic_give_timebase; - smp_ops->take_timebase = smp_generic_take_timebase; + if (pmac_tb_freeze != NULL) { + struct device_node *p = of_get_parent(cc); + of_node_put(cc); + while(p && strcmp(p->type, "i2c")) { + cc = of_get_parent(p); + of_node_put(p); + p = cc; + } + if (p == NULL) + goto no_i2c_sync; + /* Open i2c bus for synchronous access */ + if (pmac_low_i2c_open(p, 0)) { + printk(KERN_ERR "Failed top open i2c bus %s for clock" + " sync, fallback to software sync !\n", + p->full_name); + of_node_put(p); + goto no_i2c_sync; + } + pmac_tb_clock_chip_host = p; + printk(KERN_INFO "Processor timebase sync using %s i2c clock\n", + name); + return; } + no_i2c_sync: + pmac_tb_freeze = NULL; } -/* nothing to do here, caches are already set up by service processor */ -static inline void __devinit core99_init_caches(int cpu) -{ -} +#endif /* CONFIG_PPC64 */ -#else /* CONFIG_PPC64 */ /* - * SMP G4 powermacs use a GPIO to enable/disable the timebase. + * SMP G4 and newer G5 use a GPIO to enable/disable the timebase. */ static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ -static unsigned int pri_tb_hi, pri_tb_lo; -static unsigned int pri_tb_stamp; - -/* not __init, called in sleep/wakeup code */ -void smp_core99_give_timebase(void) +static void smp_core99_gpio_tb_freeze(int freeze) { - unsigned long flags; - unsigned int t; - - /* wait for the secondary to be in take_timebase */ - for (t = 100000; t > 0 && !sec_tb_reset; --t) - udelay(10); - if (!sec_tb_reset) { - printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); - return; - } - - /* freeze the timebase and read it */ - /* disable interrupts so the timebase is disabled for the - shortest possible time */ - local_irq_save(flags); - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); + if (freeze) + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); + else + pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); - mb(); - pri_tb_hi = get_tbu(); - pri_tb_lo = get_tbl(); - pri_tb_stamp = last_jiffy_stamp(smp_processor_id()); - mb(); - - /* tell the secondary we're ready */ - sec_tb_reset = 2; - mb(); - - /* wait for the secondary to have taken it */ - /* note: can't use udelay here, since it needs the timebase running */ - for (t = 10000000; t > 0 && sec_tb_reset; --t) - barrier(); - if (sec_tb_reset) - /* XXX BUG_ON here? */ - printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); - - /* Now, restart the timebase by leaving the GPIO to an open collector */ - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); - pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); - local_irq_restore(flags); -} - -/* not __init, called in sleep/wakeup code */ -void smp_core99_take_timebase(void) -{ - unsigned long flags; - - /* tell the primary we're here */ - sec_tb_reset = 1; - mb(); - - /* wait for the primary to set pri_tb_hi/lo */ - while (sec_tb_reset < 2) - mb(); - - /* set our stuff the same as the primary */ - local_irq_save(flags); - set_dec(1); - set_tb(pri_tb_hi, pri_tb_lo); - last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; - mb(); - - /* tell the primary we're done */ - sec_tb_reset = 0; - mb(); - local_irq_restore(flags); } /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ @@ -677,6 +635,7 @@ volatile static long int core99_l3_cache; static void __devinit core99_init_caches(int cpu) { +#ifndef CONFIG_PPC64 if (!cpu_has_feature(CPU_FTR_L2CR)) return; @@ -702,30 +661,80 @@ static void __devinit core99_init_caches(int cpu) _set_L3CR(core99_l3_cache); printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); } +#endif /* !CONFIG_PPC64 */ } static void __init smp_core99_setup(int ncpus) { - struct device_node *cpu; - u32 *tbprop = NULL; - int i; +#ifdef CONFIG_PPC64 - core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != NULL) { - tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL); - if (tbprop) - core99_tb_gpio = *tbprop; - of_node_put(cpu); + /* i2c based HW sync on some G5s */ + if (machine_is_compatible("PowerMac7,2") || + machine_is_compatible("PowerMac7,3") || + machine_is_compatible("RackMac3,1")) + smp_core99_setup_i2c_hwsync(ncpus); + + /* GPIO based HW sync on recent G5s */ + if (pmac_tb_freeze == NULL) { + struct device_node *np = + of_find_node_by_name(NULL, "timebase-enable"); + u32 *reg = (u32 *)get_property(np, "reg", NULL); + + if (np && reg && !strcmp(np->type, "gpio")) { + core99_tb_gpio = *reg; + if (core99_tb_gpio < 0x50) + core99_tb_gpio += 0x50; + pmac_tb_freeze = smp_core99_gpio_tb_freeze; + printk(KERN_INFO "Processor timebase sync using" + " GPIO 0x%02x\n", core99_tb_gpio); + } } - /* XXX should get this from reg properties */ - for (i = 1; i < ncpus; ++i) - smp_hw_index[i] = i; - powersave_nap = 0; -} +#else /* CONFIG_PPC64 */ + + /* GPIO based HW sync on ppc32 Core99 */ + if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) { + struct device_node *cpu; + u32 *tbprop = NULL; + + core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ + cpu = of_find_node_by_type(NULL, "cpu"); + if (cpu != NULL) { + tbprop = (u32 *)get_property(cpu, "timebase-enable", + NULL); + if (tbprop) + core99_tb_gpio = *tbprop; + of_node_put(cpu); + } + pmac_tb_freeze = smp_core99_gpio_tb_freeze; + printk(KERN_INFO "Processor timebase sync using" + " GPIO 0x%02x\n", core99_tb_gpio); + } + +#endif /* CONFIG_PPC64 */ + + /* No timebase sync, fallback to software */ + if (pmac_tb_freeze == NULL) { + smp_ops->give_timebase = smp_generic_give_timebase; + smp_ops->take_timebase = smp_generic_take_timebase; + printk(KERN_INFO "Processor timebase sync using software\n"); + } + +#ifndef CONFIG_PPC64 + { + int i; + + /* XXX should get this from reg properties */ + for (i = 1; i < ncpus; ++i) + smp_hw_index[i] = i; + } #endif + /* 32 bits SMP can't NAP */ + if (!machine_is_compatible("MacRISC4")) + powersave_nap = 0; +} + static int __init smp_core99_probe(void) { struct device_node *cpus; @@ -803,17 +812,25 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) mpic_setup_this_cpu(); if (cpu_nr == 0) { -#ifdef CONFIG_POWER4 +#ifdef CONFIG_PPC64 extern void g5_phy_disable_cpu1(void); + /* Close i2c bus if it was used for tb sync */ + if (pmac_tb_clock_chip_host) { + pmac_low_i2c_close(pmac_tb_clock_chip_host); + pmac_tb_clock_chip_host = NULL; + } + /* If we didn't start the second CPU, we must take * it off the bus */ if (machine_is_compatible("MacRISC4") && num_online_cpus() < 2) g5_phy_disable_cpu1(); -#endif /* CONFIG_POWER4 */ - if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); +#endif /* CONFIG_PPC64 */ + + if (ppc_md.progress) + ppc_md.progress("core99_setup_cpu 0 done", 0x349); } } diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index b3e3636a57b0..14b9abde2d27 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -4,6 +4,6 @@ obj-$(CONFIG_PPC_I8259) += i8259.o obj-$(CONFIG_PPC_MPC106) += grackle.o obj-$(CONFIG_BOOKE) += dcr.o obj-$(CONFIG_40x) += dcr.o -obj-$(CONFIG_U3_DART) += u3_iommu.o +obj-$(CONFIG_U3_DART) += dart_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o obj-$(CONFIG_83xx) += ipic.o diff --git a/arch/powerpc/sysdev/dart.h b/arch/powerpc/sysdev/dart.h index 33ed9ed7fc1e..c2d05763ccbe 100644 --- a/arch/powerpc/sysdev/dart.h +++ b/arch/powerpc/sysdev/dart.h @@ -20,29 +20,44 @@ #define _POWERPC_SYSDEV_DART_H -/* physical base of DART registers */ -#define DART_BASE 0xf8033000UL - /* Offset from base to control register */ -#define DARTCNTL 0 +#define DART_CNTL 0 + /* Offset from base to exception register */ -#define DARTEXCP 0x10 +#define DART_EXCP_U3 0x10 /* Offset from base to TLB tag registers */ -#define DARTTAG 0x1000 +#define DART_TAGS_U3 0x1000 +/* U4 registers */ +#define DART_BASE_U4 0x10 +#define DART_SIZE_U4 0x20 +#define DART_EXCP_U4 0x30 +#define DART_TAGS_U4 0x1000 /* Control Register fields */ -/* base address of table (pfn) */ -#define DARTCNTL_BASE_MASK 0xfffff -#define DARTCNTL_BASE_SHIFT 12 +/* U3 registers */ +#define DART_CNTL_U3_BASE_MASK 0xfffff +#define DART_CNTL_U3_BASE_SHIFT 12 +#define DART_CNTL_U3_FLUSHTLB 0x400 +#define DART_CNTL_U3_ENABLE 0x200 +#define DART_CNTL_U3_SIZE_MASK 0x1ff +#define DART_CNTL_U3_SIZE_SHIFT 0 + +/* U4 registers */ +#define DART_BASE_U4_BASE_MASK 0xffffff +#define DART_BASE_U4_BASE_SHIFT 0 +#define DART_CNTL_U4_FLUSHTLB 0x20000000 +#define DART_CNTL_U4_ENABLE 0x80000000 +#define DART_SIZE_U4_SIZE_MASK 0x1fff +#define DART_SIZE_U4_SIZE_SHIFT 0 + +#define DART_REG(r) (dart + ((r) >> 2)) +#define DART_IN(r) (in_be32(DART_REG(r))) +#define DART_OUT(r,v) (out_be32(DART_REG(r), (v))) -#define DARTCNTL_FLUSHTLB 0x400 -#define DARTCNTL_ENABLE 0x200 /* size of table in pages */ -#define DARTCNTL_SIZE_MASK 0x1ff -#define DARTCNTL_SIZE_SHIFT 0 /* DART table fields */ diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c new file mode 100644 index 000000000000..df0dbdee762a --- /dev/null +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -0,0 +1,350 @@ +/* + * arch/powerpc/sysdev/dart_iommu.c + * + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * Copyright (C) 2005 Benjamin Herrenschmidt , + * IBM Corporation + * + * Based on pSeries_iommu.c: + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * + * Dynamic DMA mapping support, Apple U3, U4 & IBM CPC925 "DART" iommu. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dart.h" + +extern int iommu_force_on; + +/* Physical base address and size of the DART table */ +unsigned long dart_tablebase; /* exported to htab_initialize */ +static unsigned long dart_tablesize; + +/* Virtual base address of the DART table */ +static u32 *dart_vbase; + +/* Mapped base address for the dart */ +static unsigned int *__iomem dart; + +/* Dummy val that entries are set to when unused */ +static unsigned int dart_emptyval; + +static struct iommu_table iommu_table_dart; +static int iommu_table_dart_inited; +static int dart_dirty; +static int dart_is_u4; + +#define DBG(...) + +static inline void dart_tlb_invalidate_all(void) +{ + unsigned long l = 0; + unsigned int reg, inv_bit; + unsigned long limit; + + DBG("dart: flush\n"); + + /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the + * control register and wait for it to clear. + * + * Gotcha: Sometimes, the DART won't detect that the bit gets + * set. If so, clear it and set it again. + */ + + limit = 0; + + inv_bit = dart_is_u4 ? DART_CNTL_U4_FLUSHTLB : DART_CNTL_U3_FLUSHTLB; +retry: + l = 0; + reg = DART_IN(DART_CNTL); + reg |= inv_bit; + DART_OUT(DART_CNTL, reg); + + while ((DART_IN(DART_CNTL) & inv_bit) && l < (1L << limit)) + l++; + if (l == (1L << limit)) { + if (limit < 4) { + limit++; + reg = DART_IN(DART_CNTL); + reg &= ~inv_bit; + DART_OUT(DART_CNTL, reg); + goto retry; + } else + panic("DART: TLB did not flush after waiting a long " + "time. Buggy U3 ?"); + } +} + +static void dart_flush(struct iommu_table *tbl) +{ + if (dart_dirty) + dart_tlb_invalidate_all(); + dart_dirty = 0; +} + +static void dart_build(struct iommu_table *tbl, long index, + long npages, unsigned long uaddr, + enum dma_data_direction direction) +{ + unsigned int *dp; + unsigned int rpn; + + DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr); + + index <<= DART_PAGE_FACTOR; + npages <<= DART_PAGE_FACTOR; + + dp = ((unsigned int*)tbl->it_base) + index; + + /* On U3, all memory is contigous, so we can move this + * out of the loop. + */ + while (npages--) { + rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT; + + *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); + + rpn++; + uaddr += DART_PAGE_SIZE; + } + + dart_dirty = 1; +} + + +static void dart_free(struct iommu_table *tbl, long index, long npages) +{ + unsigned int *dp; + + /* We don't worry about flushing the TLB cache. The only drawback of + * not doing it is that we won't catch buggy device drivers doing + * bad DMAs, but then no 32-bit architecture ever does either. + */ + + DBG("dart: free at: %lx, %lx\n", index, npages); + + index <<= DART_PAGE_FACTOR; + npages <<= DART_PAGE_FACTOR; + + dp = ((unsigned int *)tbl->it_base) + index; + + while (npages--) + *(dp++) = dart_emptyval; +} + + +static int dart_init(struct device_node *dart_node) +{ + unsigned int i; + unsigned long tmp, base, size; + struct resource r; + + if (dart_tablebase == 0 || dart_tablesize == 0) { + printk(KERN_INFO "DART: table not allocated, using " + "direct DMA\n"); + return -ENODEV; + } + + if (of_address_to_resource(dart_node, 0, &r)) + panic("DART: can't get register base ! "); + + /* Make sure nothing from the DART range remains in the CPU cache + * from a previous mapping that existed before the kernel took + * over + */ + flush_dcache_phys_range(dart_tablebase, + dart_tablebase + dart_tablesize); + + /* Allocate a spare page to map all invalid DART pages. We need to do + * that to work around what looks like a problem with the HT bridge + * prefetching into invalid pages and corrupting data + */ + tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE); + if (!tmp) + panic("DART: Cannot allocate spare page!"); + dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & + DARTMAP_RPNMASK); + + /* Map in DART registers */ + dart = ioremap(r.start, r.end - r.start + 1); + if (dart == NULL) + panic("DART: Cannot map registers!"); + + /* Map in DART table */ + dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); + + /* Fill initial table */ + for (i = 0; i < dart_tablesize/4; i++) + dart_vbase[i] = dart_emptyval; + + /* Initialize DART with table base and enable it. */ + base = dart_tablebase >> DART_PAGE_SHIFT; + size = dart_tablesize >> DART_PAGE_SHIFT; + if (dart_is_u4) { + BUG_ON(size & ~DART_SIZE_U4_SIZE_MASK); + DART_OUT(DART_BASE_U4, base); + DART_OUT(DART_SIZE_U4, size); + DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE); + } else { + BUG_ON(size & ~DART_CNTL_U3_SIZE_MASK); + DART_OUT(DART_CNTL, + DART_CNTL_U3_ENABLE | + (base << DART_CNTL_U3_BASE_SHIFT) | + (size << DART_CNTL_U3_SIZE_SHIFT)); + } + + /* Invalidate DART to get rid of possible stale TLBs */ + dart_tlb_invalidate_all(); + + printk(KERN_INFO "DART IOMMU initialized for %s type chipset\n", + dart_is_u4 ? "U4" : "U3"); + + return 0; +} + +static void iommu_table_dart_setup(void) +{ + iommu_table_dart.it_busno = 0; + iommu_table_dart.it_offset = 0; + /* it_size is in number of entries */ + iommu_table_dart.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR; + + /* Initialize the common IOMMU code */ + iommu_table_dart.it_base = (unsigned long)dart_vbase; + iommu_table_dart.it_index = 0; + iommu_table_dart.it_blocksize = 1; + iommu_init_table(&iommu_table_dart); + + /* Reserve the last page of the DART to avoid possible prefetch + * past the DART mapped area + */ + set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); +} + +static void iommu_dev_setup_dart(struct pci_dev *dev) +{ + struct device_node *dn; + + /* We only have one iommu table on the mac for now, which makes + * things simple. Setup all PCI devices to point to this table + * + * We must use pci_device_to_OF_node() to make sure that + * we get the real "final" pointer to the device in the + * pci_dev sysdata and not the temporary PHB one + */ + dn = pci_device_to_OF_node(dev); + + if (dn) + PCI_DN(dn)->iommu_table = &iommu_table_dart; +} + +static void iommu_bus_setup_dart(struct pci_bus *bus) +{ + struct device_node *dn; + + if (!iommu_table_dart_inited) { + iommu_table_dart_inited = 1; + iommu_table_dart_setup(); + } + + dn = pci_bus_to_OF_node(bus); + + if (dn) + PCI_DN(dn)->iommu_table = &iommu_table_dart; +} + +static void iommu_dev_setup_null(struct pci_dev *dev) { } +static void iommu_bus_setup_null(struct pci_bus *bus) { } + +void iommu_init_early_dart(void) +{ + struct device_node *dn; + + /* Find the DART in the device-tree */ + dn = of_find_compatible_node(NULL, "dart", "u3-dart"); + if (dn == NULL) { + dn = of_find_compatible_node(NULL, "dart", "u4-dart"); + if (dn == NULL) + goto bail; + dart_is_u4 = 1; + } + + /* Setup low level TCE operations for the core IOMMU code */ + ppc_md.tce_build = dart_build; + ppc_md.tce_free = dart_free; + ppc_md.tce_flush = dart_flush; + + /* Initialize the DART HW */ + if (dart_init(dn) == 0) { + ppc_md.iommu_dev_setup = iommu_dev_setup_dart; + ppc_md.iommu_bus_setup = iommu_bus_setup_dart; + + /* Setup pci_dma ops */ + pci_iommu_init(); + + return; + } + + bail: + /* If init failed, use direct iommu and null setup functions */ + ppc_md.iommu_dev_setup = iommu_dev_setup_null; + ppc_md.iommu_bus_setup = iommu_bus_setup_null; + + /* Setup pci_dma ops */ + pci_direct_iommu_init(); +} + + +void __init alloc_dart_table(void) +{ + /* Only reserve DART space if machine has more than 2GB of RAM + * or if requested with iommu=on on cmdline. + */ + if (lmb_end_of_DRAM() <= 0x80000000ull && !iommu_force_on) + return; + + /* 512 pages (2MB) is max DART tablesize. */ + dart_tablesize = 1UL << 21; + /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we + * will blow up an entire large page anyway in the kernel mapping + */ + dart_tablebase = (unsigned long) + abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); + + printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase); +} diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 9513ea78e6c1..4f26304d0263 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -13,6 +13,9 @@ */ #undef DEBUG +#undef DEBUG_IPI +#undef DEBUG_IRQ +#undef DEBUG_LOW #include #include @@ -168,35 +171,86 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic) /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) * to force the edge setting on the MPIC and do the ack workaround. */ -static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no) +static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) { - if (source_no >= 128 || !mpic->fixups) + if (source >= 128 || !mpic->fixups) return 0; - return mpic->fixups[source_no].base != NULL; + return mpic->fixups[source].base != NULL; } -static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) +static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) { - struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; + struct mpic_irq_fixup *fixup = &mpic->fixups[source]; - spin_lock(&mpic->fixup_lock); - writeb(0x11 + 2 * fixup->irq, fixup->base + 2); - writel(fixup->data, fixup->base + 4); - spin_unlock(&mpic->fixup_lock); + if (fixup->applebase) { + unsigned int soff = (fixup->index >> 3) & ~3; + unsigned int mask = 1U << (fixup->index & 0x1f); + writel(mask, fixup->applebase + soff); + } else { + spin_lock(&mpic->fixup_lock); + writeb(0x11 + 2 * fixup->index, fixup->base + 2); + writel(fixup->data, fixup->base + 4); + spin_unlock(&mpic->fixup_lock); + } } +static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, + unsigned int irqflags) +{ + struct mpic_irq_fixup *fixup = &mpic->fixups[source]; + unsigned long flags; + u32 tmp; + + if (fixup->base == NULL) + return; + + DBG("startup_ht_interrupt(%u, %u) index: %d\n", + source, irqflags, fixup->index); + spin_lock_irqsave(&mpic->fixup_lock, flags); + /* Enable and configure */ + writeb(0x10 + 2 * fixup->index, fixup->base + 2); + tmp = readl(fixup->base + 4); + tmp &= ~(0x23U); + if (irqflags & IRQ_LEVEL) + tmp |= 0x22; + writel(tmp, fixup->base + 4); + spin_unlock_irqrestore(&mpic->fixup_lock, flags); +} + +static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, + unsigned int irqflags) +{ + struct mpic_irq_fixup *fixup = &mpic->fixups[source]; + unsigned long flags; + u32 tmp; + + if (fixup->base == NULL) + return; + + DBG("shutdown_ht_interrupt(%u, %u)\n", source, irqflags); + + /* Disable */ + spin_lock_irqsave(&mpic->fixup_lock, flags); + writeb(0x10 + 2 * fixup->index, fixup->base + 2); + tmp = readl(fixup->base + 4); + tmp &= ~1U; + writel(tmp, fixup->base + 4); + spin_unlock_irqrestore(&mpic->fixup_lock, flags); +} -static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) +static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, + unsigned int devfn, u32 vdid) { int i, irq, n; + u8 __iomem *base; u32 tmp; u8 pos; - for (pos = readb(devbase + 0x34); pos; pos = readb(devbase + pos + 1)) { - u8 id = readb(devbase + pos); - - if (id == 0x08) { + for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; + pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { + u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); + if (id == PCI_CAP_ID_HT_IRQCONF) { id = readb(devbase + pos + 3); if (id == 0x80) break; @@ -205,33 +259,41 @@ static void __init mpic_scan_ioapic(struct mpic *mpic, u8 __iomem *devbase) if (pos == 0) return; - printk(KERN_INFO "mpic: - Workarounds @ %p, pos = 0x%02x\n", devbase, pos); + base = devbase + pos; + writeb(0x01, base + 2); + n = (readl(base + 4) >> 16) & 0xff; - devbase += pos; - - writeb(0x01, devbase + 2); - n = (readl(devbase + 4) >> 16) & 0xff; + printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" + " has %d irqs\n", + devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); for (i = 0; i <= n; i++) { - writeb(0x10 + 2 * i, devbase + 2); - tmp = readl(devbase + 4); - if ((tmp & 0x21) != 0x20) - continue; + writeb(0x10 + 2 * i, base + 2); + tmp = readl(base + 4); irq = (tmp >> 16) & 0xff; - mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase; - writeb(0x11 + 2 * i, devbase + 2); - mpic->fixups[irq].data = readl(devbase + 4) | 0x80000000; + DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); + /* mask it , will be unmasked later */ + tmp |= 0x1; + writel(tmp, base + 4); + mpic->fixups[irq].index = i; + mpic->fixups[irq].base = base; + /* Apple HT PIC has a non-standard way of doing EOIs */ + if ((vdid & 0xffff) == 0x106b) + mpic->fixups[irq].applebase = devbase + 0x60; + else + mpic->fixups[irq].applebase = NULL; + writeb(0x11 + 2 * i, base + 2); + mpic->fixups[irq].data = readl(base + 4) | 0x80000000; } } -static void __init mpic_scan_ioapics(struct mpic *mpic) +static void __init mpic_scan_ht_pics(struct mpic *mpic) { unsigned int devfn; u8 __iomem *cfgspace; - printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n"); + printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); /* Allocate fixups array */ mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); @@ -247,13 +309,14 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) cfgspace = ioremap(0xf2000000, 0x10000); BUG_ON(cfgspace == NULL); - /* Now we scan all slots. We do a very quick scan, we read the header type, - * vendor ID and device ID only, that's plenty enough + /* Now we scan all slots. We do a very quick scan, we read the header + * type, vendor ID and device ID only, that's plenty enough */ for (devfn = 0; devfn < 0x100; devfn++) { u8 __iomem *devbase = cfgspace + (devfn << 8); u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); u32 l = readl(devbase + PCI_VENDOR_ID); + u16 s; DBG("devfn %x, l: %x\n", devfn, l); @@ -261,8 +324,12 @@ static void __init mpic_scan_ioapics(struct mpic *mpic) if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) goto next; + /* Check if is supports capability lists */ + s = readw(devbase + PCI_STATUS); + if (!(s & PCI_STATUS_CAP_LIST)) + goto next; - mpic_scan_ioapic(mpic, devbase); + mpic_scan_ht_pic(mpic, devbase, devfn, l); next: /* next device, if function 0 */ @@ -363,6 +430,31 @@ static void mpic_enable_irq(unsigned int irq) break; } } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); + +#ifdef CONFIG_MPIC_BROKEN_U3 + if (mpic->flags & MPIC_BROKEN_U3) { + unsigned int src = irq - mpic->irq_offset; + if (mpic_is_ht_interrupt(mpic, src) && + (irq_desc[irq].status & IRQ_LEVEL)) + mpic_ht_end_irq(mpic, src); + } +#endif /* CONFIG_MPIC_BROKEN_U3 */ +} + +static unsigned int mpic_startup_irq(unsigned int irq) +{ +#ifdef CONFIG_MPIC_BROKEN_U3 + struct mpic *mpic = mpic_from_irq(irq); + unsigned int src = irq - mpic->irq_offset; + + if (mpic_is_ht_interrupt(mpic, src)) + mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); + +#endif /* CONFIG_MPIC_BROKEN_U3 */ + + mpic_enable_irq(irq); + + return 0; } static void mpic_disable_irq(unsigned int irq) @@ -386,12 +478,27 @@ static void mpic_disable_irq(unsigned int irq) } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); } +static void mpic_shutdown_irq(unsigned int irq) +{ +#ifdef CONFIG_MPIC_BROKEN_U3 + struct mpic *mpic = mpic_from_irq(irq); + unsigned int src = irq - mpic->irq_offset; + + if (mpic_is_ht_interrupt(mpic, src)) + mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); + +#endif /* CONFIG_MPIC_BROKEN_U3 */ + + mpic_disable_irq(irq); +} + static void mpic_end_irq(unsigned int irq) { struct mpic *mpic = mpic_from_irq(irq); +#ifdef DEBUG_IRQ DBG("%s: end_irq: %d\n", mpic->name, irq); - +#endif /* We always EOI on end_irq() even for edge interrupts since that * should only lower the priority, the MPIC should have properly * latched another edge interrupt coming in anyway @@ -400,8 +507,9 @@ static void mpic_end_irq(unsigned int irq) #ifdef CONFIG_MPIC_BROKEN_U3 if (mpic->flags & MPIC_BROKEN_U3) { unsigned int src = irq - mpic->irq_offset; - if (mpic_is_ht_interrupt(mpic, src)) - mpic_apic_end_irq(mpic, src); + if (mpic_is_ht_interrupt(mpic, src) && + (irq_desc[irq].status & IRQ_LEVEL)) + mpic_ht_end_irq(mpic, src); } #endif /* CONFIG_MPIC_BROKEN_U3 */ @@ -482,6 +590,8 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, mpic->name = name; mpic->hc_irq.typename = name; + mpic->hc_irq.startup = mpic_startup_irq; + mpic->hc_irq.shutdown = mpic_shutdown_irq; mpic->hc_irq.enable = mpic_enable_irq; mpic->hc_irq.disable = mpic_disable_irq; mpic->hc_irq.end = mpic_end_irq; @@ -650,10 +760,10 @@ void __init mpic_init(struct mpic *mpic) mpic->irq_count = mpic->num_sources; #ifdef CONFIG_MPIC_BROKEN_U3 - /* Do the ioapic fixups on U3 broken mpic */ + /* Do the HT PIC fixups on U3 broken mpic */ DBG("MPIC flags: %x\n", mpic->flags); if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) - mpic_scan_ioapics(mpic); + mpic_scan_ht_pics(mpic); #endif /* CONFIG_MPIC_BROKEN_U3 */ for (i = 0; i < mpic->num_sources; i++) { @@ -840,7 +950,9 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) BUG_ON(mpic == NULL); +#ifdef DEBUG_IPI DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); +#endif mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); @@ -851,19 +963,28 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) u32 irq; irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; +#ifdef DEBUG_LOW DBG("%s: get_one_irq(): %d\n", mpic->name, irq); - +#endif if (mpic->cascade && irq == mpic->cascade_vec) { +#ifdef DEBUG_LOW DBG("%s: cascading ...\n", mpic->name); +#endif irq = mpic->cascade(regs, mpic->cascade_data); mpic_eoi(mpic); return irq; } if (unlikely(irq == MPIC_VEC_SPURRIOUS)) return -1; - if (irq < MPIC_VEC_IPI_0) + if (irq < MPIC_VEC_IPI_0) { +#ifdef DEBUG_IRQ + DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset); +#endif return irq + mpic->irq_offset; + } +#ifdef DEBUG_IPI DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); +#endif return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; } diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/u3_iommu.c deleted file mode 100644 index 5c1a26a6d00c..000000000000 --- a/arch/powerpc/sysdev/u3_iommu.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * arch/powerpc/sysdev/u3_iommu.c - * - * Copyright (C) 2004 Olof Johansson , IBM Corporation - * - * Based on pSeries_iommu.c: - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * Copyright (C) 2004 Olof Johansson , IBM Corporation - * - * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu. - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dart.h" - -extern int iommu_force_on; - -/* Physical base address and size of the DART table */ -unsigned long dart_tablebase; /* exported to htab_initialize */ -static unsigned long dart_tablesize; - -/* Virtual base address of the DART table */ -static u32 *dart_vbase; - -/* Mapped base address for the dart */ -static unsigned int *dart; - -/* Dummy val that entries are set to when unused */ -static unsigned int dart_emptyval; - -static struct iommu_table iommu_table_u3; -static int iommu_table_u3_inited; -static int dart_dirty; - -#define DBG(...) - -static inline void dart_tlb_invalidate_all(void) -{ - unsigned long l = 0; - unsigned int reg; - unsigned long limit; - - DBG("dart: flush\n"); - - /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the - * control register and wait for it to clear. - * - * Gotcha: Sometimes, the DART won't detect that the bit gets - * set. If so, clear it and set it again. - */ - - limit = 0; - -retry: - reg = in_be32((unsigned int *)dart+DARTCNTL); - reg |= DARTCNTL_FLUSHTLB; - out_be32((unsigned int *)dart+DARTCNTL, reg); - - l = 0; - while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && - l < (1L<it_base) + index; - - /* On U3, all memory is contigous, so we can move this - * out of the loop. - */ - while (npages--) { - rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT; - - *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); - - rpn++; - uaddr += DART_PAGE_SIZE; - } - - dart_dirty = 1; -} - - -static void dart_free(struct iommu_table *tbl, long index, long npages) -{ - unsigned int *dp; - - /* We don't worry about flushing the TLB cache. The only drawback of - * not doing it is that we won't catch buggy device drivers doing - * bad DMAs, but then no 32-bit architecture ever does either. - */ - - DBG("dart: free at: %lx, %lx\n", index, npages); - - index <<= DART_PAGE_FACTOR; - npages <<= DART_PAGE_FACTOR; - - dp = ((unsigned int *)tbl->it_base) + index; - - while (npages--) - *(dp++) = dart_emptyval; -} - - -static int dart_init(struct device_node *dart_node) -{ - unsigned int regword; - unsigned int i; - unsigned long tmp; - - if (dart_tablebase == 0 || dart_tablesize == 0) { - printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); - return -ENODEV; - } - - /* Make sure nothing from the DART range remains in the CPU cache - * from a previous mapping that existed before the kernel took - * over - */ - flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); - - /* Allocate a spare page to map all invalid DART pages. We need to do - * that to work around what looks like a problem with the HT bridge - * prefetching into invalid pages and corrupting data - */ - tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE); - if (!tmp) - panic("U3-DART: Cannot allocate spare page!"); - dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) & DARTMAP_RPNMASK); - - /* Map in DART registers. FIXME: Use device node to get base address */ - dart = ioremap(DART_BASE, 0x7000); - if (dart == NULL) - panic("U3-DART: Cannot map registers!"); - - /* Set initial control register contents: table base, - * table size and enable bit - */ - regword = DARTCNTL_ENABLE | - ((dart_tablebase >> DART_PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | - (((dart_tablesize >> DART_PAGE_SHIFT) & DARTCNTL_SIZE_MASK) - << DARTCNTL_SIZE_SHIFT); - dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); - - /* Fill initial table */ - for (i = 0; i < dart_tablesize/4; i++) - dart_vbase[i] = dart_emptyval; - - /* Initialize DART with table base and enable it. */ - out_be32((unsigned int *)dart, regword); - - /* Invalidate DART to get rid of possible stale TLBs */ - dart_tlb_invalidate_all(); - - printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n"); - - return 0; -} - -static void iommu_table_u3_setup(void) -{ - iommu_table_u3.it_busno = 0; - iommu_table_u3.it_offset = 0; - /* it_size is in number of entries */ - iommu_table_u3.it_size = (dart_tablesize / sizeof(u32)) >> DART_PAGE_FACTOR; - - /* Initialize the common IOMMU code */ - iommu_table_u3.it_base = (unsigned long)dart_vbase; - iommu_table_u3.it_index = 0; - iommu_table_u3.it_blocksize = 1; - iommu_init_table(&iommu_table_u3); - - /* Reserve the last page of the DART to avoid possible prefetch - * past the DART mapped area - */ - set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map); -} - -static void iommu_dev_setup_u3(struct pci_dev *dev) -{ - struct device_node *dn; - - /* We only have one iommu table on the mac for now, which makes - * things simple. Setup all PCI devices to point to this table - * - * We must use pci_device_to_OF_node() to make sure that - * we get the real "final" pointer to the device in the - * pci_dev sysdata and not the temporary PHB one - */ - dn = pci_device_to_OF_node(dev); - - if (dn) - PCI_DN(dn)->iommu_table = &iommu_table_u3; -} - -static void iommu_bus_setup_u3(struct pci_bus *bus) -{ - struct device_node *dn; - - if (!iommu_table_u3_inited) { - iommu_table_u3_inited = 1; - iommu_table_u3_setup(); - } - - dn = pci_bus_to_OF_node(bus); - - if (dn) - PCI_DN(dn)->iommu_table = &iommu_table_u3; -} - -static void iommu_dev_setup_null(struct pci_dev *dev) { } -static void iommu_bus_setup_null(struct pci_bus *bus) { } - -void iommu_init_early_u3(void) -{ - struct device_node *dn; - - /* Find the DART in the device-tree */ - dn = of_find_compatible_node(NULL, "dart", "u3-dart"); - if (dn == NULL) - return; - - /* Setup low level TCE operations for the core IOMMU code */ - ppc_md.tce_build = dart_build; - ppc_md.tce_free = dart_free; - ppc_md.tce_flush = dart_flush; - - /* Initialize the DART HW */ - if (dart_init(dn)) { - /* If init failed, use direct iommu and null setup functions */ - ppc_md.iommu_dev_setup = iommu_dev_setup_null; - ppc_md.iommu_bus_setup = iommu_bus_setup_null; - - /* Setup pci_dma ops */ - pci_direct_iommu_init(); - } else { - ppc_md.iommu_dev_setup = iommu_dev_setup_u3; - ppc_md.iommu_bus_setup = iommu_bus_setup_u3; - - /* Setup pci_dma ops */ - pci_iommu_init(); - } -} - - -void __init alloc_u3_dart_table(void) -{ - /* Only reserve DART space if machine has more than 2GB of RAM - * or if requested with iommu=on on cmdline. - */ - if (lmb_end_of_DRAM() <= 0x80000000ull && !iommu_force_on) - return; - - /* 512 pages (2MB) is max DART tablesize. */ - dart_tablesize = 1UL << 21; - /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we - * will blow up an entire large page anyway in the kernel mapping - */ - dart_tablebase = (unsigned long) - abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); - - printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); -} diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index a8d3bc0a9c5c..5013b1285e22 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1686,7 +1686,7 @@ pmac_ide_probe(void) #else macio_register_driver(&pmac_ide_macio_driver); pci_register_driver(&pmac_ide_pci_driver); -#endif +#endif } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index e8378274d710..96226116a646 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -53,7 +53,7 @@ #undef DEBUG_SMU #ifdef DEBUG_SMU -#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0) +#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) #else #define DPRINTK(fmt, args...) do { } while (0) #endif @@ -909,10 +909,13 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id) struct property *prop; /* First query the partition info */ + DPRINTK("SMU: Query partition infos ... (irq=%d)\n", smu->db_irq); smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2, smu_done_complete, &comp, SMU_CMD_PARTITION_LATEST, id); wait_for_completion(&comp); + DPRINTK("SMU: done, status: %d, reply_len: %d\n", + cmd.cmd.status, cmd.cmd.reply_len); /* Partition doesn't exist (or other error) */ if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6) @@ -975,6 +978,8 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size, sprintf(pname, "sdb-partition-%02x", id); + DPRINTK("smu_get_sdb_partition(%02x)\n", id); + if (interruptible) { int rc; rc = down_interruptible(&smu_part_access); @@ -986,6 +991,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size, part = (struct smu_sdbp_header *)get_property(smu->of_node, pname, size); if (part == NULL) { + DPRINTK("trying to extract from SMU ...\n"); part = smu_create_sdb_partition(id); if (part != NULL && size) *size = part->len << 2; diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index f89f06050893..59f062668997 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -56,7 +56,7 @@ struct device_node; /* Walks all buses and creates iommu tables */ extern void iommu_setup_pSeries(void); -extern void iommu_setup_u3(void); +extern void iommu_setup_dart(void); /* Frees table for an individual device node */ extern void iommu_free_table(struct device_node *dn); @@ -104,7 +104,7 @@ extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, extern void iommu_init_early_pSeries(void); extern void iommu_init_early_iSeries(void); -extern void iommu_init_early_u3(void); +extern void iommu_init_early_dart(void); #ifdef CONFIG_PCI extern void pci_iommu_init(void); @@ -113,6 +113,6 @@ extern void pci_direct_iommu_init(void); static inline void pci_iommu_init(void) { } #endif -extern void alloc_u3_dart_table(void); +extern void alloc_dart_table(void); #endif /* _ASM_IOMMU_H */ diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index 6ce27e1b5646..bf7e71793205 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -117,8 +117,9 @@ typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data); struct mpic_irq_fixup { u8 __iomem *base; + u8 __iomem *applebase; u32 data; - unsigned int irq; + unsigned int index; }; #endif /* CONFIG_MPIC_BROKEN_U3 */ diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h index e9683bcff19b..f6997ed5179e 100644 --- a/include/asm-powerpc/pmac_feature.h +++ b/include/asm-powerpc/pmac_feature.h @@ -121,6 +121,7 @@ #define PMAC_TYPE_IMAC_G5 0x152 /* iMac G5 */ #define PMAC_TYPE_XSERVE_G5 0x153 /* Xserve G5 */ #define PMAC_TYPE_UNKNOWN_K2 0x19f /* Any other K2 based */ +#define PMAC_TYPE_UNKNOWN_SHASTA 0x19e /* Any other Shasta based */ /* * Motherboard flags @@ -341,6 +342,7 @@ enum { macio_pangea, macio_intrepid, macio_keylargo2, + macio_shasta, }; struct macio_chip diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index e2a089b051ed..d27a78b71297 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -196,6 +196,7 @@ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -- cgit v1.2.3 From a6230af7bdffcd3837cb9fbefc17aa6aaada486c Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 8 Jan 2006 20:04:55 -0800 Subject: [CIFS] Minor cleanup to new cifs acl header. Signed-off-by: Steve French --- fs/cifs/cifsacl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 4cfcdf2e6304..d152ff50ea8c 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -34,3 +34,5 @@ struct cifs_sid { const cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; /* group users */ const cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; + +#endif /* _CIFSACL_H */ -- cgit v1.2.3 From 56c8eaee65d688b526c12dca54a30276335679e5 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 19 Dec 2005 16:49:07 +1100 Subject: [PATCH] powerpc: Fix g5 DART init The patch enabling the new G5's with U4 broke initialization of the DART driver, causing it to trigger a BUG_ON for a case that is actually valid. This patch fixes it: Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/dart_iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index df0dbdee762a..e00b46b9514e 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -216,12 +216,12 @@ static int dart_init(struct device_node *dart_node) base = dart_tablebase >> DART_PAGE_SHIFT; size = dart_tablesize >> DART_PAGE_SHIFT; if (dart_is_u4) { - BUG_ON(size & ~DART_SIZE_U4_SIZE_MASK); + size &= DART_SIZE_U4_SIZE_MASK; DART_OUT(DART_BASE_U4, base); DART_OUT(DART_SIZE_U4, size); DART_OUT(DART_CNTL, DART_CNTL_U4_ENABLE); } else { - BUG_ON(size & ~DART_CNTL_U3_SIZE_MASK); + size &= DART_CNTL_U3_SIZE_MASK; DART_OUT(DART_CNTL, DART_CNTL_U3_ENABLE | (base << DART_CNTL_U3_BASE_SHIFT) | -- cgit v1.2.3 From 14c89e7fc84ae55354b8bf12fee1b6d14f259c8a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 14 Dec 2005 16:08:40 +1100 Subject: [PATCH] powerpc: Replace VMALLOCBASE with VMALLOC_START On ppc64, we independently define VMALLOCBASE and VMALLOC_START to be the same thing: the start of the vmalloc() area at 0xd000000000000000. VMALLOC_START is used much more widely, including in generic code, so this patch gets rid of the extraneous VMALLOCBASE. This does require moving the definitions of region IDs from page_64.h to pgtable.h, but they don't clearly belong in the former rather than the latter, anyway. While we're moving them, clean up the definitions of the REGION_IDs: - Abolish REGION_SIZE, it was only used once, to define REGION_MASK anyway - Define the specific region ids in terms of the REGION_ID() macro. - Define KERNEL_REGION_ID in terms of PAGE_OFFSET rather than KERNELBASE. It amounts to the same thing, but conceptually this is about the region of the linear mapping (which starts at PAGE_OFFSET) rather than of the kernel text itself (which is at KERNELBASE). Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/lparmap.c | 4 ++-- arch/powerpc/mm/slb.c | 6 +++--- include/asm-powerpc/page_64.h | 10 ---------- include/asm-powerpc/pgtable.h | 11 +++++++++++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c index 8a53d436ad9a..92d947447565 100644 --- a/arch/powerpc/kernel/lparmap.c +++ b/arch/powerpc/kernel/lparmap.c @@ -18,8 +18,8 @@ const struct LparMap __attribute__((__section__(".text"))) xLparMap = { .xEsids = { { .xKernelEsid = GET_ESID(PAGE_OFFSET), .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), }, - { .xKernelEsid = GET_ESID(VMALLOCBASE), - .xKernelVsid = KERNEL_VSID(VMALLOCBASE), }, + { .xKernelEsid = GET_ESID(VMALLOC_START), + .xKernelVsid = KERNEL_VSID(VMALLOC_START), }, }, .xRanges = { diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index cc22570856af..ffc8ed4de62d 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -87,8 +87,8 @@ static void slb_flush_and_rebolt(void) /* Slot 2 - kernel stack */ "slbmte %2,%3\n" "isync" - :: "r"(mk_vsid_data(VMALLOCBASE, vflags)), - "r"(mk_esid_data(VMALLOCBASE, 1)), + :: "r"(mk_vsid_data(VMALLOC_START, vflags)), + "r"(mk_esid_data(VMALLOC_START, 1)), "r"(mk_vsid_data(ksp_esid_data, lflags)), "r"(ksp_esid_data) : "memory"); @@ -216,7 +216,7 @@ void slb_initialize(void) create_slbe(PAGE_OFFSET, lflags, 0); /* VMALLOC space has 4K pages always for now */ - create_slbe(VMALLOCBASE, vflags, 1); + create_slbe(VMALLOC_START, vflags, 1); /* We don't bolt the stack for the time being - we're in boot, * so the stack is in the bolted segment. By the time it goes diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h index 6642c0125001..8a07a93b0321 100644 --- a/include/asm-powerpc/page_64.h +++ b/include/asm-powerpc/page_64.h @@ -25,16 +25,6 @@ */ #define PAGE_FACTOR (PAGE_SHIFT - HW_PAGE_SHIFT) -#define REGION_SIZE 4UL -#define REGION_SHIFT 60UL -#define REGION_MASK (((1UL<> REGION_SHIFT) -#define KERNEL_REGION_ID (KERNELBASE >> REGION_SHIFT) -#define USER_REGION_ID (0UL) -#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT) - /* Segment size */ #define SID_SHIFT 28 #define SID_MASK 0xfffffffffUL diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h index 0303f57366c1..3518adb2cc18 100644 --- a/include/asm-powerpc/pgtable.h +++ b/include/asm-powerpc/pgtable.h @@ -57,6 +57,17 @@ struct mm_struct; #define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */ #define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE) +/* + * Region IDs + */ +#define REGION_SHIFT 60UL +#define REGION_MASK (0xfUL << REGION_SHIFT) +#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT) + +#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START)) +#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET)) +#define USER_REGION_ID (0UL) + /* * Common bits in a linux-style PTE. These match the bits in the * (hardware-defined) PowerPC PTE as closely as possible. Additional -- cgit v1.2.3 From a04c8780fd234aeeba5e87f7e37beffd05ef21ae Mon Sep 17 00:00:00 2001 From: Kristian Mueller Date: Thu, 15 Dec 2005 12:31:55 +0800 Subject: [PATCH] via-pmu: compile without Power Management support Fix compilation of via-pmu.c without Power Management support. Signed-off-by: Paul Mackerras --- drivers/macintosh/via-pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 79c7b44a94ee..3c0552016b91 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -158,8 +158,8 @@ static int pmu_version; static int drop_interrupts; #if defined(CONFIG_PM) && defined(CONFIG_PPC32) static int option_lid_wakeup = 1; -static int sleep_in_progress; #endif /* CONFIG_PM && CONFIG_PPC32 */ +static int sleep_in_progress; static unsigned long async_req_locks; static unsigned int pmu_irq_stats[11]; -- cgit v1.2.3 From f2c4583a381c584c8c025048071a120cc9562ded Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 15 Dec 2005 15:00:57 +1100 Subject: [PATCH] powerpc: pci_address_to_pio fix This fixes pci_address_to_pio() to return an unsigned long (to be safe) and fixes a bug in the implementation that caused it to return a bogus IO port number Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci_64.c | 11 ++++++----- arch/powerpc/kernel/prom_parse.c | 4 ++-- arch/ppc/kernel/pci.c | 10 ++++++---- include/asm-powerpc/pci-bridge.h | 6 +++--- include/asm-ppc/pci-bridge.h | 6 +++--- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index f73a16e9867a..fc60a773af7d 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -1365,16 +1365,17 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) #endif /* CONFIG_PPC_MULTIPLATFORM */ -unsigned int pci_address_to_pio(phys_addr_t address) +unsigned long pci_address_to_pio(phys_addr_t address) { struct pci_controller *hose, *tmp; list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { if (address >= hose->io_base_phys && - address < (hose->io_base_phys + hose->pci_io_size)) - return (unsigned int) - ((unsigned long)hose->io_base_virt + - (address - hose->io_base_phys)); + address < (hose->io_base_phys + hose->pci_io_size)) { + unsigned long base = + (unsigned long)hose->io_base_virt - pci_io_base; + return base + (address - hose->io_base_phys); + } } return (unsigned int)-1; } diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 5b764277f470..309ae1d5fa77 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c @@ -503,9 +503,9 @@ static int __of_address_to_resource(struct device_node *dev, u32 *addrp, return -EINVAL; memset(r, 0, sizeof(struct resource)); if (flags & IORESOURCE_IO) { - unsigned int port; + unsigned long port; port = pci_address_to_pio(taddr); - if (port == (unsigned int)-1) + if (port == (unsigned long)-1) return -EINVAL; r->start = port; r->end = port + size - 1; diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 8de320308e87..c8b48f171699 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1811,7 +1811,7 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr) EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); -unsigned int pci_address_to_pio(phys_addr_t address) +unsigned long pci_address_to_pio(phys_addr_t address) { struct pci_controller* hose = hose_head; @@ -1819,9 +1819,11 @@ unsigned int pci_address_to_pio(phys_addr_t address) unsigned int size = hose->io_resource.end - hose->io_resource.start + 1; if (address >= hose->io_base_phys && - address < (hose->io_base_phys + size)) - return (unsigned int)hose->io_base_virt + - (address - hose->io_base_phys); + address < (hose->io_base_phys + size)) { + unsigned long base = + (unsigned long)hose->io_base_virt - _IO_BASE; + return base + (address - hose->io_base_phys); + } return (unsigned int)-1; } diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 3d94e55f25d6..443c75a16571 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -158,11 +158,11 @@ pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); #ifdef CONFIG_PCI -extern unsigned int pci_address_to_pio(phys_addr_t address); +extern unsigned long pci_address_to_pio(phys_addr_t address); #else -static inline unsigned int pci_address_to_pio(phys_addr_t address) +static inline unsigned long pci_address_to_pio(phys_addr_t address) { - return (unsigned int)-1; + return (unsigned long)-1; } #endif diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 95672ddfe528..9d5230689b31 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -138,11 +138,11 @@ static inline unsigned char bridge_swizzle(unsigned char pin, extern int pciauto_bus_scan(struct pci_controller *, int); #ifdef CONFIG_PCI -extern unsigned int pci_address_to_pio(phys_addr_t address); +extern unsigned long pci_address_to_pio(phys_addr_t address); #else -static inline unsigned int pci_address_to_pio(phys_addr_t address) +static inline unsigned long pci_address_to_pio(phys_addr_t address) { - return (unsigned int)-1; + return (unsigned long)-1; } #endif -- cgit v1.2.3 From e5cd040409dc0f8d34a21827d6b74918b3a4fccf Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 19 Dec 2005 15:49:07 -0600 Subject: [PATCH] powerpc: Fix compile problem in pci.c for ppc32 pci_address_to_pio is missing a closing curly brace Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/ppc/kernel/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index c8b48f171699..50c75eec8874 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1823,7 +1823,7 @@ unsigned long pci_address_to_pio(phys_addr_t address) unsigned long base = (unsigned long)hose->io_base_virt - _IO_BASE; return base + (address - hose->io_base_phys); - + } } return (unsigned int)-1; } -- cgit v1.2.3 From 555d97ac87aef08bb55dff6f05e68fe2987d6f6d Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Thu, 15 Dec 2005 20:02:04 -0600 Subject: [PATCH] powerpc: G4+ oprofile support This patch adds oprofile support for the 7450 and all its multitudinous derivatives. * Added 7450 (and derivatives) support for oprofile * Changed e500 cputable to have oprofile model and cpu_type fields * Added support for classic 32-bit performance monitor interrupt * Cleaned up common powerpc oprofile code to be as common as possible * Cleaned up oprofile_impl.h to reflect 32 bit classic code * Added 32-bit MMCRx bitfield definitions and SPR numbers Signed-off-by: Andy Fleming Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 74 ++++++++++-- arch/powerpc/kernel/head_32.S | 12 +- arch/powerpc/kernel/pmc.c | 5 + arch/powerpc/kernel/traps.c | 2 - arch/powerpc/oprofile/Makefile | 1 + arch/powerpc/oprofile/common.c | 61 ++-------- arch/powerpc/oprofile/op_model_7450.c | 206 ++++++++++++++++++++++++++++++++++ include/asm-powerpc/oprofile_impl.h | 31 +++-- include/asm-powerpc/reg.h | 36 ++++-- 9 files changed, 344 insertions(+), 84 deletions(-) create mode 100644 arch/powerpc/oprofile/op_model_7450.c diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 1d85cedbbb7b..f7f2a830fca1 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -545,7 +545,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7450 2.1 */ .pvr_mask = 0xffffffff, @@ -556,7 +560,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7450 2.3 and newer */ .pvr_mask = 0xffff0000, @@ -567,7 +575,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7455 rev 1.x */ .pvr_mask = 0xffffff00, @@ -578,7 +590,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7455 rev 2.0 */ .pvr_mask = 0xffffffff, @@ -589,7 +605,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7455 others */ .pvr_mask = 0xffff0000, @@ -600,7 +620,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7447/7457 Rev 1.0 */ .pvr_mask = 0xffffffff, @@ -611,7 +635,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7447/7457 Rev 1.1 */ .pvr_mask = 0xffffffff, @@ -622,7 +650,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7447/7457 Rev 1.2 and later */ .pvr_mask = 0xffff0000, @@ -633,7 +665,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7447A */ .pvr_mask = 0xffff0000, @@ -644,7 +680,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 7448 */ .pvr_mask = 0xffff0000, @@ -655,7 +695,11 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 6, - .cpu_setup = __setup_cpu_745x + .cpu_setup = __setup_cpu_745x, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/7450", + .oprofile_model = &op_model_7450, +#endif }, { /* 82xx (8240, 8245, 8260 are all 603e cores) */ .pvr_mask = 0x7fff0000, @@ -979,6 +1023,10 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/e500", + .oprofile_model = &op_model_fsl_booke, +#endif }, { /* e500v2 */ .pvr_mask = 0xffff0000, @@ -992,6 +1040,10 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, +#ifdef CONFIG_OPROFILE + .oprofile_cpu_type = "ppc/e500", + .oprofile_model = &op_model_fsl_booke, +#endif }, #endif #if !CLASSIC_PPC diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 6359e364fe66..bf37ef2b3aac 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -466,16 +466,11 @@ SystemCall: * by executing an altivec instruction. */ . = 0xf00 - b Trap_0f + b PerformanceMonitor . = 0xf20 b AltiVecUnavailable -Trap_0f: - EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0xf00, unknown_exception) - /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. @@ -719,6 +714,11 @@ AltiVecUnavailable: #endif /* CONFIG_ALTIVEC */ EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) +PerformanceMonitor: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_STD(0xf00, performance_monitor_exception) + #ifdef CONFIG_ALTIVEC /* Note that the AltiVec support is closely modeled after the FP * support. Changes to one are likely to be applicable to the diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index 2d333cc84082..e6fb194fe537 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -43,8 +43,13 @@ static void dummy_perf(struct pt_regs *regs) mtspr(SPRN_MMCR0, mmcr0); } #else +/* Ensure exceptions are disabled */ static void dummy_perf(struct pt_regs *regs) { + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + + mmcr0 &= ~(MMCR0_PMXE); + mtspr(SPRN_MMCR0, mmcr0); } #endif diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 76b579ca5230..6c793463d511 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -901,12 +901,10 @@ void altivec_unavailable_exception(struct pt_regs *regs) die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); } -#if defined(CONFIG_PPC64) || defined(CONFIG_E500) void performance_monitor_exception(struct pt_regs *regs) { perf_irq(regs); } -#endif #ifdef CONFIG_8xx void SoftwareEmulation(struct pt_regs *regs) diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile index 0782d0cca89c..554cd7c75321 100644 --- a/arch/powerpc/oprofile/Makefile +++ b/arch/powerpc/oprofile/Makefile @@ -9,3 +9,4 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ oprofile-y := $(DRIVER_OBJS) common.o oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o +oprofile-$(CONFIG_PPC32) += op_model_7450.o diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index af2c05d20ba5..a370778b68dd 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -14,9 +14,6 @@ */ #include -#ifndef __powerpc64__ -#include -#endif /* ! __powerpc64__ */ #include #include #include @@ -31,10 +28,6 @@ static struct op_powerpc_model *model; static struct op_counter_config ctr[OP_MAX_COUNTER]; static struct op_system_config sys; -#ifndef __powerpc64__ -static char *cpu_type; -#endif /* ! __powerpc64__ */ - static void op_handle_interrupt(struct pt_regs *regs) { model->handle_interrupt(regs, ctr); @@ -53,14 +46,7 @@ static int op_powerpc_setup(void) model->reg_setup(ctr, &sys, model->num_counters); /* Configure the registers on all cpus. */ -#ifdef __powerpc64__ on_each_cpu(model->cpu_setup, NULL, 0, 1); -#else /* __powerpc64__ */ -#if 0 - /* FIXME: Make multi-cpu work */ - on_each_cpu(model->reg_setup, NULL, 0, 1); -#endif -#endif /* __powerpc64__ */ return 0; } @@ -95,7 +81,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) { int i; -#ifdef __powerpc64__ +#ifdef CONFIG_PPC64 /* * There is one mmcr0, mmcr1 and mmcra for setting the events for * all of the counters. @@ -103,7 +89,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); -#endif /* __powerpc64__ */ +#endif for (i = 0; i < model->num_counters; ++i) { struct dentry *dir; @@ -115,65 +101,46 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); -#ifdef __powerpc64__ + /* - * We dont support per counter user/kernel selection, but - * we leave the entries because userspace expects them + * Classic PowerPC doesn't support per-counter + * control like this, but the options are + * expected, so they remain. For Freescale + * Book-E style performance monitors, we do + * support them. */ -#endif /* __powerpc64__ */ oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); -#ifndef __powerpc64__ - /* FIXME: Not sure if this is used */ -#endif /* ! __powerpc64__ */ oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); } oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); -#ifdef __powerpc64__ +#ifdef CONFIG_PPC64 oprofilefs_create_ulong(sb, root, "backtrace_spinlocks", &sys.backtrace_spinlocks); -#endif /* __powerpc64__ */ +#endif /* Default to tracing both kernel and user */ sys.enable_kernel = 1; sys.enable_user = 1; -#ifdef __powerpc64__ +#ifdef CONFIG_PPC64 /* Turn on backtracing through spinlocks by default */ sys.backtrace_spinlocks = 1; -#endif /* __powerpc64__ */ +#endif return 0; } int __init oprofile_arch_init(struct oprofile_operations *ops) { -#ifndef __powerpc64__ -#ifdef CONFIG_FSL_BOOKE - model = &op_model_fsl_booke; -#else - return -ENODEV; -#endif - - cpu_type = kmalloc(32, GFP_KERNEL); - if (NULL == cpu_type) - return -ENOMEM; - - sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name); - - model->num_counters = cur_cpu_spec->num_pmcs; - - ops->cpu_type = cpu_type; -#else /* __powerpc64__ */ if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type) return -ENODEV; model = cur_cpu_spec->oprofile_model; model->num_counters = cur_cpu_spec->num_pmcs; ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; -#endif /* __powerpc64__ */ ops->create_files = op_powerpc_create_files; ops->setup = op_powerpc_setup; ops->shutdown = op_powerpc_shutdown; @@ -188,8 +155,4 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) void oprofile_arch_exit(void) { -#ifndef __powerpc64__ - kfree(cpu_type); - cpu_type = NULL; -#endif /* ! __powerpc64__ */ } diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c new file mode 100644 index 000000000000..32abfdbb0eb1 --- /dev/null +++ b/arch/powerpc/oprofile/op_model_7450.c @@ -0,0 +1,206 @@ +/* + * oprofile/op_model_7450.c + * + * Freescale 745x/744x oprofile support, based on fsl_booke support + * Copyright (C) 2004 Anton Blanchard , IBM + * + * Copyright (c) 2004 Freescale Semiconductor, Inc + * + * Author: Andy Fleming + * Maintainer: Kumar Gala + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long reset_value[OP_MAX_COUNTER]; + +static int oprofile_running; +static u32 mmcr0_val, mmcr1_val, mmcr2_val; + +#define MMCR0_PMC1_SHIFT 6 +#define MMCR0_PMC2_SHIFT 0 +#define MMCR1_PMC3_SHIFT 27 +#define MMCR1_PMC4_SHIFT 22 +#define MMCR1_PMC5_SHIFT 17 +#define MMCR1_PMC6_SHIFT 11 + +#define mmcr0_event1(event) \ + ((event << MMCR0_PMC1_SHIFT) & MMCR0_PMC1SEL) +#define mmcr0_event2(event) \ + ((event << MMCR0_PMC2_SHIFT) & MMCR0_PMC2SEL) + +#define mmcr1_event3(event) \ + ((event << MMCR1_PMC3_SHIFT) & MMCR1_PMC3SEL) +#define mmcr1_event4(event) \ + ((event << MMCR1_PMC4_SHIFT) & MMCR1_PMC4SEL) +#define mmcr1_event5(event) \ + ((event << MMCR1_PMC5_SHIFT) & MMCR1_PMC5SEL) +#define mmcr1_event6(event) \ + ((event << MMCR1_PMC6_SHIFT) & MMCR1_PMC6SEL) + +#define MMCR0_INIT (MMCR0_FC | MMCR0_FCS | MMCR0_FCP | MMCR0_FCM1 | MMCR0_FCM0) + +/* Unfreezes the counters on this CPU, enables the interrupt, + * enables the counters to trigger the interrupt, and sets the + * counters to only count when the mark bit is not set. + */ +static void pmc_start_ctrs(void) +{ + u32 mmcr0 = mfspr(SPRN_MMCR0); + + mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0); + mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE); + + mtspr(SPRN_MMCR0, mmcr0); +} + +/* Disables the counters on this CPU, and freezes them */ +static void pmc_stop_ctrs(void) +{ + u32 mmcr0 = mfspr(SPRN_MMCR0); + + mmcr0 |= MMCR0_FC; + mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE); + + mtspr(SPRN_MMCR0, mmcr0); +} + +/* Configures the counters on this CPU based on the global + * settings */ +static void fsl7450_cpu_setup(void *unused) +{ + /* freeze all counters */ + pmc_stop_ctrs(); + + mtspr(SPRN_MMCR0, mmcr0_val); + mtspr(SPRN_MMCR1, mmcr1_val); + mtspr(SPRN_MMCR2, mmcr2_val); +} + +#define NUM_CTRS 6 + +/* Configures the global settings for the countes on all CPUs. */ +static void fsl7450_reg_setup(struct op_counter_config *ctr, + struct op_system_config *sys, + int num_ctrs) +{ + int i; + + /* Our counters count up, and "count" refers to + * how much before the next interrupt, and we interrupt + * on overflow. So we calculate the starting value + * which will give us "count" until overflow. + * Then we set the events on the enabled counters */ + for (i = 0; i < NUM_CTRS; ++i) + reset_value[i] = 0x80000000UL - ctr[i].count; + + /* Set events for Counters 1 & 2 */ + mmcr0_val = MMCR0_INIT | mmcr0_event1(ctr[0].event) + | mmcr0_event2(ctr[1].event); + + /* Setup user/kernel bits */ + if (sys->enable_kernel) + mmcr0_val &= ~(MMCR0_FCS); + + if (sys->enable_user) + mmcr0_val &= ~(MMCR0_FCP); + + /* Set events for Counters 3-6 */ + mmcr1_val = mmcr1_event3(ctr[2].event) + | mmcr1_event4(ctr[3].event) + | mmcr1_event5(ctr[4].event) + | mmcr1_event6(ctr[5].event); + + mmcr2_val = 0; +} + +/* Sets the counters on this CPU to the chosen values, and starts them */ +static void fsl7450_start(struct op_counter_config *ctr) +{ + int i; + + mtmsr(mfmsr() | MSR_PMM); + + for (i = 0; i < NUM_CTRS; ++i) { + if (ctr[i].enabled) + ctr_write(i, reset_value[i]); + else + ctr_write(i, 0); + } + + /* Clear the freeze bit, and enable the interrupt. + * The counters won't actually start until the rfi clears + * the PMM bit */ + pmc_start_ctrs(); + + oprofile_running = 1; +} + +/* Stop the counters on this CPU */ +static void fsl7450_stop(void) +{ + /* freeze counters */ + pmc_stop_ctrs(); + + oprofile_running = 0; + + mb(); +} + + +/* Handle the interrupt on this CPU, and log a sample for each + * event that triggered the interrupt */ +static void fsl7450_handle_interrupt(struct pt_regs *regs, + struct op_counter_config *ctr) +{ + unsigned long pc; + int is_kernel; + int val; + int i; + + /* set the PMM bit (see comment below) */ + mtmsr(mfmsr() | MSR_PMM); + + pc = mfspr(SPRN_SIAR); + is_kernel = (pc >= KERNELBASE); + + for (i = 0; i < NUM_CTRS; ++i) { + val = ctr_read(i); + if (val < 0) { + if (oprofile_running && ctr[i].enabled) { + oprofile_add_pc(pc, is_kernel, i); + ctr_write(i, reset_value[i]); + } else { + ctr_write(i, 0); + } + } + } + + /* The freeze bit was set by the interrupt. */ + /* Clear the freeze bit, and reenable the interrupt. + * The counters won't actually start until the rfi clears + * the PMM bit */ + pmc_start_ctrs(); +} + +struct op_powerpc_model op_model_7450= { + .reg_setup = fsl7450_reg_setup, + .cpu_setup = fsl7450_cpu_setup, + .start = fsl7450_start, + .stop = fsl7450_stop, + .handle_interrupt = fsl7450_handle_interrupt, +}; diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h index 8013cd273ced..b48d35e40172 100644 --- a/include/asm-powerpc/oprofile_impl.h +++ b/include/asm-powerpc/oprofile_impl.h @@ -22,24 +22,22 @@ struct op_counter_config { unsigned long enabled; unsigned long event; unsigned long count; + /* Classic doesn't support per-counter user/kernel selection */ unsigned long kernel; -#ifdef __powerpc64__ - /* We dont support per counter user/kernel selection */ -#endif unsigned long user; unsigned long unit_mask; }; /* System-wide configuration as set via oprofilefs. */ struct op_system_config { -#ifdef __powerpc64__ +#ifdef CONFIG_PPC64 unsigned long mmcr0; unsigned long mmcr1; unsigned long mmcra; #endif unsigned long enable_kernel; unsigned long enable_user; -#ifdef __powerpc64__ +#ifdef CONFIG_PPC64 unsigned long backtrace_spinlocks; #endif }; @@ -49,9 +47,7 @@ struct op_powerpc_model { void (*reg_setup) (struct op_counter_config *, struct op_system_config *, int num_counters); -#ifdef __powerpc64__ void (*cpu_setup) (void *); -#endif void (*start) (struct op_counter_config *); void (*stop) (void); void (*handle_interrupt) (struct pt_regs *, @@ -59,10 +55,19 @@ struct op_powerpc_model { int num_counters; }; -#ifdef __powerpc64__ +#ifdef CONFIG_FSL_BOOKE +extern struct op_powerpc_model op_model_fsl_booke; +#else /* Otherwise, it's classic */ + +#ifdef CONFIG_PPC64 extern struct op_powerpc_model op_model_rs64; extern struct op_powerpc_model op_model_power4; +#else /* Otherwise, CONFIG_PPC32 */ +extern struct op_powerpc_model op_model_7450; +#endif + +/* All the classic PPC parts use these */ static inline unsigned int ctr_read(unsigned int i) { switch(i) { @@ -78,10 +83,14 @@ static inline unsigned int ctr_read(unsigned int i) return mfspr(SPRN_PMC5); case 5: return mfspr(SPRN_PMC6); + +/* No PPC32 chip has more than 6 so far */ +#ifdef CONFIG_PPC64 case 6: return mfspr(SPRN_PMC7); case 7: return mfspr(SPRN_PMC8); +#endif default: return 0; } @@ -108,16 +117,20 @@ static inline void ctr_write(unsigned int i, unsigned int val) case 5: mtspr(SPRN_PMC6, val); break; + +/* No PPC32 chip has more than 6, yet */ +#ifdef CONFIG_PPC64 case 6: mtspr(SPRN_PMC7, val); break; case 7: mtspr(SPRN_PMC8, val); break; +#endif default: break; } } -#endif /* __powerpc64__ */ +#endif /* !CONFIG_FSL_BOOKE */ #endif /* _ASM_POWERPC_OPROFILE_IMPL_H */ diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index eb392d038ed7..a9a76857f5aa 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -443,12 +443,35 @@ #define SPRN_SDAR 781 #else /* 32-bit */ -#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ -#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ -#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ -#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ -#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ -#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ +#define SPRN_MMCR0 952 /* Monitor Mode Control Register 0 */ +#define MMCR0_FC 0x80000000UL /* freeze counters */ +#define MMCR0_FCS 0x40000000UL /* freeze in supervisor state */ +#define MMCR0_FCP 0x20000000UL /* freeze in problem state */ +#define MMCR0_FCM1 0x10000000UL /* freeze counters while MSR mark = 1 */ +#define MMCR0_FCM0 0x08000000UL /* freeze counters while MSR mark = 0 */ +#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */ +#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */ +#define MMCR0_TBEE 0x00400000UL /* time base exception enable */ +#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/ +#define MMCR0_PMCnCE 0x00004000UL /* count enable for all but PMC 1*/ +#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */ +#define MMCR0_PMC1SEL 0x00001fc0UL /* PMC 1 Event */ +#define MMCR0_PMC2SEL 0x0000003fUL /* PMC 2 Event */ + +#define SPRN_MMCR1 956 +#define MMCR1_PMC3SEL 0xf8000000UL /* PMC 3 Event */ +#define MMCR1_PMC4SEL 0x07c00000UL /* PMC 4 Event */ +#define MMCR1_PMC5SEL 0x003e0000UL /* PMC 5 Event */ +#define MMCR1_PMC6SEL 0x0001f800UL /* PMC 6 Event */ +#define SPRN_MMCR2 944 +#define SPRN_PMC1 953 /* Performance Counter Register 1 */ +#define SPRN_PMC2 954 /* Performance Counter Register 2 */ +#define SPRN_PMC3 957 /* Performance Counter Register 3 */ +#define SPRN_PMC4 958 /* Performance Counter Register 4 */ +#define SPRN_PMC5 945 /* Performance Counter Register 5 */ +#define SPRN_PMC6 946 /* Performance Counter Register 6 */ + +#define SPRN_SIAR 955 /* Sampled Instruction Address Register */ /* Bit definitions for MMCR0 and PMC1 / PMC2. */ #define MMCR0_PMC1_CYCLES (1 << 7) @@ -458,7 +481,6 @@ #define MMCR0_PMC2_CYCLES 0x1 #define MMCR0_PMC2_ITLB 0x7 #define MMCR0_PMC2_LOADMISSTIME 0x5 -#define MMCR0_PMXE (1 << 26) #endif /* Processor Version Register (PVR) field extraction */ -- cgit v1.2.3 From e1333803c3a8fb167ba67ffc5540dbb53fa7deb3 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 16 Dec 2005 14:49:25 +1100 Subject: [PATCH] powerpc: Fix iSeries bug in VMALLOCBASE/VMALLOC_START consolidation Oops, forgot to compile the VMALLOCBASE/VMALLOC_START patch on iSeries. VMALLOC_START is defined in pgtable.h whereas previously VMALLOCBASE was previously defined in page.h. lparmap.c needs to be updated appropriately. Booted on iSeries RS64 (now). Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/lparmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c index 92d947447565..584d1e3c013d 100644 --- a/arch/powerpc/kernel/lparmap.c +++ b/arch/powerpc/kernel/lparmap.c @@ -7,7 +7,7 @@ * 2 of the License, or (at your option) any later version. */ #include -#include +#include #include const struct LparMap __attribute__((__section__(".text"))) xLparMap = { -- cgit v1.2.3 From 84c2008af01132c4ca257ed9b595693c611df15d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:00:28 -0800 Subject: [PATCH] revert "mm: page_state fixes" Hugh says: page_alloc_cpu_notify() specifically contains code to /* Add dead cpu's page_states to our own. */ which handles this more efficiently. Cc: Hugh Dickins Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fd47494cb989..0b98f428b07b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1204,6 +1204,7 @@ static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask) int cpu = 0; memset(ret, 0, sizeof(*ret)); + cpus_and(*cpumask, *cpumask, cpu_online_map); cpu = first_cpu(*cpumask); while (cpu < NR_CPUS) { @@ -1256,7 +1257,7 @@ unsigned long read_page_state_offset(unsigned long offset) unsigned long ret = 0; int cpu; - for_each_cpu(cpu) { + for_each_online_cpu(cpu) { unsigned long in; in = (unsigned long)&per_cpu(page_states, cpu) + offset; -- cgit v1.2.3 From 5998bf1ddb5fb236597190b2274d357add63fd7e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:00:29 -0800 Subject: [PATCH] asm-generic/atomic.h needs types.h For BITS_PER_LONG Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/atomic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index e0a28b925ef0..0fada8f16dc6 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -8,6 +8,7 @@ * edit all arch specific atomic.h files. */ +#include /* * Suppport for atomic_long_t -- cgit v1.2.3 From 70c00ba0bbfb583e39b964ebd88620c18aa02c62 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Sun, 8 Jan 2006 01:00:29 -0800 Subject: [PATCH] small hp_sdc_rtc cleanup: use no_llseek Use no_llseek function. Signed-off-by: Marcelo Tosatti Cc: "Brian S. Julin" Acked-by: Vojtech Pavlik Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/misc/hp_sdc_rtc.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 1cd7657f7e42..1be963961c15 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -60,8 +60,6 @@ static struct fasync_struct *hp_sdc_rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); -static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin); - static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos); @@ -387,11 +385,6 @@ static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) return 0; } -static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { ssize_t retval; @@ -679,7 +672,7 @@ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, static struct file_operations hp_sdc_rtc_fops = { .owner = THIS_MODULE, - .llseek = hp_sdc_rtc_llseek, + .llseek = no_llseek, .read = hp_sdc_rtc_read, .poll = hp_sdc_rtc_poll, .ioctl = hp_sdc_rtc_ioctl, -- cgit v1.2.3 From 4dab06fa7b6d07ee95c8bba5ddd0840633069159 Mon Sep 17 00:00:00 2001 From: Woody Suwalski Date: Sun, 8 Jan 2006 01:00:31 -0800 Subject: [PATCH] ARM Netwinder watchdog wdt977 update Cleanup for the ARM-only watchdog driver wdt977. This is probably the last update, since we want to merge with w83977f_wdt. Jose Goncalves has ported this driver to i386, so probably we can iron out configuration differences. Signed-off-by: Woody Suwalski Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/wdt977.c | 216 +++++++++++++++++++++++++++-------------- 1 file changed, 141 insertions(+), 75 deletions(-) diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c index 44d49dfacbb3..3843900e94c4 100644 --- a/drivers/char/watchdog/wdt977.c +++ b/drivers/char/watchdog/wdt977.c @@ -1,5 +1,5 @@ /* - * Wdt977 0.03: A Watchdog Device for Netwinder W83977AF chip + * Wdt977 0.04: A Watchdog Device for Netwinder W83977AF chip * * (c) Copyright 1998 Rebel.com (Woody Suwalski ) * @@ -18,6 +18,8 @@ * from minutes to seconds. * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in * nwwatchdog_init. + * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks + * remove limitiation to be used on Netwinders only */ #include @@ -28,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -37,8 +40,18 @@ #include #include -#define PFX "Wdt977: " -#define WATCHDOG_MINOR 130 +#define WATCHDOG_VERSION "0.04" +#define WATCHDOG_NAME "Wdt977" +#define PFX WATCHDOG_NAME ": " +#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" + +#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ +#define IO_DATA_PORT (IO_INDEX_PORT+1) + +#define UNLOCK_DATA 0x87 +#define LOCK_DATA 0xAA +#define DEVICE_REGISTER 0x07 + #define DEFAULT_TIMEOUT 60 /* default timeout in seconds */ @@ -47,6 +60,7 @@ static int timeoutM; /* timeout in minutes */ static unsigned long timer_alive; static int testmode; static char expect_close; +static spinlock_t spinlock; module_param(timeout, int, 0); MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); @@ -63,9 +77,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON static int wdt977_start(void) { + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 * F2 has the timeout in minutes @@ -73,28 +91,29 @@ static int wdt977_start(void) * at timeout, and to reset timer on kbd/mouse activity (not impl.) * F4 is used to just clear the TIMEOUT'ed state (bit 0) */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ - outb(0xF4,0x370); - outb(0x00,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(timeoutM, IO_DATA_PORT); + outb_p(0xF3, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */ + outb_p(0xF4, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ /* in test mode watch the bit 1 on F4 to indicate "triggered" */ if (!testmode) { - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x07, IO_DATA_PORT); + outb_p(0xE6, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); } /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); printk(KERN_INFO PFX "activated.\n"); return 0; @@ -106,35 +125,39 @@ static int wdt977_start(void) static int wdt977_stop(void) { + unsigned long flags; + spin_lock_irqsave(&spinlock, flags); + /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 * F3 is reset to its default state * F4 can clear the TIMEOUT'ed state (bit 0) - back to default * We can not use GP17 as a PowerLed, as we use its usage as a RedLed */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(0xFF,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); - outb(0xF4,0x370); - outb(0x00,0x371); - outb(0xF2,0x370); - outb(0x00,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(0xFF, IO_DATA_PORT); + outb_p(0xF3, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); + outb_p(0xF4, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x07, IO_DATA_PORT); + outb_p(0xE6, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); printk(KERN_INFO PFX "shutdown.\n"); return 0; @@ -147,19 +170,23 @@ static int wdt977_stop(void) static int wdt977_keepalive(void) { + unsigned long flags; + spin_lock_irqsave(&spinlock, flags); + /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and kicks watchdog reg F2 */ /* F2 has the timeout in minutes */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(timeoutM, IO_DATA_PORT); /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); return 0; } @@ -198,22 +225,26 @@ static int wdt977_set_timeout(int t) static int wdt977_get_status(int *status) { int new_status; + unsigned long flags; - *status=0; + spin_lock_irqsave(&spinlock, flags); /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and read watchdog reg F4 */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF4,0x370); - new_status = inb(0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF4, IO_INDEX_PORT); + new_status = inb_p(IO_DATA_PORT); /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); + + *status=0; if (new_status & 1) *status |= WDIOF_CARDRESET; @@ -249,8 +280,8 @@ static int wdt977_release(struct inode *inode, struct file *file) wdt977_stop(); clear_bit(0,&timer_alive); } else { - printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); wdt977_keepalive(); + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); } expect_close = 0; return 0; @@ -271,14 +302,17 @@ static int wdt977_release(struct inode *inode, struct file *file) static ssize_t wdt977_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - if (count) { - if (!nowayout) { + if (count) + { + if (!nowayout) + { size_t i; /* In case it was set long ago */ expect_close = 0; - for (i = 0; i != count; i++) { + for (i = 0; i != count; i++) + { char c; if (get_user(c, buf + i)) return -EFAULT; @@ -287,6 +321,7 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, } } + /* someone wrote to us, we should restart timer */ wdt977_keepalive(); } return count; @@ -308,7 +343,7 @@ static struct watchdog_info ident = { WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .firmware_version = 1, - .identity = "Winbond 83977", + .identity = WATCHDOG_NAME, }; static int wdt977_ioctl(struct inode *inode, struct file *file, @@ -405,50 +440,81 @@ static struct notifier_block wdt977_notifier = { .notifier_call = wdt977_notify_sys, }; -static int __init nwwatchdog_init(void) +static int __init wd977_init(void) { - int retval; - if (!machine_is_netwinder()) - return -ENODEV; + int rc; + + //if (!machine_is_netwinder()) + // return -ENODEV; + + printk(KERN_INFO PFX DRIVER_VERSION); + + spin_lock_init(&spinlock); /* Check that the timeout value is within it's range ; if not reset to the default */ - if (wdt977_set_timeout(timeout)) { + if (wdt977_set_timeout(timeout)) + { wdt977_set_timeout(DEFAULT_TIMEOUT); printk(KERN_INFO PFX "timeout value must be 60"); +MODULE_AUTHOR("Woody Suwalski "); MODULE_DESCRIPTION("W83977AF Watchdog driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.2.3 From b792de39d892e06b18ddea85be076bae123d6bf6 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Sun, 8 Jan 2006 01:00:32 -0800 Subject: [PATCH] Fix compilation with CONFIG_MEMORY_HOTPLUG=y and gcc41. Fix compilation with CONFIG_MEMORY_HOTPLUG=y and gcc41. Also remove unneeded declations, add a public function. drivers/base/memory.c:53: error: static declaration of 'register_memory_notifier' follows non-static declaration include/linux/memory.h:85: error: previous declaration of 'register_memory_notifier' was here drivers/base/memory.c:58: error: static declaration of 'unregister_memory_notifier' follows non-static declaration include/linux/memory.h:86: error: previous declaration of 'unregister_memory_notifier' was here drivers/base/memory.c:68: error: static declaration of 'register_memory' follows non-static declaration include/linux/memory.h:73: error: previous declaration of 'register_memory' was here Signed-off-by: Olaf Hering Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memory.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/linux/memory.h b/include/linux/memory.h index dc4081b6f161..e251dc43d0f5 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -70,21 +70,15 @@ static inline void unregister_memory_notifier(struct notifier_block *nb) { } #else -extern int register_memory(struct memory_block *, struct mem_section *section, struct node *); extern int register_new_memory(struct mem_section *); extern int unregister_memory_section(struct mem_section *); extern int memory_dev_init(void); -extern int register_memory_notifier(struct notifier_block *nb); -extern void unregister_memory_notifier(struct notifier_block *nb); +extern int remove_memory_block(unsigned long, struct mem_section *, int); #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION< Date: Sun, 8 Jan 2006 01:00:33 -0800 Subject: [PATCH] slab: remove unused align parameter from alloc_percpu __alloc_percpu and alloc_percpu both take an 'align' argument which is completely ignored. snmp6_mib_init() in net/ipv6/af_inet6.c attempts to use it, but it will be ignored. Therefore, remove the 'align' argument and fixup the lone caller. Signed-off-by: Matthew Dobson Acked-by: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/percpu.h | 7 +++---- mm/slab.c | 3 +-- net/ipv6/af_inet6.c | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/linux/percpu.h b/include/linux/percpu.h index fb8d2d24e4bb..20317d88deba 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -33,14 +33,14 @@ struct percpu_data { (__typeof__(ptr))__p->ptrs[(cpu)]; \ }) -extern void *__alloc_percpu(size_t size, size_t align); +extern void *__alloc_percpu(size_t size); extern void free_percpu(const void *); #else /* CONFIG_SMP */ #define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); }) -static inline void *__alloc_percpu(size_t size, size_t align) +static inline void *__alloc_percpu(size_t size) { void *ret = kmalloc(size, GFP_KERNEL); if (ret) @@ -55,7 +55,6 @@ static inline void free_percpu(const void *ptr) #endif /* CONFIG_SMP */ /* Simple wrapper for the common case: zeros memory. */ -#define alloc_percpu(type) \ - ((type *)(__alloc_percpu(sizeof(type), __alignof__(type)))) +#define alloc_percpu(type) ((type *)(__alloc_percpu(sizeof(type)))) #endif /* __LINUX_PERCPU_H */ diff --git a/mm/slab.c b/mm/slab.c index e5ec26e0c460..eb70fddf2059 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2944,9 +2944,8 @@ EXPORT_SYMBOL(__kmalloc); * Objects should be dereferenced using the per_cpu_ptr macro only. * * @size: how many bytes of memory are required. - * @align: the alignment, which can't be greater than SMP_CACHE_BYTES. */ -void *__alloc_percpu(size_t size, size_t align) +void *__alloc_percpu(size_t size) { int i; struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 68afc53be662..25c3fe5005d9 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -689,11 +689,11 @@ snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) if (ptr == NULL) return -EINVAL; - ptr[0] = __alloc_percpu(mibsize, mibalign); + ptr[0] = __alloc_percpu(mibsize); if (!ptr[0]) goto err0; - ptr[1] = __alloc_percpu(mibsize, mibalign); + ptr[1] = __alloc_percpu(mibsize); if (!ptr[1]) goto err1; -- cgit v1.2.3 From 85289f98ddc13f6cea82c59d6ff78f9d205dfccc Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 8 Jan 2006 01:00:36 -0800 Subject: [PATCH] slab: extract slabinfo header printing to separate function This patch extracts slabinfo header printing to a separate function print_slabinfo_header() to make s_start() more readable. Signed-off-by: Matthew Dobson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index eb70fddf2059..3d3b5a46854f 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3364,32 +3364,37 @@ next: #ifdef CONFIG_PROC_FS -static void *s_start(struct seq_file *m, loff_t *pos) +static void print_slabinfo_header(struct seq_file *m) { - loff_t n = *pos; - struct list_head *p; - - down(&cache_chain_sem); - if (!n) { - /* - * Output format version, so at least we can change it - * without _too_ many complaints. - */ + /* + * Output format version, so at least we can change it + * without _too_ many complaints. + */ #if STATS - seq_puts(m, "slabinfo - version: 2.1 (statistics)\n"); + seq_puts(m, "slabinfo - version: 2.1 (statistics)\n"); #else - seq_puts(m, "slabinfo - version: 2.1\n"); + seq_puts(m, "slabinfo - version: 2.1\n"); #endif - seq_puts(m, "# name "); - seq_puts(m, " : tunables "); - seq_puts(m, " : slabdata "); + seq_puts(m, "# name " + " "); + seq_puts(m, " : tunables "); + seq_puts(m, " : slabdata "); #if STATS - seq_puts(m, " : globalstat " - " "); - seq_puts(m, " : cpustat "); + seq_puts(m, " : globalstat " + " "); + seq_puts(m, " : cpustat "); #endif - seq_putc(m, '\n'); - } + seq_putc(m, '\n'); +} + +static void *s_start(struct seq_file *m, loff_t *pos) +{ + loff_t n = *pos; + struct list_head *p; + + down(&cache_chain_sem); + if (!n) + print_slabinfo_header(m); p = cache_chain.next; while (n--) { p = p->next; -- cgit v1.2.3 From 4d268eba1187ef66844a6a33b9431e5d0dadd4ad Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 8 Jan 2006 01:00:36 -0800 Subject: [PATCH] slab: extract slab order calculation to separate function This patch moves the ugly loop that determines the 'optimal' size (page order) of cache slabs from kmem_cache_create() to a separate function and cleans it up a bit. Thanks to Matthew Wilcox for the help with this patch. Signed-off-by: Matthew Dobson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 89 +++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 3d3b5a46854f..2551b1eeadb3 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1473,6 +1473,53 @@ static inline void set_up_list3s(kmem_cache_t *cachep, int index) } } +/** + * calculate_slab_order - calculate size (page order) of slabs and the number + * of objects per slab. + * + * This could be made much more intelligent. For now, try to avoid using + * high order pages for slabs. When the gfp() functions are more friendly + * towards high-order requests, this should be changed. + */ +static inline size_t calculate_slab_order(kmem_cache_t *cachep, size_t size, + size_t align, gfp_t flags) +{ + size_t left_over = 0; + + for ( ; ; cachep->gfporder++) { + unsigned int num; + size_t remainder; + + if (cachep->gfporder > MAX_GFP_ORDER) { + cachep->num = 0; + break; + } + + cache_estimate(cachep->gfporder, size, align, flags, + &remainder, &num); + if (!num) + continue; + /* More than offslab_limit objects will cause problems */ + if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit) + break; + + cachep->num = num; + left_over = remainder; + + /* + * Large number of objects is good, but very large slabs are + * currently bad for the gfp()s. + */ + if (cachep->gfporder >= slab_break_gfp_order) + break; + + if ((left_over * 8) <= (PAGE_SIZE << cachep->gfporder)) + /* Acceptable internal fragmentation */ + break; + } + return left_over; +} + /** * kmem_cache_create - Create a cache. * @name: A string which is used in /proc/slabinfo to identify this cache. @@ -1682,46 +1729,8 @@ kmem_cache_create (const char *name, size_t size, size_t align, cachep->gfporder = 0; cache_estimate(cachep->gfporder, size, align, flags, &left_over, &cachep->num); - } else { - /* - * Calculate size (in pages) of slabs, and the num of objs per - * slab. This could be made much more intelligent. For now, - * try to avoid using high page-orders for slabs. When the - * gfp() funcs are more friendly towards high-order requests, - * this should be changed. - */ - do { - unsigned int break_flag = 0; -cal_wastage: - cache_estimate(cachep->gfporder, size, align, flags, - &left_over, &cachep->num); - if (break_flag) - break; - if (cachep->gfporder >= MAX_GFP_ORDER) - break; - if (!cachep->num) - goto next; - if (flags & CFLGS_OFF_SLAB && - cachep->num > offslab_limit) { - /* This num of objs will cause problems. */ - cachep->gfporder--; - break_flag++; - goto cal_wastage; - } - - /* - * Large num of objs is good, but v. large slabs are - * currently bad for the gfp()s. - */ - if (cachep->gfporder >= slab_break_gfp_order) - break; - - if ((left_over*8) <= (PAGE_SIZE<gfporder)) - break; /* Acceptable internal fragmentation. */ -next: - cachep->gfporder++; - } while (1); - } + } else + left_over = calculate_slab_order(cachep, size, align, flags); if (!cachep->num) { printk("kmem_cache_create: couldn't create cache %s.\n", name); -- cgit v1.2.3 From b28a02de8c70d41d6b6ba8911e83ed3ccf2e13f8 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 8 Jan 2006 01:00:37 -0800 Subject: [PATCH] slab: fix code formatting The slab allocator code is inconsistent in coding style and messy. For this patch, I ran Lindent for mm/slab.c and fixed up goofs by hand. Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 964 ++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 500 insertions(+), 464 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 2551b1eeadb3..f71d8be2f4e0 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -130,7 +130,6 @@ #define FORCED_DEBUG 0 #endif - /* Shouldn't this be in a header file somewhere? */ #define BYTES_PER_WORD sizeof(void *) @@ -217,12 +216,12 @@ static unsigned long offslab_limit; * Slabs are chained into three list: fully used, partial, fully free slabs. */ struct slab { - struct list_head list; - unsigned long colouroff; - void *s_mem; /* including colour offset */ - unsigned int inuse; /* num of objs active in slab */ - kmem_bufctl_t free; - unsigned short nodeid; + struct list_head list; + unsigned long colouroff; + void *s_mem; /* including colour offset */ + unsigned int inuse; /* num of objs active in slab */ + kmem_bufctl_t free; + unsigned short nodeid; }; /* @@ -242,9 +241,9 @@ struct slab { * We assume struct slab_rcu can overlay struct slab when destroying. */ struct slab_rcu { - struct rcu_head head; - kmem_cache_t *cachep; - void *addr; + struct rcu_head head; + kmem_cache_t *cachep; + void *addr; }; /* @@ -279,23 +278,23 @@ struct array_cache { #define BOOT_CPUCACHE_ENTRIES 1 struct arraycache_init { struct array_cache cache; - void * entries[BOOT_CPUCACHE_ENTRIES]; + void *entries[BOOT_CPUCACHE_ENTRIES]; }; /* * The slab lists for all objects. */ struct kmem_list3 { - struct list_head slabs_partial; /* partial list first, better asm code */ - struct list_head slabs_full; - struct list_head slabs_free; - unsigned long free_objects; - unsigned long next_reap; - int free_touched; - unsigned int free_limit; - spinlock_t list_lock; - struct array_cache *shared; /* shared per node */ - struct array_cache **alien; /* on other nodes */ + struct list_head slabs_partial; /* partial list first, better asm code */ + struct list_head slabs_full; + struct list_head slabs_free; + unsigned long free_objects; + unsigned long next_reap; + int free_touched; + unsigned int free_limit; + spinlock_t list_lock; + struct array_cache *shared; /* shared per node */ + struct array_cache **alien; /* on other nodes */ }; /* @@ -367,63 +366,63 @@ static inline void kmem_list3_init(struct kmem_list3 *parent) * * manages a cache. */ - + struct kmem_cache { /* 1) per-cpu data, touched during every alloc/free */ - struct array_cache *array[NR_CPUS]; - unsigned int batchcount; - unsigned int limit; - unsigned int shared; - unsigned int objsize; + struct array_cache *array[NR_CPUS]; + unsigned int batchcount; + unsigned int limit; + unsigned int shared; + unsigned int objsize; /* 2) touched by every alloc & free from the backend */ - struct kmem_list3 *nodelists[MAX_NUMNODES]; - unsigned int flags; /* constant flags */ - unsigned int num; /* # of objs per slab */ - spinlock_t spinlock; + struct kmem_list3 *nodelists[MAX_NUMNODES]; + unsigned int flags; /* constant flags */ + unsigned int num; /* # of objs per slab */ + spinlock_t spinlock; /* 3) cache_grow/shrink */ /* order of pgs per slab (2^n) */ - unsigned int gfporder; + unsigned int gfporder; /* force GFP flags, e.g. GFP_DMA */ - gfp_t gfpflags; + gfp_t gfpflags; - size_t colour; /* cache colouring range */ - unsigned int colour_off; /* colour offset */ - unsigned int colour_next; /* cache colouring */ - kmem_cache_t *slabp_cache; - unsigned int slab_size; - unsigned int dflags; /* dynamic flags */ + size_t colour; /* cache colouring range */ + unsigned int colour_off; /* colour offset */ + unsigned int colour_next; /* cache colouring */ + kmem_cache_t *slabp_cache; + unsigned int slab_size; + unsigned int dflags; /* dynamic flags */ /* constructor func */ - void (*ctor)(void *, kmem_cache_t *, unsigned long); + void (*ctor) (void *, kmem_cache_t *, unsigned long); /* de-constructor func */ - void (*dtor)(void *, kmem_cache_t *, unsigned long); + void (*dtor) (void *, kmem_cache_t *, unsigned long); /* 4) cache creation/removal */ - const char *name; - struct list_head next; + const char *name; + struct list_head next; /* 5) statistics */ #if STATS - unsigned long num_active; - unsigned long num_allocations; - unsigned long high_mark; - unsigned long grown; - unsigned long reaped; - unsigned long errors; - unsigned long max_freeable; - unsigned long node_allocs; - unsigned long node_frees; - atomic_t allochit; - atomic_t allocmiss; - atomic_t freehit; - atomic_t freemiss; + unsigned long num_active; + unsigned long num_allocations; + unsigned long high_mark; + unsigned long grown; + unsigned long reaped; + unsigned long errors; + unsigned long max_freeable; + unsigned long node_allocs; + unsigned long node_frees; + atomic_t allochit; + atomic_t allocmiss; + atomic_t freehit; + atomic_t freemiss; #endif #if DEBUG - int dbghead; - int reallen; + int dbghead; + int reallen; #endif }; @@ -523,14 +522,15 @@ static unsigned long *dbg_redzone2(kmem_cache_t *cachep, void *objp) { BUG_ON(!(cachep->flags & SLAB_RED_ZONE)); if (cachep->flags & SLAB_STORE_USER) - return (unsigned long*) (objp+cachep->objsize-2*BYTES_PER_WORD); - return (unsigned long*) (objp+cachep->objsize-BYTES_PER_WORD); + return (unsigned long *)(objp + cachep->objsize - + 2 * BYTES_PER_WORD); + return (unsigned long *)(objp + cachep->objsize - BYTES_PER_WORD); } static void **dbg_userword(kmem_cache_t *cachep, void *objp) { BUG_ON(!(cachep->flags & SLAB_STORE_USER)); - return (void**)(objp+cachep->objsize-BYTES_PER_WORD); + return (void **)(objp + cachep->objsize - BYTES_PER_WORD); } #else @@ -607,31 +607,31 @@ struct cache_names { static struct cache_names __initdata cache_names[] = { #define CACHE(x) { .name = "size-" #x, .name_dma = "size-" #x "(DMA)" }, #include - { NULL, } + {NULL,} #undef CACHE }; static struct arraycache_init initarray_cache __initdata = - { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; + { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; static struct arraycache_init initarray_generic = - { { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; + { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; /* internal cache of cache description objs */ static kmem_cache_t cache_cache = { - .batchcount = 1, - .limit = BOOT_CPUCACHE_ENTRIES, - .shared = 1, - .objsize = sizeof(kmem_cache_t), - .flags = SLAB_NO_REAP, - .spinlock = SPIN_LOCK_UNLOCKED, - .name = "kmem_cache", + .batchcount = 1, + .limit = BOOT_CPUCACHE_ENTRIES, + .shared = 1, + .objsize = sizeof(kmem_cache_t), + .flags = SLAB_NO_REAP, + .spinlock = SPIN_LOCK_UNLOCKED, + .name = "kmem_cache", #if DEBUG - .reallen = sizeof(kmem_cache_t), + .reallen = sizeof(kmem_cache_t), #endif }; /* Guard access to the cache-chain. */ -static struct semaphore cache_chain_sem; +static struct semaphore cache_chain_sem; static struct list_head cache_chain; /* @@ -655,9 +655,9 @@ static enum { static DEFINE_PER_CPU(struct work_struct, reap_work); -static void free_block(kmem_cache_t* cachep, void** objpp, int len, int node); -static void enable_cpucache (kmem_cache_t *cachep); -static void cache_reap (void *unused); +static void free_block(kmem_cache_t *cachep, void **objpp, int len, int node); +static void enable_cpucache(kmem_cache_t *cachep); +static void cache_reap(void *unused); static int __node_shrink(kmem_cache_t *cachep, int node); static inline struct array_cache *ac_data(kmem_cache_t *cachep) @@ -671,9 +671,9 @@ static inline kmem_cache_t *__find_general_cachep(size_t size, gfp_t gfpflags) #if DEBUG /* This happens if someone tries to call - * kmem_cache_create(), or __kmalloc(), before - * the generic caches are initialized. - */ + * kmem_cache_create(), or __kmalloc(), before + * the generic caches are initialized. + */ BUG_ON(malloc_sizes[INDEX_AC].cs_cachep == NULL); #endif while (size > csizep->cs_size) @@ -697,10 +697,10 @@ EXPORT_SYMBOL(kmem_find_general_cachep); /* Cal the num objs, wastage, and bytes left over for a given slab size. */ static void cache_estimate(unsigned long gfporder, size_t size, size_t align, - int flags, size_t *left_over, unsigned int *num) + int flags, size_t *left_over, unsigned int *num) { int i; - size_t wastage = PAGE_SIZE< 0) i--; @@ -718,8 +718,8 @@ static void cache_estimate(unsigned long gfporder, size_t size, size_t align, i = SLAB_LIMIT; *num = i; - wastage -= i*size; - wastage -= ALIGN(base+i*extra, align); + wastage -= i * size; + wastage -= ALIGN(base + i * extra, align); *left_over = wastage; } @@ -728,7 +728,7 @@ static void cache_estimate(unsigned long gfporder, size_t size, size_t align, static void __slab_error(const char *function, kmem_cache_t *cachep, char *msg) { printk(KERN_ERR "slab error in %s(): cache `%s': %s\n", - function, cachep->name, msg); + function, cachep->name, msg); dump_stack(); } @@ -755,9 +755,9 @@ static void __devinit start_cpu_timer(int cpu) } static struct array_cache *alloc_arraycache(int node, int entries, - int batchcount) + int batchcount) { - int memsize = sizeof(void*)*entries+sizeof(struct array_cache); + int memsize = sizeof(void *) * entries + sizeof(struct array_cache); struct array_cache *nc = NULL; nc = kmalloc_node(memsize, GFP_KERNEL, node); @@ -775,7 +775,7 @@ static struct array_cache *alloc_arraycache(int node, int entries, static inline struct array_cache **alloc_alien_cache(int node, int limit) { struct array_cache **ac_ptr; - int memsize = sizeof(void*)*MAX_NUMNODES; + int memsize = sizeof(void *) * MAX_NUMNODES; int i; if (limit > 1) @@ -789,7 +789,7 @@ static inline struct array_cache **alloc_alien_cache(int node, int limit) } ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d); if (!ac_ptr[i]) { - for (i--; i <=0; i--) + for (i--; i <= 0; i--) kfree(ac_ptr[i]); kfree(ac_ptr); return NULL; @@ -807,12 +807,13 @@ static inline void free_alien_cache(struct array_cache **ac_ptr) return; for_each_node(i) - kfree(ac_ptr[i]); + kfree(ac_ptr[i]); kfree(ac_ptr); } -static inline void __drain_alien_cache(kmem_cache_t *cachep, struct array_cache *ac, int node) +static inline void __drain_alien_cache(kmem_cache_t *cachep, + struct array_cache *ac, int node) { struct kmem_list3 *rl3 = cachep->nodelists[node]; @@ -826,7 +827,7 @@ static inline void __drain_alien_cache(kmem_cache_t *cachep, struct array_cache static void drain_alien_cache(kmem_cache_t *cachep, struct kmem_list3 *l3) { - int i=0; + int i = 0; struct array_cache *ac; unsigned long flags; @@ -846,10 +847,10 @@ static void drain_alien_cache(kmem_cache_t *cachep, struct kmem_list3 *l3) #endif static int __devinit cpuup_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) + unsigned long action, void *hcpu) { long cpu = (long)hcpu; - kmem_cache_t* cachep; + kmem_cache_t *cachep; struct kmem_list3 *l3 = NULL; int node = cpu_to_node(cpu); int memsize = sizeof(struct kmem_list3); @@ -871,27 +872,27 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, */ if (!cachep->nodelists[node]) { if (!(l3 = kmalloc_node(memsize, - GFP_KERNEL, node))) + GFP_KERNEL, node))) goto bad; kmem_list3_init(l3); l3->next_reap = jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + ((unsigned long)cachep) % REAPTIMEOUT_LIST3; cachep->nodelists[node] = l3; } spin_lock_irq(&cachep->nodelists[node]->list_lock); cachep->nodelists[node]->free_limit = - (1 + nr_cpus_node(node)) * - cachep->batchcount + cachep->num; + (1 + nr_cpus_node(node)) * + cachep->batchcount + cachep->num; spin_unlock_irq(&cachep->nodelists[node]->list_lock); } /* Now we can go ahead with allocating the shared array's - & array cache's */ + & array cache's */ list_for_each_entry(cachep, &cache_chain, next) { nc = alloc_arraycache(node, cachep->limit, - cachep->batchcount); + cachep->batchcount); if (!nc) goto bad; cachep->array[cpu] = nc; @@ -900,12 +901,13 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, BUG_ON(!l3); if (!l3->shared) { if (!(nc = alloc_arraycache(node, - cachep->shared*cachep->batchcount, - 0xbaadf00d))) - goto bad; + cachep->shared * + cachep->batchcount, + 0xbaadf00d))) + goto bad; /* we are serialised from CPU_DEAD or - CPU_UP_CANCELLED by the cpucontrol lock */ + CPU_UP_CANCELLED by the cpucontrol lock */ l3->shared = nc; } } @@ -942,13 +944,13 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, free_block(cachep, nc->entry, nc->avail, node); if (!cpus_empty(mask)) { - spin_unlock(&l3->list_lock); - goto unlock_cache; - } + spin_unlock(&l3->list_lock); + goto unlock_cache; + } if (l3->shared) { free_block(cachep, l3->shared->entry, - l3->shared->avail, node); + l3->shared->avail, node); kfree(l3->shared); l3->shared = NULL; } @@ -966,7 +968,7 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, } else { spin_unlock(&l3->list_lock); } -unlock_cache: + unlock_cache: spin_unlock_irq(&cachep->spinlock); kfree(nc); } @@ -975,7 +977,7 @@ unlock_cache: #endif } return NOTIFY_OK; -bad: + bad: up(&cache_chain_sem); return NOTIFY_BAD; } @@ -985,8 +987,7 @@ static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 }; /* * swap the static kmem_list3 with kmalloced memory */ -static void init_list(kmem_cache_t *cachep, struct kmem_list3 *list, - int nodeid) +static void init_list(kmem_cache_t *cachep, struct kmem_list3 *list, int nodeid) { struct kmem_list3 *ptr; @@ -1055,14 +1056,14 @@ void __init kmem_cache_init(void) cache_cache.objsize = ALIGN(cache_cache.objsize, cache_line_size()); cache_estimate(0, cache_cache.objsize, cache_line_size(), 0, - &left_over, &cache_cache.num); + &left_over, &cache_cache.num); if (!cache_cache.num) BUG(); - cache_cache.colour = left_over/cache_cache.colour_off; + cache_cache.colour = left_over / cache_cache.colour_off; cache_cache.colour_next = 0; - cache_cache.slab_size = ALIGN(cache_cache.num*sizeof(kmem_bufctl_t) + - sizeof(struct slab), cache_line_size()); + cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) + + sizeof(struct slab), cache_line_size()); /* 2+3) create the kmalloc caches */ sizes = malloc_sizes; @@ -1074,14 +1075,18 @@ void __init kmem_cache_init(void) */ sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name, - sizes[INDEX_AC].cs_size, ARCH_KMALLOC_MINALIGN, - (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); + sizes[INDEX_AC].cs_size, + ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS | + SLAB_PANIC), NULL, NULL); if (INDEX_AC != INDEX_L3) sizes[INDEX_L3].cs_cachep = - kmem_cache_create(names[INDEX_L3].name, - sizes[INDEX_L3].cs_size, ARCH_KMALLOC_MINALIGN, - (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); + kmem_cache_create(names[INDEX_L3].name, + sizes[INDEX_L3].cs_size, + ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, + NULL); while (sizes->cs_size != ULONG_MAX) { /* @@ -1091,35 +1096,41 @@ void __init kmem_cache_init(void) * Note for systems short on memory removing the alignment will * allow tighter packing of the smaller caches. */ - if(!sizes->cs_cachep) + if (!sizes->cs_cachep) sizes->cs_cachep = kmem_cache_create(names->name, - sizes->cs_size, ARCH_KMALLOC_MINALIGN, - (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); + sizes->cs_size, + ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS + | SLAB_PANIC), + NULL, NULL); /* Inc off-slab bufctl limit until the ceiling is hit. */ if (!(OFF_SLAB(sizes->cs_cachep))) { - offslab_limit = sizes->cs_size-sizeof(struct slab); + offslab_limit = sizes->cs_size - sizeof(struct slab); offslab_limit /= sizeof(kmem_bufctl_t); } sizes->cs_dmacachep = kmem_cache_create(names->name_dma, - sizes->cs_size, ARCH_KMALLOC_MINALIGN, - (ARCH_KMALLOC_FLAGS | SLAB_CACHE_DMA | SLAB_PANIC), - NULL, NULL); + sizes->cs_size, + ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS | + SLAB_CACHE_DMA | + SLAB_PANIC), NULL, + NULL); sizes++; names++; } /* 4) Replace the bootstrap head arrays */ { - void * ptr; + void *ptr; ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); local_irq_disable(); BUG_ON(ac_data(&cache_cache) != &initarray_cache.cache); memcpy(ptr, ac_data(&cache_cache), - sizeof(struct arraycache_init)); + sizeof(struct arraycache_init)); cache_cache.array[smp_processor_id()] = ptr; local_irq_enable(); @@ -1127,11 +1138,11 @@ void __init kmem_cache_init(void) local_irq_disable(); BUG_ON(ac_data(malloc_sizes[INDEX_AC].cs_cachep) - != &initarray_generic.cache); + != &initarray_generic.cache); memcpy(ptr, ac_data(malloc_sizes[INDEX_AC].cs_cachep), - sizeof(struct arraycache_init)); + sizeof(struct arraycache_init)); malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] = - ptr; + ptr; local_irq_enable(); } /* 5) Replace the bootstrap kmem_list3's */ @@ -1139,16 +1150,16 @@ void __init kmem_cache_init(void) int node; /* Replace the static kmem_list3 structures for the boot cpu */ init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], - numa_node_id()); + numa_node_id()); for_each_online_node(node) { init_list(malloc_sizes[INDEX_AC].cs_cachep, - &initkmem_list3[SIZE_AC+node], node); + &initkmem_list3[SIZE_AC + node], node); if (INDEX_AC != INDEX_L3) { init_list(malloc_sizes[INDEX_L3].cs_cachep, - &initkmem_list3[SIZE_L3+node], - node); + &initkmem_list3[SIZE_L3 + node], + node); } } } @@ -1158,7 +1169,7 @@ void __init kmem_cache_init(void) kmem_cache_t *cachep; down(&cache_chain_sem); list_for_each_entry(cachep, &cache_chain, next) - enable_cpucache(cachep); + enable_cpucache(cachep); up(&cache_chain_sem); } @@ -1184,7 +1195,7 @@ static int __init cpucache_init(void) * pages to gfp. */ for_each_online_cpu(cpu) - start_cpu_timer(cpu); + start_cpu_timer(cpu); return 0; } @@ -1226,7 +1237,7 @@ static void *kmem_getpages(kmem_cache_t *cachep, gfp_t flags, int nodeid) */ static void kmem_freepages(kmem_cache_t *cachep, void *addr) { - unsigned long i = (1<gfporder); + unsigned long i = (1 << cachep->gfporder); struct page *page = virt_to_page(addr); const unsigned long nr_freed = i; @@ -1239,13 +1250,13 @@ static void kmem_freepages(kmem_cache_t *cachep, void *addr) if (current->reclaim_state) current->reclaim_state->reclaimed_slab += nr_freed; free_pages((unsigned long)addr, cachep->gfporder); - if (cachep->flags & SLAB_RECLAIM_ACCOUNT) - atomic_sub(1<gfporder, &slab_reclaim_pages); + if (cachep->flags & SLAB_RECLAIM_ACCOUNT) + atomic_sub(1 << cachep->gfporder, &slab_reclaim_pages); } static void kmem_rcu_free(struct rcu_head *head) { - struct slab_rcu *slab_rcu = (struct slab_rcu *) head; + struct slab_rcu *slab_rcu = (struct slab_rcu *)head; kmem_cache_t *cachep = slab_rcu->cachep; kmem_freepages(cachep, slab_rcu->addr); @@ -1257,19 +1268,19 @@ static void kmem_rcu_free(struct rcu_head *head) #ifdef CONFIG_DEBUG_PAGEALLOC static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, - unsigned long caller) + unsigned long caller) { int size = obj_reallen(cachep); - addr = (unsigned long *)&((char*)addr)[obj_dbghead(cachep)]; + addr = (unsigned long *)&((char *)addr)[obj_dbghead(cachep)]; - if (size < 5*sizeof(unsigned long)) + if (size < 5 * sizeof(unsigned long)) return; - *addr++=0x12345678; - *addr++=caller; - *addr++=smp_processor_id(); - size -= 3*sizeof(unsigned long); + *addr++ = 0x12345678; + *addr++ = caller; + *addr++ = smp_processor_id(); + size -= 3 * sizeof(unsigned long); { unsigned long *sptr = &caller; unsigned long svalue; @@ -1277,7 +1288,7 @@ static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, while (!kstack_end(sptr)) { svalue = *sptr++; if (kernel_text_address(svalue)) { - *addr++=svalue; + *addr++ = svalue; size -= sizeof(unsigned long); if (size <= sizeof(unsigned long)) break; @@ -1285,25 +1296,25 @@ static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, } } - *addr++=0x87654321; + *addr++ = 0x87654321; } #endif static void poison_obj(kmem_cache_t *cachep, void *addr, unsigned char val) { int size = obj_reallen(cachep); - addr = &((char*)addr)[obj_dbghead(cachep)]; + addr = &((char *)addr)[obj_dbghead(cachep)]; memset(addr, val, size); - *(unsigned char *)(addr+size-1) = POISON_END; + *(unsigned char *)(addr + size - 1) = POISON_END; } static void dump_line(char *data, int offset, int limit) { int i; printk(KERN_ERR "%03x:", offset); - for (i=0;iflags & SLAB_RED_ZONE) { printk(KERN_ERR "Redzone: 0x%lx/0x%lx.\n", - *dbg_redzone1(cachep, objp), - *dbg_redzone2(cachep, objp)); + *dbg_redzone1(cachep, objp), + *dbg_redzone2(cachep, objp)); } if (cachep->flags & SLAB_STORE_USER) { printk(KERN_ERR "Last user: [<%p>]", - *dbg_userword(cachep, objp)); + *dbg_userword(cachep, objp)); print_symbol("(%s)", - (unsigned long)*dbg_userword(cachep, objp)); + (unsigned long)*dbg_userword(cachep, objp)); printk("\n"); } - realobj = (char*)objp+obj_dbghead(cachep); + realobj = (char *)objp + obj_dbghead(cachep); size = obj_reallen(cachep); - for (i=0; i size) - limit = size-i; + if (i + limit > size) + limit = size - i; dump_line(realobj, i, limit); } } @@ -1346,27 +1357,28 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp) int size, i; int lines = 0; - realobj = (char*)objp+obj_dbghead(cachep); + realobj = (char *)objp + obj_dbghead(cachep); size = obj_reallen(cachep); - for (i=0;i size) - limit = size-i; + if (i + limit > size) + limit = size - i; dump_line(realobj, i, limit); i += 16; lines++; @@ -1382,19 +1394,19 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp) struct slab *slabp = page_get_slab(virt_to_page(objp)); int objnr; - objnr = (objp-slabp->s_mem)/cachep->objsize; + objnr = (objp - slabp->s_mem) / cachep->objsize; if (objnr) { - objp = slabp->s_mem+(objnr-1)*cachep->objsize; - realobj = (char*)objp+obj_dbghead(cachep); + objp = slabp->s_mem + (objnr - 1) * cachep->objsize; + realobj = (char *)objp + obj_dbghead(cachep); printk(KERN_ERR "Prev obj: start=%p, len=%d\n", - realobj, size); + realobj, size); print_objinfo(cachep, objp, 2); } - if (objnr+1 < cachep->num) { - objp = slabp->s_mem+(objnr+1)*cachep->objsize; - realobj = (char*)objp+obj_dbghead(cachep); + if (objnr + 1 < cachep->num) { + objp = slabp->s_mem + (objnr + 1) * cachep->objsize; + realobj = (char *)objp + obj_dbghead(cachep); printk(KERN_ERR "Next obj: start=%p, len=%d\n", - realobj, size); + realobj, size); print_objinfo(cachep, objp, 2); } } @@ -1405,7 +1417,7 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp) * Before calling the slab must have been unlinked from the cache. * The cache-lock is not held/needed. */ -static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) +static void slab_destroy(kmem_cache_t *cachep, struct slab *slabp) { void *addr = slabp->s_mem - slabp->colouroff; @@ -1416,8 +1428,11 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) if (cachep->flags & SLAB_POISON) { #ifdef CONFIG_DEBUG_PAGEALLOC - if ((cachep->objsize%PAGE_SIZE)==0 && OFF_SLAB(cachep)) - kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE,1); + if ((cachep->objsize % PAGE_SIZE) == 0 + && OFF_SLAB(cachep)) + kernel_map_pages(virt_to_page(objp), + cachep->objsize / PAGE_SIZE, + 1); else check_poison_obj(cachep, objp); #else @@ -1427,20 +1442,20 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) if (cachep->flags & SLAB_RED_ZONE) { if (*dbg_redzone1(cachep, objp) != RED_INACTIVE) slab_error(cachep, "start of a freed object " - "was overwritten"); + "was overwritten"); if (*dbg_redzone2(cachep, objp) != RED_INACTIVE) slab_error(cachep, "end of a freed object " - "was overwritten"); + "was overwritten"); } if (cachep->dtor && !(cachep->flags & SLAB_POISON)) - (cachep->dtor)(objp+obj_dbghead(cachep), cachep, 0); + (cachep->dtor) (objp + obj_dbghead(cachep), cachep, 0); } #else if (cachep->dtor) { int i; for (i = 0; i < cachep->num; i++) { - void* objp = slabp->s_mem+cachep->objsize*i; - (cachep->dtor)(objp, cachep, 0); + void *objp = slabp->s_mem + cachep->objsize * i; + (cachep->dtor) (objp, cachep, 0); } } #endif @@ -1448,7 +1463,7 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) { struct slab_rcu *slab_rcu; - slab_rcu = (struct slab_rcu *) slabp; + slab_rcu = (struct slab_rcu *)slabp; slab_rcu->cachep = cachep; slab_rcu->addr = addr; call_rcu(&slab_rcu->head, kmem_rcu_free); @@ -1466,10 +1481,10 @@ static inline void set_up_list3s(kmem_cache_t *cachep, int index) int node; for_each_online_node(node) { - cachep->nodelists[node] = &initkmem_list3[index+node]; + cachep->nodelists[node] = &initkmem_list3[index + node]; cachep->nodelists[node]->next_reap = jiffies + - REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep) % REAPTIMEOUT_LIST3; } } @@ -1486,7 +1501,7 @@ static inline size_t calculate_slab_order(kmem_cache_t *cachep, size_t size, { size_t left_over = 0; - for ( ; ; cachep->gfporder++) { + for (;; cachep->gfporder++) { unsigned int num; size_t remainder; @@ -1566,14 +1581,13 @@ kmem_cache_create (const char *name, size_t size, size_t align, * Sanity checks... these are all serious usage bugs. */ if ((!name) || - in_interrupt() || - (size < BYTES_PER_WORD) || - (size > (1< (1 << MAX_OBJ_ORDER) * PAGE_SIZE) || (dtor && !ctor)) { + printk(KERN_ERR "%s: Early error in slab %s\n", + __FUNCTION__, name); + BUG(); + } down(&cache_chain_sem); @@ -1593,11 +1607,11 @@ kmem_cache_create (const char *name, size_t size, size_t align, set_fs(old_fs); if (res) { printk("SLAB: cache with size %d has lost its name\n", - pc->objsize); + pc->objsize); continue; } - if (!strcmp(pc->name,name)) { + if (!strcmp(pc->name, name)) { printk("kmem_cache_create: duplicate cache %s\n", name); dump_stack(); goto oops; @@ -1609,10 +1623,9 @@ kmem_cache_create (const char *name, size_t size, size_t align, if ((flags & SLAB_DEBUG_INITIAL) && !ctor) { /* No constructor, but inital state check requested */ printk(KERN_ERR "%s: No con, but init state check " - "requested - %s\n", __FUNCTION__, name); + "requested - %s\n", __FUNCTION__, name); flags &= ~SLAB_DEBUG_INITIAL; } - #if FORCED_DEBUG /* * Enable redzoning and last user accounting, except for caches with @@ -1620,8 +1633,9 @@ kmem_cache_create (const char *name, size_t size, size_t align, * above the next power of two: caches with object sizes just above a * power of two have a significant amount of internal fragmentation. */ - if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD))) - flags |= SLAB_RED_ZONE|SLAB_STORE_USER; + if ((size < 4096 + || fls(size - 1) == fls(size - 1 + 3 * BYTES_PER_WORD))) + flags |= SLAB_RED_ZONE | SLAB_STORE_USER; if (!(flags & SLAB_DESTROY_BY_RCU)) flags |= SLAB_POISON; #endif @@ -1642,9 +1656,9 @@ kmem_cache_create (const char *name, size_t size, size_t align, * unaligned accesses for some archs when redzoning is used, and makes * sure any on-slab bufctl's are also correctly aligned. */ - if (size & (BYTES_PER_WORD-1)) { - size += (BYTES_PER_WORD-1); - size &= ~(BYTES_PER_WORD-1); + if (size & (BYTES_PER_WORD - 1)) { + size += (BYTES_PER_WORD - 1); + size &= ~(BYTES_PER_WORD - 1); } /* calculate out the final buffer alignment: */ @@ -1655,7 +1669,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, * objects into one cacheline. */ ralign = cache_line_size(); - while (size <= ralign/2) + while (size <= ralign / 2) ralign /= 2; } else { ralign = BYTES_PER_WORD; @@ -1664,13 +1678,13 @@ kmem_cache_create (const char *name, size_t size, size_t align, if (ralign < ARCH_SLAB_MINALIGN) { ralign = ARCH_SLAB_MINALIGN; if (ralign > BYTES_PER_WORD) - flags &= ~(SLAB_RED_ZONE|SLAB_STORE_USER); + flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER); } /* 3) caller mandated alignment: disables debug if necessary */ if (ralign < align) { ralign = align; if (ralign > BYTES_PER_WORD) - flags &= ~(SLAB_RED_ZONE|SLAB_STORE_USER); + flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER); } /* 4) Store it. Note that the debug code below can reduce * the alignment to BYTES_PER_WORD. @@ -1692,7 +1706,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, /* add space for red zone words */ cachep->dbghead += BYTES_PER_WORD; - size += 2*BYTES_PER_WORD; + size += 2 * BYTES_PER_WORD; } if (flags & SLAB_STORE_USER) { /* user store requires word alignment and @@ -1703,7 +1717,8 @@ kmem_cache_create (const char *name, size_t size, size_t align, size += BYTES_PER_WORD; } #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) - if (size >= malloc_sizes[INDEX_L3+1].cs_size && cachep->reallen > cache_line_size() && size < PAGE_SIZE) { + if (size >= malloc_sizes[INDEX_L3 + 1].cs_size + && cachep->reallen > cache_line_size() && size < PAGE_SIZE) { cachep->dbghead += PAGE_SIZE - size; size = PAGE_SIZE; } @@ -1711,7 +1726,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, #endif /* Determine if the slab management is 'on' or 'off' slab. */ - if (size >= (PAGE_SIZE>>3)) + if (size >= (PAGE_SIZE >> 3)) /* * Size is large, assume best to place the slab management obj * off-slab (should allow better packing of objs). @@ -1728,7 +1743,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, */ cachep->gfporder = 0; cache_estimate(cachep->gfporder, size, align, flags, - &left_over, &cachep->num); + &left_over, &cachep->num); } else left_over = calculate_slab_order(cachep, size, align, flags); @@ -1738,8 +1753,8 @@ kmem_cache_create (const char *name, size_t size, size_t align, cachep = NULL; goto oops; } - slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t) - + sizeof(struct slab), align); + slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t) + + sizeof(struct slab), align); /* * If the slab has been placed off-slab, and we have enough space then @@ -1752,14 +1767,15 @@ kmem_cache_create (const char *name, size_t size, size_t align, if (flags & CFLGS_OFF_SLAB) { /* really off slab. No need for manual alignment */ - slab_size = cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab); + slab_size = + cachep->num * sizeof(kmem_bufctl_t) + sizeof(struct slab); } cachep->colour_off = cache_line_size(); /* Offset must be a multiple of the alignment. */ if (cachep->colour_off < align) cachep->colour_off = align; - cachep->colour = left_over/cachep->colour_off; + cachep->colour = left_over / cachep->colour_off; cachep->slab_size = slab_size; cachep->flags = flags; cachep->gfpflags = 0; @@ -1786,7 +1802,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, * the creation of further caches will BUG(). */ cachep->array[smp_processor_id()] = - &initarray_generic.cache; + &initarray_generic.cache; /* If the cache that's used by * kmalloc(sizeof(kmem_list3)) is the first cache, @@ -1800,8 +1816,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, g_cpucache_up = PARTIAL_AC; } else { cachep->array[smp_processor_id()] = - kmalloc(sizeof(struct arraycache_init), - GFP_KERNEL); + kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); if (g_cpucache_up == PARTIAL_AC) { set_up_list3s(cachep, SIZE_L3); @@ -1811,16 +1826,18 @@ kmem_cache_create (const char *name, size_t size, size_t align, for_each_online_node(node) { cachep->nodelists[node] = - kmalloc_node(sizeof(struct kmem_list3), - GFP_KERNEL, node); + kmalloc_node(sizeof + (struct kmem_list3), + GFP_KERNEL, node); BUG_ON(!cachep->nodelists[node]); - kmem_list3_init(cachep->nodelists[node]); + kmem_list3_init(cachep-> + nodelists[node]); } } } cachep->nodelists[numa_node_id()]->next_reap = - jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + jiffies + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep) % REAPTIMEOUT_LIST3; BUG_ON(!ac_data(cachep)); ac_data(cachep)->avail = 0; @@ -1829,15 +1846,15 @@ kmem_cache_create (const char *name, size_t size, size_t align, ac_data(cachep)->touched = 0; cachep->batchcount = 1; cachep->limit = BOOT_CPUCACHE_ENTRIES; - } + } /* cache setup completed, link it into the list */ list_add(&cachep->next, &cache_chain); unlock_cpu_hotplug(); -oops: + oops: if (!cachep && (flags & SLAB_PANIC)) panic("kmem_cache_create(): failed to create slab `%s'\n", - name); + name); up(&cache_chain_sem); return cachep; } @@ -1880,7 +1897,7 @@ static inline void check_spinlock_acquired_node(kmem_cache_t *cachep, int node) /* * Waits for all CPUs to execute func(). */ -static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg) +static void smp_call_function_all_cpus(void (*func)(void *arg), void *arg) { check_irq_on(); preempt_disable(); @@ -1895,12 +1912,12 @@ static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg) preempt_enable(); } -static void drain_array_locked(kmem_cache_t* cachep, - struct array_cache *ac, int force, int node); +static void drain_array_locked(kmem_cache_t *cachep, struct array_cache *ac, + int force, int node); static void do_drain(void *arg) { - kmem_cache_t *cachep = (kmem_cache_t*)arg; + kmem_cache_t *cachep = (kmem_cache_t *) arg; struct array_cache *ac; int node = numa_node_id(); @@ -1920,7 +1937,7 @@ static void drain_cpu_caches(kmem_cache_t *cachep) smp_call_function_all_cpus(do_drain, cachep); check_irq_on(); spin_lock_irq(&cachep->spinlock); - for_each_online_node(node) { + for_each_online_node(node) { l3 = cachep->nodelists[node]; if (l3) { spin_lock(&l3->list_lock); @@ -1958,8 +1975,7 @@ static int __node_shrink(kmem_cache_t *cachep, int node) slab_destroy(cachep, slabp); spin_lock_irq(&l3->list_lock); } - ret = !list_empty(&l3->slabs_full) || - !list_empty(&l3->slabs_partial); + ret = !list_empty(&l3->slabs_full) || !list_empty(&l3->slabs_partial); return ret; } @@ -2015,7 +2031,7 @@ EXPORT_SYMBOL(kmem_cache_shrink); * The caller must guarantee that noone will allocate memory from the cache * during the kmem_cache_destroy(). */ -int kmem_cache_destroy(kmem_cache_t * cachep) +int kmem_cache_destroy(kmem_cache_t *cachep) { int i; struct kmem_list3 *l3; @@ -2037,7 +2053,7 @@ int kmem_cache_destroy(kmem_cache_t * cachep) if (__cache_shrink(cachep)) { slab_error(cachep, "Can't free all objects"); down(&cache_chain_sem); - list_add(&cachep->next,&cache_chain); + list_add(&cachep->next, &cache_chain); up(&cache_chain_sem); unlock_cpu_hotplug(); return 1; @@ -2047,7 +2063,7 @@ int kmem_cache_destroy(kmem_cache_t * cachep) synchronize_rcu(); for_each_online_cpu(i) - kfree(cachep->array[i]); + kfree(cachep->array[i]); /* NUMA: free the list3 structures */ for_each_online_node(i) { @@ -2066,39 +2082,39 @@ int kmem_cache_destroy(kmem_cache_t * cachep) EXPORT_SYMBOL(kmem_cache_destroy); /* Get the memory for a slab management obj. */ -static struct slab* alloc_slabmgmt(kmem_cache_t *cachep, void *objp, - int colour_off, gfp_t local_flags) +static struct slab *alloc_slabmgmt(kmem_cache_t *cachep, void *objp, + int colour_off, gfp_t local_flags) { struct slab *slabp; - + if (OFF_SLAB(cachep)) { /* Slab management obj is off-slab. */ slabp = kmem_cache_alloc(cachep->slabp_cache, local_flags); if (!slabp) return NULL; } else { - slabp = objp+colour_off; + slabp = objp + colour_off; colour_off += cachep->slab_size; } slabp->inuse = 0; slabp->colouroff = colour_off; - slabp->s_mem = objp+colour_off; + slabp->s_mem = objp + colour_off; return slabp; } static inline kmem_bufctl_t *slab_bufctl(struct slab *slabp) { - return (kmem_bufctl_t *)(slabp+1); + return (kmem_bufctl_t *) (slabp + 1); } static void cache_init_objs(kmem_cache_t *cachep, - struct slab *slabp, unsigned long ctor_flags) + struct slab *slabp, unsigned long ctor_flags) { int i; for (i = 0; i < cachep->num; i++) { - void *objp = slabp->s_mem+cachep->objsize*i; + void *objp = slabp->s_mem + cachep->objsize * i; #if DEBUG /* need to poison the objs? */ if (cachep->flags & SLAB_POISON) @@ -2116,25 +2132,28 @@ static void cache_init_objs(kmem_cache_t *cachep, * Otherwise, deadlock. They must also be threaded. */ if (cachep->ctor && !(cachep->flags & SLAB_POISON)) - cachep->ctor(objp+obj_dbghead(cachep), cachep, ctor_flags); + cachep->ctor(objp + obj_dbghead(cachep), cachep, + ctor_flags); if (cachep->flags & SLAB_RED_ZONE) { if (*dbg_redzone2(cachep, objp) != RED_INACTIVE) slab_error(cachep, "constructor overwrote the" - " end of an object"); + " end of an object"); if (*dbg_redzone1(cachep, objp) != RED_INACTIVE) slab_error(cachep, "constructor overwrote the" - " start of an object"); + " start of an object"); } - if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) && cachep->flags & SLAB_POISON) - kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0); + if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) + && cachep->flags & SLAB_POISON) + kernel_map_pages(virt_to_page(objp), + cachep->objsize / PAGE_SIZE, 0); #else if (cachep->ctor) cachep->ctor(objp, cachep, ctor_flags); #endif - slab_bufctl(slabp)[i] = i+1; + slab_bufctl(slabp)[i] = i + 1; } - slab_bufctl(slabp)[i-1] = BUFCTL_END; + slab_bufctl(slabp)[i - 1] = BUFCTL_END; slabp->free = 0; } @@ -2170,17 +2189,17 @@ static void set_slab_attr(kmem_cache_t *cachep, struct slab *slabp, void *objp) */ static int cache_grow(kmem_cache_t *cachep, gfp_t flags, int nodeid) { - struct slab *slabp; - void *objp; - size_t offset; - gfp_t local_flags; - unsigned long ctor_flags; + struct slab *slabp; + void *objp; + size_t offset; + gfp_t local_flags; + unsigned long ctor_flags; struct kmem_list3 *l3; /* Be lazy and only check for valid flags here, - * keeping it out of the critical path in kmem_cache_alloc(). + * keeping it out of the critical path in kmem_cache_alloc(). */ - if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) + if (flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | SLAB_NO_GROW)) BUG(); if (flags & SLAB_NO_GROW) return 0; @@ -2246,9 +2265,9 @@ static int cache_grow(kmem_cache_t *cachep, gfp_t flags, int nodeid) l3->free_objects += cachep->num; spin_unlock(&l3->list_lock); return 1; -opps1: + opps1: kmem_freepages(cachep, objp); -failed: + failed: if (local_flags & __GFP_WAIT) local_irq_disable(); return 0; @@ -2268,18 +2287,19 @@ static void kfree_debugcheck(const void *objp) if (!virt_addr_valid(objp)) { printk(KERN_ERR "kfree_debugcheck: out of range ptr %lxh.\n", - (unsigned long)objp); - BUG(); + (unsigned long)objp); + BUG(); } page = virt_to_page(objp); if (!PageSlab(page)) { - printk(KERN_ERR "kfree_debugcheck: bad ptr %lxh.\n", (unsigned long)objp); + printk(KERN_ERR "kfree_debugcheck: bad ptr %lxh.\n", + (unsigned long)objp); BUG(); } } static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp, - void *caller) + void *caller) { struct page *page; unsigned int objnr; @@ -2290,20 +2310,26 @@ static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp, page = virt_to_page(objp); if (page_get_cache(page) != cachep) { - printk(KERN_ERR "mismatch in kmem_cache_free: expected cache %p, got %p\n", - page_get_cache(page),cachep); + printk(KERN_ERR + "mismatch in kmem_cache_free: expected cache %p, got %p\n", + page_get_cache(page), cachep); printk(KERN_ERR "%p is %s.\n", cachep, cachep->name); - printk(KERN_ERR "%p is %s.\n", page_get_cache(page), page_get_cache(page)->name); + printk(KERN_ERR "%p is %s.\n", page_get_cache(page), + page_get_cache(page)->name); WARN_ON(1); } slabp = page_get_slab(page); if (cachep->flags & SLAB_RED_ZONE) { - if (*dbg_redzone1(cachep, objp) != RED_ACTIVE || *dbg_redzone2(cachep, objp) != RED_ACTIVE) { - slab_error(cachep, "double free, or memory outside" - " object was overwritten"); - printk(KERN_ERR "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n", - objp, *dbg_redzone1(cachep, objp), *dbg_redzone2(cachep, objp)); + if (*dbg_redzone1(cachep, objp) != RED_ACTIVE + || *dbg_redzone2(cachep, objp) != RED_ACTIVE) { + slab_error(cachep, + "double free, or memory outside" + " object was overwritten"); + printk(KERN_ERR + "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n", + objp, *dbg_redzone1(cachep, objp), + *dbg_redzone2(cachep, objp)); } *dbg_redzone1(cachep, objp) = RED_INACTIVE; *dbg_redzone2(cachep, objp) = RED_INACTIVE; @@ -2311,30 +2337,31 @@ static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp, if (cachep->flags & SLAB_STORE_USER) *dbg_userword(cachep, objp) = caller; - objnr = (objp-slabp->s_mem)/cachep->objsize; + objnr = (objp - slabp->s_mem) / cachep->objsize; BUG_ON(objnr >= cachep->num); - BUG_ON(objp != slabp->s_mem + objnr*cachep->objsize); + BUG_ON(objp != slabp->s_mem + objnr * cachep->objsize); if (cachep->flags & SLAB_DEBUG_INITIAL) { /* Need to call the slab's constructor so the * caller can perform a verify of its state (debugging). * Called without the cache-lock held. */ - cachep->ctor(objp+obj_dbghead(cachep), - cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY); + cachep->ctor(objp + obj_dbghead(cachep), + cachep, SLAB_CTOR_CONSTRUCTOR | SLAB_CTOR_VERIFY); } if (cachep->flags & SLAB_POISON && cachep->dtor) { /* we want to cache poison the object, * call the destruction callback */ - cachep->dtor(objp+obj_dbghead(cachep), cachep, 0); + cachep->dtor(objp + obj_dbghead(cachep), cachep, 0); } if (cachep->flags & SLAB_POISON) { #ifdef CONFIG_DEBUG_PAGEALLOC if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) { store_stackinfo(cachep, objp, (unsigned long)caller); - kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0); + kernel_map_pages(virt_to_page(objp), + cachep->objsize / PAGE_SIZE, 0); } else { poison_obj(cachep, objp, POISON_FREE); } @@ -2349,7 +2376,7 @@ static void check_slabp(kmem_cache_t *cachep, struct slab *slabp) { kmem_bufctl_t i; int entries = 0; - + /* Check slab's freelist to see if this obj is there. */ for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) { entries++; @@ -2357,13 +2384,16 @@ static void check_slabp(kmem_cache_t *cachep, struct slab *slabp) goto bad; } if (entries != cachep->num - slabp->inuse) { -bad: - printk(KERN_ERR "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n", - cachep->name, cachep->num, slabp, slabp->inuse); - for (i=0;inum*sizeof(kmem_bufctl_t);i++) { - if ((i%16)==0) + bad: + printk(KERN_ERR + "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n", + cachep->name, cachep->num, slabp, slabp->inuse); + for (i = 0; + i < sizeof(slabp) + cachep->num * sizeof(kmem_bufctl_t); + i++) { + if ((i % 16) == 0) printk("\n%03x:", i); - printk(" %02x", ((unsigned char*)slabp)[i]); + printk(" %02x", ((unsigned char *)slabp)[i]); } printk("\n"); BUG(); @@ -2383,7 +2413,7 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, gfp_t flags) check_irq_off(); ac = ac_data(cachep); -retry: + retry: batchcount = ac->batchcount; if (!ac->touched && batchcount > BATCHREFILL_LIMIT) { /* if there was little recent activity on this @@ -2405,8 +2435,8 @@ retry: shared_array->avail -= batchcount; ac->avail = batchcount; memcpy(ac->entry, - &(shared_array->entry[shared_array->avail]), - sizeof(void*)*batchcount); + &(shared_array->entry[shared_array->avail]), + sizeof(void *) * batchcount); shared_array->touched = 1; goto alloc_done; } @@ -2434,7 +2464,7 @@ retry: /* get obj pointer */ ac->entry[ac->avail++] = slabp->s_mem + - slabp->free*cachep->objsize; + slabp->free * cachep->objsize; slabp->inuse++; next = slab_bufctl(slabp)[slabp->free]; @@ -2442,7 +2472,7 @@ retry: slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; WARN_ON(numa_node_id() != slabp->nodeid); #endif - slabp->free = next; + slabp->free = next; } check_slabp(cachep, slabp); @@ -2454,9 +2484,9 @@ retry: list_add(&slabp->list, &l3->slabs_partial); } -must_grow: + must_grow: l3->free_objects -= ac->avail; -alloc_done: + alloc_done: spin_unlock(&l3->list_lock); if (unlikely(!ac->avail)) { @@ -2468,7 +2498,7 @@ alloc_done: if (!x && ac->avail == 0) // no objects in sight? abort return NULL; - if (!ac->avail) // objects refilled by interrupt? + if (!ac->avail) // objects refilled by interrupt? goto retry; } ac->touched = 1; @@ -2485,16 +2515,16 @@ cache_alloc_debugcheck_before(kmem_cache_t *cachep, gfp_t flags) } #if DEBUG -static void * -cache_alloc_debugcheck_after(kmem_cache_t *cachep, - gfp_t flags, void *objp, void *caller) +static void *cache_alloc_debugcheck_after(kmem_cache_t *cachep, gfp_t flags, + void *objp, void *caller) { - if (!objp) + if (!objp) return objp; - if (cachep->flags & SLAB_POISON) { + if (cachep->flags & SLAB_POISON) { #ifdef CONFIG_DEBUG_PAGEALLOC if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) - kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 1); + kernel_map_pages(virt_to_page(objp), + cachep->objsize / PAGE_SIZE, 1); else check_poison_obj(cachep, objp); #else @@ -2506,24 +2536,28 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep, *dbg_userword(cachep, objp) = caller; if (cachep->flags & SLAB_RED_ZONE) { - if (*dbg_redzone1(cachep, objp) != RED_INACTIVE || *dbg_redzone2(cachep, objp) != RED_INACTIVE) { - slab_error(cachep, "double free, or memory outside" - " object was overwritten"); - printk(KERN_ERR "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n", - objp, *dbg_redzone1(cachep, objp), *dbg_redzone2(cachep, objp)); + if (*dbg_redzone1(cachep, objp) != RED_INACTIVE + || *dbg_redzone2(cachep, objp) != RED_INACTIVE) { + slab_error(cachep, + "double free, or memory outside" + " object was overwritten"); + printk(KERN_ERR + "%p: redzone 1: 0x%lx, redzone 2: 0x%lx.\n", + objp, *dbg_redzone1(cachep, objp), + *dbg_redzone2(cachep, objp)); } *dbg_redzone1(cachep, objp) = RED_ACTIVE; *dbg_redzone2(cachep, objp) = RED_ACTIVE; } objp += obj_dbghead(cachep); if (cachep->ctor && cachep->flags & SLAB_POISON) { - unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR; + unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR; if (!(flags & __GFP_WAIT)) ctor_flags |= SLAB_CTOR_ATOMIC; cachep->ctor(objp, cachep, ctor_flags); - } + } return objp; } #else @@ -2532,7 +2566,7 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep, static inline void *____cache_alloc(kmem_cache_t *cachep, gfp_t flags) { - void* objp; + void *objp; struct array_cache *ac; check_irq_off(); @@ -2551,7 +2585,7 @@ static inline void *____cache_alloc(kmem_cache_t *cachep, gfp_t flags) static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags) { unsigned long save_flags; - void* objp; + void *objp; cache_alloc_debugcheck_before(cachep, flags); @@ -2559,7 +2593,7 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags) objp = ____cache_alloc(cachep, flags); local_irq_restore(save_flags); objp = cache_alloc_debugcheck_after(cachep, flags, objp, - __builtin_return_address(0)); + __builtin_return_address(0)); prefetchw(objp); return objp; } @@ -2571,74 +2605,75 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, gfp_t flags) static void *__cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid) { struct list_head *entry; - struct slab *slabp; - struct kmem_list3 *l3; - void *obj; - kmem_bufctl_t next; - int x; - - l3 = cachep->nodelists[nodeid]; - BUG_ON(!l3); - -retry: - spin_lock(&l3->list_lock); - entry = l3->slabs_partial.next; - if (entry == &l3->slabs_partial) { - l3->free_touched = 1; - entry = l3->slabs_free.next; - if (entry == &l3->slabs_free) - goto must_grow; - } - - slabp = list_entry(entry, struct slab, list); - check_spinlock_acquired_node(cachep, nodeid); - check_slabp(cachep, slabp); - - STATS_INC_NODEALLOCS(cachep); - STATS_INC_ACTIVE(cachep); - STATS_SET_HIGH(cachep); - - BUG_ON(slabp->inuse == cachep->num); - - /* get obj pointer */ - obj = slabp->s_mem + slabp->free*cachep->objsize; - slabp->inuse++; - next = slab_bufctl(slabp)[slabp->free]; + struct slab *slabp; + struct kmem_list3 *l3; + void *obj; + kmem_bufctl_t next; + int x; + + l3 = cachep->nodelists[nodeid]; + BUG_ON(!l3); + + retry: + spin_lock(&l3->list_lock); + entry = l3->slabs_partial.next; + if (entry == &l3->slabs_partial) { + l3->free_touched = 1; + entry = l3->slabs_free.next; + if (entry == &l3->slabs_free) + goto must_grow; + } + + slabp = list_entry(entry, struct slab, list); + check_spinlock_acquired_node(cachep, nodeid); + check_slabp(cachep, slabp); + + STATS_INC_NODEALLOCS(cachep); + STATS_INC_ACTIVE(cachep); + STATS_SET_HIGH(cachep); + + BUG_ON(slabp->inuse == cachep->num); + + /* get obj pointer */ + obj = slabp->s_mem + slabp->free * cachep->objsize; + slabp->inuse++; + next = slab_bufctl(slabp)[slabp->free]; #if DEBUG - slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; + slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; #endif - slabp->free = next; - check_slabp(cachep, slabp); - l3->free_objects--; - /* move slabp to correct slabp list: */ - list_del(&slabp->list); - - if (slabp->free == BUFCTL_END) { - list_add(&slabp->list, &l3->slabs_full); - } else { - list_add(&slabp->list, &l3->slabs_partial); - } + slabp->free = next; + check_slabp(cachep, slabp); + l3->free_objects--; + /* move slabp to correct slabp list: */ + list_del(&slabp->list); + + if (slabp->free == BUFCTL_END) { + list_add(&slabp->list, &l3->slabs_full); + } else { + list_add(&slabp->list, &l3->slabs_partial); + } - spin_unlock(&l3->list_lock); - goto done; + spin_unlock(&l3->list_lock); + goto done; -must_grow: - spin_unlock(&l3->list_lock); - x = cache_grow(cachep, flags, nodeid); + must_grow: + spin_unlock(&l3->list_lock); + x = cache_grow(cachep, flags, nodeid); - if (!x) - return NULL; + if (!x) + return NULL; - goto retry; -done: - return obj; + goto retry; + done: + return obj; } #endif /* * Caller needs to acquire correct kmem_list's list_lock */ -static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int node) +static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, + int node) { int i; struct kmem_list3 *l3; @@ -2661,7 +2696,7 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int n if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) { printk(KERN_ERR "slab: double free detected in cache " - "'%s', objp %p\n", cachep->name, objp); + "'%s', objp %p\n", cachep->name, objp); BUG(); } #endif @@ -2705,20 +2740,19 @@ static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac) spin_lock(&l3->list_lock); if (l3->shared) { struct array_cache *shared_array = l3->shared; - int max = shared_array->limit-shared_array->avail; + int max = shared_array->limit - shared_array->avail; if (max) { if (batchcount > max) batchcount = max; memcpy(&(shared_array->entry[shared_array->avail]), - ac->entry, - sizeof(void*)*batchcount); + ac->entry, sizeof(void *) * batchcount); shared_array->avail += batchcount; goto free_done; } } free_block(cachep, ac->entry, batchcount, node); -free_done: + free_done: #if STATS { int i = 0; @@ -2740,10 +2774,9 @@ free_done: spin_unlock(&l3->list_lock); ac->avail -= batchcount; memmove(ac->entry, &(ac->entry[batchcount]), - sizeof(void*)*ac->avail); + sizeof(void *) * ac->avail); } - /* * __cache_free * Release an obj back to its cache. If the obj has a constructed @@ -2768,7 +2801,8 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp) if (unlikely(slabp->nodeid != numa_node_id())) { struct array_cache *alien = NULL; int nodeid = slabp->nodeid; - struct kmem_list3 *l3 = cachep->nodelists[numa_node_id()]; + struct kmem_list3 *l3 = + cachep->nodelists[numa_node_id()]; STATS_INC_NODEFREES(cachep); if (l3->alien && l3->alien[nodeid]) { @@ -2776,15 +2810,15 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp) spin_lock(&alien->lock); if (unlikely(alien->avail == alien->limit)) __drain_alien_cache(cachep, - alien, nodeid); + alien, nodeid); alien->entry[alien->avail++] = objp; spin_unlock(&alien->lock); } else { spin_lock(&(cachep->nodelists[nodeid])-> - list_lock); + list_lock); free_block(cachep, &objp, 1, nodeid); spin_unlock(&(cachep->nodelists[nodeid])-> - list_lock); + list_lock); } return; } @@ -2831,9 +2865,9 @@ EXPORT_SYMBOL(kmem_cache_alloc); */ int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr) { - unsigned long addr = (unsigned long) ptr; + unsigned long addr = (unsigned long)ptr; unsigned long min_addr = PAGE_OFFSET; - unsigned long align_mask = BYTES_PER_WORD-1; + unsigned long align_mask = BYTES_PER_WORD - 1; unsigned long size = cachep->objsize; struct page *page; @@ -2853,7 +2887,7 @@ int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr) if (unlikely(page_get_cache(page) != cachep)) goto out; return 1; -out: + out: return 0; } @@ -2880,8 +2914,10 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid) if (unlikely(!cachep->nodelists[nodeid])) { /* Fall back to __cache_alloc if we run into trouble */ - printk(KERN_WARNING "slab: not allocating in inactive node %d for cache %s\n", nodeid, cachep->name); - return __cache_alloc(cachep,flags); + printk(KERN_WARNING + "slab: not allocating in inactive node %d for cache %s\n", + nodeid, cachep->name); + return __cache_alloc(cachep, flags); } cache_alloc_debugcheck_before(cachep, flags); @@ -2891,7 +2927,9 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, gfp_t flags, int nodeid) else ptr = __cache_alloc_node(cachep, flags, nodeid); local_irq_restore(save_flags); - ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, __builtin_return_address(0)); + ptr = + cache_alloc_debugcheck_after(cachep, flags, ptr, + __builtin_return_address(0)); return ptr; } @@ -2957,7 +2995,7 @@ EXPORT_SYMBOL(__kmalloc); void *__alloc_percpu(size_t size) { int i; - struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL); + struct percpu_data *pdata = kmalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; @@ -2981,9 +3019,9 @@ void *__alloc_percpu(size_t size) } /* Catch derefs w/o wrappers */ - return (void *) (~(unsigned long) pdata); + return (void *)(~(unsigned long)pdata); -unwind_oom: + unwind_oom: while (--i >= 0) { if (!cpu_possible(i)) continue; @@ -3046,7 +3084,7 @@ void kfree(const void *objp) local_irq_save(flags); kfree_debugcheck(objp); c = page_get_cache(virt_to_page(objp)); - __cache_free(c, (void*)objp); + __cache_free(c, (void *)objp); local_irq_restore(flags); } EXPORT_SYMBOL(kfree); @@ -3059,17 +3097,16 @@ EXPORT_SYMBOL(kfree); * Don't free memory not originally allocated by alloc_percpu() * The complemented objp is to check for that. */ -void -free_percpu(const void *objp) +void free_percpu(const void *objp) { int i; - struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp); + struct percpu_data *p = (struct percpu_data *)(~(unsigned long)objp); /* * We allocate for all cpus so we cannot use for online cpu here. */ for_each_cpu(i) - kfree(p->ptrs[i]); + kfree(p->ptrs[i]); kfree(p); } EXPORT_SYMBOL(free_percpu); @@ -3103,44 +3140,44 @@ static int alloc_kmemlist(kmem_cache_t *cachep) if (!(new_alien = alloc_alien_cache(node, cachep->limit))) goto fail; #endif - if (!(new = alloc_arraycache(node, (cachep->shared* - cachep->batchcount), 0xbaadf00d))) + if (!(new = alloc_arraycache(node, (cachep->shared * + cachep->batchcount), + 0xbaadf00d))) goto fail; if ((l3 = cachep->nodelists[node])) { spin_lock_irq(&l3->list_lock); if ((nc = cachep->nodelists[node]->shared)) - free_block(cachep, nc->entry, - nc->avail, node); + free_block(cachep, nc->entry, nc->avail, node); l3->shared = new; if (!cachep->nodelists[node]->alien) { l3->alien = new_alien; new_alien = NULL; } - l3->free_limit = (1 + nr_cpus_node(node))* - cachep->batchcount + cachep->num; + l3->free_limit = (1 + nr_cpus_node(node)) * + cachep->batchcount + cachep->num; spin_unlock_irq(&l3->list_lock); kfree(nc); free_alien_cache(new_alien); continue; } if (!(l3 = kmalloc_node(sizeof(struct kmem_list3), - GFP_KERNEL, node))) + GFP_KERNEL, node))) goto fail; kmem_list3_init(l3); l3->next_reap = jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + ((unsigned long)cachep) % REAPTIMEOUT_LIST3; l3->shared = new; l3->alien = new_alien; - l3->free_limit = (1 + nr_cpus_node(node))* - cachep->batchcount + cachep->num; + l3->free_limit = (1 + nr_cpus_node(node)) * + cachep->batchcount + cachep->num; cachep->nodelists[node] = l3; } return err; -fail: + fail: err = -ENOMEM; return err; } @@ -3162,18 +3199,19 @@ static void do_ccupdate_local(void *info) new->new[smp_processor_id()] = old; } - static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount, - int shared) + int shared) { struct ccupdate_struct new; int i, err; - memset(&new.new,0,sizeof(new.new)); + memset(&new.new, 0, sizeof(new.new)); for_each_online_cpu(i) { - new.new[i] = alloc_arraycache(cpu_to_node(i), limit, batchcount); + new.new[i] = + alloc_arraycache(cpu_to_node(i), limit, batchcount); if (!new.new[i]) { - for (i--; i >= 0; i--) kfree(new.new[i]); + for (i--; i >= 0; i--) + kfree(new.new[i]); return -ENOMEM; } } @@ -3201,13 +3239,12 @@ static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount, err = alloc_kmemlist(cachep); if (err) { printk(KERN_ERR "alloc_kmemlist failed for %s, error %d.\n", - cachep->name, -err); + cachep->name, -err); BUG(); } return 0; } - static void enable_cpucache(kmem_cache_t *cachep) { int err; @@ -3254,14 +3291,14 @@ static void enable_cpucache(kmem_cache_t *cachep) if (limit > 32) limit = 32; #endif - err = do_tune_cpucache(cachep, limit, (limit+1)/2, shared); + err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared); if (err) printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n", - cachep->name, -err); + cachep->name, -err); } -static void drain_array_locked(kmem_cache_t *cachep, - struct array_cache *ac, int force, int node) +static void drain_array_locked(kmem_cache_t *cachep, struct array_cache *ac, + int force, int node) { int tofree; @@ -3269,14 +3306,14 @@ static void drain_array_locked(kmem_cache_t *cachep, if (ac->touched && !force) { ac->touched = 0; } else if (ac->avail) { - tofree = force ? ac->avail : (ac->limit+4)/5; + tofree = force ? ac->avail : (ac->limit + 4) / 5; if (tofree > ac->avail) { - tofree = (ac->avail+1)/2; + tofree = (ac->avail + 1) / 2; } free_block(cachep, ac->entry, tofree, node); ac->avail -= tofree; memmove(ac->entry, &(ac->entry[tofree]), - sizeof(void*)*ac->avail); + sizeof(void *) * ac->avail); } } @@ -3299,13 +3336,14 @@ static void cache_reap(void *unused) if (down_trylock(&cache_chain_sem)) { /* Give up. Setup the next iteration. */ - schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC); + schedule_delayed_work(&__get_cpu_var(reap_work), + REAPTIMEOUT_CPUC); return; } list_for_each(walk, &cache_chain) { kmem_cache_t *searchp; - struct list_head* p; + struct list_head *p; int tofree; struct slab *slabp; @@ -3322,7 +3360,7 @@ static void cache_reap(void *unused) spin_lock_irq(&l3->list_lock); drain_array_locked(searchp, ac_data(searchp), 0, - numa_node_id()); + numa_node_id()); if (time_after(l3->next_reap, jiffies)) goto next_unlock; @@ -3331,14 +3369,16 @@ static void cache_reap(void *unused) if (l3->shared) drain_array_locked(searchp, l3->shared, 0, - numa_node_id()); + numa_node_id()); if (l3->free_touched) { l3->free_touched = 0; goto next_unlock; } - tofree = (l3->free_limit+5*searchp->num-1)/(5*searchp->num); + tofree = + (l3->free_limit + 5 * searchp->num - + 1) / (5 * searchp->num); do { p = l3->slabs_free.next; if (p == &(l3->slabs_free)) @@ -3358,10 +3398,10 @@ static void cache_reap(void *unused) spin_unlock_irq(&l3->list_lock); slab_destroy(searchp, slabp); spin_lock_irq(&l3->list_lock); - } while(--tofree > 0); -next_unlock: + } while (--tofree > 0); + next_unlock: spin_unlock_irq(&l3->list_lock); -next: + next: cond_resched(); } check_irq_on(); @@ -3418,7 +3458,7 @@ static void *s_next(struct seq_file *m, void *p, loff_t *pos) kmem_cache_t *cachep = p; ++*pos; return cachep->next.next == &cache_chain ? NULL - : list_entry(cachep->next.next, kmem_cache_t, next); + : list_entry(cachep->next.next, kmem_cache_t, next); } static void s_stop(struct seq_file *m, void *p) @@ -3430,11 +3470,11 @@ static int s_show(struct seq_file *m, void *p) { kmem_cache_t *cachep = p; struct list_head *q; - struct slab *slabp; - unsigned long active_objs; - unsigned long num_objs; - unsigned long active_slabs = 0; - unsigned long num_slabs, free_objects = 0, shared_avail = 0; + struct slab *slabp; + unsigned long active_objs; + unsigned long num_objs; + unsigned long active_slabs = 0; + unsigned long num_slabs, free_objects = 0, shared_avail = 0; const char *name; char *error = NULL; int node; @@ -3451,14 +3491,14 @@ static int s_show(struct seq_file *m, void *p) spin_lock(&l3->list_lock); - list_for_each(q,&l3->slabs_full) { + list_for_each(q, &l3->slabs_full) { slabp = list_entry(q, struct slab, list); if (slabp->inuse != cachep->num && !error) error = "slabs_full accounting error"; active_objs += cachep->num; active_slabs++; } - list_for_each(q,&l3->slabs_partial) { + list_for_each(q, &l3->slabs_partial) { slabp = list_entry(q, struct slab, list); if (slabp->inuse == cachep->num && !error) error = "slabs_partial inuse accounting error"; @@ -3467,7 +3507,7 @@ static int s_show(struct seq_file *m, void *p) active_objs += slabp->inuse; active_slabs++; } - list_for_each(q,&l3->slabs_free) { + list_for_each(q, &l3->slabs_free) { slabp = list_entry(q, struct slab, list); if (slabp->inuse && !error) error = "slabs_free/inuse accounting error"; @@ -3478,25 +3518,24 @@ static int s_show(struct seq_file *m, void *p) spin_unlock(&l3->list_lock); } - num_slabs+=active_slabs; - num_objs = num_slabs*cachep->num; + num_slabs += active_slabs; + num_objs = num_slabs * cachep->num; if (num_objs - active_objs != free_objects && !error) error = "free_objects accounting error"; - name = cachep->name; + name = cachep->name; if (error) printk(KERN_ERR "slab: cache %s error: %s\n", name, error); seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", - name, active_objs, num_objs, cachep->objsize, - cachep->num, (1<gfporder)); + name, active_objs, num_objs, cachep->objsize, + cachep->num, (1 << cachep->gfporder)); seq_printf(m, " : tunables %4u %4u %4u", - cachep->limit, cachep->batchcount, - cachep->shared); + cachep->limit, cachep->batchcount, cachep->shared); seq_printf(m, " : slabdata %6lu %6lu %6lu", - active_slabs, num_slabs, shared_avail); + active_slabs, num_slabs, shared_avail); #if STATS - { /* list3 stats */ + { /* list3 stats */ unsigned long high = cachep->high_mark; unsigned long allocs = cachep->num_allocations; unsigned long grown = cachep->grown; @@ -3507,9 +3546,7 @@ static int s_show(struct seq_file *m, void *p) unsigned long node_frees = cachep->node_frees; seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu \ - %4lu %4lu %4lu %4lu", - allocs, high, grown, reaped, errors, - max_freeable, node_allocs, node_frees); + %4lu %4lu %4lu %4lu", allocs, high, grown, reaped, errors, max_freeable, node_allocs, node_frees); } /* cpu stats */ { @@ -3519,7 +3556,7 @@ static int s_show(struct seq_file *m, void *p) unsigned long freemiss = atomic_read(&cachep->freemiss); seq_printf(m, " : cpustat %6lu %6lu %6lu %6lu", - allochit, allocmiss, freehit, freemiss); + allochit, allocmiss, freehit, freemiss); } #endif seq_putc(m, '\n'); @@ -3542,10 +3579,10 @@ static int s_show(struct seq_file *m, void *p) */ struct seq_operations slabinfo_op = { - .start = s_start, - .next = s_next, - .stop = s_stop, - .show = s_show, + .start = s_start, + .next = s_next, + .stop = s_stop, + .show = s_show, }; #define MAX_SLABINFO_WRITE 128 @@ -3556,18 +3593,18 @@ struct seq_operations slabinfo_op = { * @count: data length * @ppos: unused */ -ssize_t slabinfo_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) +ssize_t slabinfo_write(struct file *file, const char __user * buffer, + size_t count, loff_t *ppos) { - char kbuf[MAX_SLABINFO_WRITE+1], *tmp; + char kbuf[MAX_SLABINFO_WRITE + 1], *tmp; int limit, batchcount, shared, res; struct list_head *p; - + if (count > MAX_SLABINFO_WRITE) return -EINVAL; if (copy_from_user(&kbuf, buffer, count)) return -EFAULT; - kbuf[MAX_SLABINFO_WRITE] = '\0'; + kbuf[MAX_SLABINFO_WRITE] = '\0'; tmp = strchr(kbuf, ' '); if (!tmp) @@ -3580,18 +3617,17 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer, /* Find the cache in the chain of caches. */ down(&cache_chain_sem); res = -EINVAL; - list_for_each(p,&cache_chain) { + list_for_each(p, &cache_chain) { kmem_cache_t *cachep = list_entry(p, kmem_cache_t, next); if (!strcmp(cachep->name, kbuf)) { if (limit < 1 || batchcount < 1 || - batchcount > limit || - shared < 0) { + batchcount > limit || shared < 0) { res = 0; } else { res = do_tune_cpucache(cachep, limit, - batchcount, shared); + batchcount, shared); } break; } -- cgit v1.2.3 From bec6b0c89b234090681a4516e20ac5debe3e7c59 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:38 -0800 Subject: [PATCH] slab: remove nested #ifdef CONFIG_NUMA For some reason there is an #ifdef CONFIG_NUMA within another #ifdef CONFIG_NUMA in the page allocator. Remove innermost #ifdef CONFIG_NUMA Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0b98f428b07b..5eeeadd9f66a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1883,7 +1883,6 @@ bad: static inline void free_zone_pagesets(int cpu) { -#ifdef CONFIG_NUMA struct zone *zone; for_each_zone(zone) { @@ -1892,7 +1891,6 @@ static inline void free_zone_pagesets(int cpu) zone_pcp(zone, cpu) = NULL; kfree(pset); } -#endif } static int __devinit pageset_cpuup_callback(struct notifier_block *nfb, -- cgit v1.2.3 From 9d0243bca345d5ce25d3f4b74b7facb3a6df1232 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:00:39 -0800 Subject: [PATCH] drop-pagecache Add /proc/sys/vm/drop_caches. When written to, this will cause the kernel to discard as much pagecache and/or reclaimable slab objects as it can. THis operation requires root permissions. It won't drop dirty data, so the user should run `sync' first. Caveats: a) Holds inode_lock for exorbitant amounts of time. b) Needs to be taught about NUMA nodes: propagate these all the way through so the discarding can be controlled on a per-node basis. This is a debugging feature: useful for getting consistent results between filesystem benchmarks. We could possibly put it under a config option, but it's less than 300 bytes. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/proc.txt | 17 ++++++++++ Documentation/sysctl/vm.txt | 3 +- fs/Makefile | 2 +- fs/drop_caches.c | 68 ++++++++++++++++++++++++++++++++++++++ include/linux/mm.h | 7 ++++ include/linux/sysctl.h | 1 + kernel/sysctl.c | 10 ++++++ mm/truncate.c | 1 - mm/vmscan.c | 3 +- 9 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 fs/drop_caches.c diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index d4773565ea2f..a4dcf42c2fd9 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1302,6 +1302,23 @@ VM has token based thrashing control mechanism and uses the token to prevent unnecessary page faults in thrashing situation. The unit of the value is second. The value would be useful to tune thrashing behavior. +drop_caches +----------- + +Writing to this will cause the kernel to drop clean caches, dentries and +inodes from memory, causing that memory to become free. + +To free pagecache: + echo 1 > /proc/sys/vm/drop_caches +To free dentries and inodes: + echo 2 > /proc/sys/vm/drop_caches +To free pagecache, dentries and inodes: + echo 3 > /proc/sys/vm/drop_caches + +As this is a non-destructive operation and dirty objects are not freeable, the +user should run `sync' first. + + 2.5 /proc/sys/dev - Device specific parameters ---------------------------------------------- diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 2f1aae32a5d9..89ba1a42a17d 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -26,12 +26,13 @@ Currently, these files are in /proc/sys/vm: - min_free_kbytes - laptop_mode - block_dump +- drop-caches ============================================================== dirty_ratio, dirty_background_ratio, dirty_expire_centisecs, dirty_writeback_centisecs, vfs_cache_pressure, laptop_mode, -block_dump, swap_token_timeout: +block_dump, swap_token_timeout, drop-caches: See Documentation/filesystems/proc.txt diff --git a/fs/Makefile b/fs/Makefile index 73676111ebbe..35e9aec608e4 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -10,7 +10,7 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \ ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \ - ioprio.o pnode.o + ioprio.o pnode.o drop_caches.o obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_EPOLL) += eventpoll.o diff --git a/fs/drop_caches.c b/fs/drop_caches.c new file mode 100644 index 000000000000..4e4762389bdc --- /dev/null +++ b/fs/drop_caches.c @@ -0,0 +1,68 @@ +/* + * Implement the manual drop-all-pagecache function + */ + +#include +#include +#include +#include +#include +#include + +/* A global variable is a bit ugly, but it keeps the code simple */ +int sysctl_drop_caches; + +static void drop_pagecache_sb(struct super_block *sb) +{ + struct inode *inode; + + spin_lock(&inode_lock); + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + if (inode->i_state & (I_FREEING|I_WILL_FREE)) + continue; + invalidate_inode_pages(inode->i_mapping); + } + spin_unlock(&inode_lock); +} + +void drop_pagecache(void) +{ + struct super_block *sb; + + spin_lock(&sb_lock); +restart: + list_for_each_entry(sb, &super_blocks, s_list) { + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + if (sb->s_root) + drop_pagecache_sb(sb); + up_read(&sb->s_umount); + spin_lock(&sb_lock); + if (__put_super_and_need_restart(sb)) + goto restart; + } + spin_unlock(&sb_lock); +} + +void drop_slab(void) +{ + int nr_objects; + + do { + nr_objects = shrink_slab(1000, GFP_KERNEL, 1000); + } while (nr_objects > 10); +} + +int drop_caches_sysctl_handler(ctl_table *table, int write, + struct file *file, void __user *buffer, size_t *length, loff_t *ppos) +{ + proc_dointvec_minmax(table, write, file, buffer, length, ppos); + if (write) { + if (sysctl_drop_caches & 1) + drop_pagecache(); + if (sysctl_drop_caches & 2) + drop_slab(); + } + return 0; +} diff --git a/include/linux/mm.h b/include/linux/mm.h index bc01fff3aa01..83c651f25188 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1036,5 +1036,12 @@ int in_gate_area_no_task(unsigned long addr); /* /proc//oom_adj set to -17 protects from the oom-killer */ #define OOM_DISABLE -17 +int drop_caches_sysctl_handler(struct ctl_table *, int, struct file *, + void __user *, size_t *, loff_t *); +int shrink_slab(unsigned long scanned, gfp_t gfp_mask, + unsigned long lru_pages); +void drop_pagecache(void); +void drop_slab(void); + #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index a9b80fc7f0f3..4cd267fe87ec 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -180,6 +180,7 @@ enum VM_VFS_CACHE_PRESSURE=26, /* dcache/icache reclaim pressure */ VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */ VM_SWAP_TOKEN_TIMEOUT=28, /* default time for token time out */ + VM_DROP_PAGECACHE=29, /* int: nuke lots of pagecache */ }; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a85047bb5739..8dcf6fd5b0f9 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -68,6 +68,7 @@ extern int min_free_kbytes; extern int printk_ratelimit_jiffies; extern int printk_ratelimit_burst; extern int pid_max_min, pid_max_max; +extern int sysctl_drop_caches; #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) int unknown_nmi_panic; @@ -774,6 +775,15 @@ static ctl_table vm_table[] = { .proc_handler = &lowmem_reserve_ratio_sysctl_handler, .strategy = &sysctl_intvec, }, + { + .ctl_name = VM_DROP_PAGECACHE, + .procname = "drop_caches", + .data = &sysctl_drop_caches, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = drop_caches_sysctl_handler, + .strategy = &sysctl_intvec, + }, { .ctl_name = VM_MIN_FREE_KBYTES, .procname = "min_free_kbytes", diff --git a/mm/truncate.c b/mm/truncate.c index 7dee32745901..b1a463d0fe71 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -249,7 +249,6 @@ unlock: break; } pagevec_release(&pvec); - cond_resched(); } return ret; } diff --git a/mm/vmscan.c b/mm/vmscan.c index be8235fb1939..428c5801d4b4 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -180,8 +180,7 @@ EXPORT_SYMBOL(remove_shrinker); * * Returns the number of slab objects which we shrunk. */ -static int shrink_slab(unsigned long scanned, gfp_t gfp_mask, - unsigned long lru_pages) +int shrink_slab(unsigned long scanned, gfp_t gfp_mask, unsigned long lru_pages) { struct shrinker *shrinker; int ret = 0; -- cgit v1.2.3 From 8ad4b1fb8205340dba16b63467bb23efc27264d6 Mon Sep 17 00:00:00 2001 From: Rohit Seth Date: Sun, 8 Jan 2006 01:00:40 -0800 Subject: [PATCH] Make high and batch sizes of per_cpu_pagelists configurable As recently there has been lot of traffic on the right values for batch and high water marks for per_cpu_pagelists. This patch makes these two variables configurable through /proc interface. A new tunable /proc/sys/vm/percpu_pagelist_fraction is added. This entry controls the fraction of pages at most in each zone that are allocated for each per cpu page list. The min value for this is 8. It means that we don't allow more than 1/8th of pages in each zone to be allocated in any single per_cpu_pagelist. The batch value of each per cpu pagelist is also updated as a result. It is set to pcp->high/4. The upper limit of batch is (PAGE_SHIFT * 8) Signed-off-by: Rohit Seth Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/vm.txt | 17 ++++++++++++++++ include/linux/mmzone.h | 2 ++ include/linux/sysctl.h | 1 + kernel/sysctl.c | 12 +++++++++++ mm/page_alloc.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+) diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 89ba1a42a17d..6910c0136f8d 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -103,3 +103,20 @@ This is used to force the Linux VM to keep a minimum number of kilobytes free. The VM uses this number to compute a pages_min value for each lowmem zone in the system. Each lowmem zone gets a number of reserved free pages based proportionally on its size. + +============================================================== + +percpu_pagelist_fraction + +This is the fraction of pages at most (high mark pcp->high) in each zone that +are allocated for each per cpu page list. The min value for this is 8. It +means that we don't allow more than 1/8th of pages in each zone to be +allocated in any single per_cpu_pagelist. This entry only changes the value +of hot per cpu pagelists. User can specify a number like 100 to allocate +1/100th of each zone to each per cpu page list. + +The batch value of each per cpu pagelist is also updated as a result. It is +set to pcp->high/4. The upper limit of batch is (PAGE_SHIFT * 8) + +The initial value is zero. Kernel does not use this value at boot time to set +the high water marks for each per cpu page list. diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index c34f4a2c62f8..2a89c132ba9c 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -437,6 +437,8 @@ int min_free_kbytes_sysctl_handler(struct ctl_table *, int, struct file *, extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1]; int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); +int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *, int, struct file *, + void __user *, size_t *, loff_t *); #include /* Returns the number of the current Node. */ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 4cd267fe87ec..7f472127b7b5 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -181,6 +181,7 @@ enum VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */ VM_SWAP_TOKEN_TIMEOUT=28, /* default time for token time out */ VM_DROP_PAGECACHE=29, /* int: nuke lots of pagecache */ + VM_PERCPU_PAGELIST_FRACTION=30,/* int: fraction of pages in each percpu_pagelist */ }; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8dcf6fd5b0f9..03b0598f2369 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -69,6 +69,7 @@ extern int printk_ratelimit_jiffies; extern int printk_ratelimit_burst; extern int pid_max_min, pid_max_max; extern int sysctl_drop_caches; +extern int percpu_pagelist_fraction; #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) int unknown_nmi_panic; @@ -79,6 +80,7 @@ extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *, /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; static int minolduid; +static int min_percpu_pagelist_fract = 8; static int ngroups_max = NGROUPS_MAX; @@ -794,6 +796,16 @@ static ctl_table vm_table[] = { .strategy = &sysctl_intvec, .extra1 = &zero, }, + { + .ctl_name = VM_PERCPU_PAGELIST_FRACTION, + .procname = "percpu_pagelist_fraction", + .data = &percpu_pagelist_fraction, + .maxlen = sizeof(percpu_pagelist_fraction), + .mode = 0644, + .proc_handler = &percpu_pagelist_fraction_sysctl_handler, + .strategy = &sysctl_intvec, + .extra1 = &min_percpu_pagelist_fract, + }, #ifdef CONFIG_MMU { .ctl_name = VM_MAX_MAP_COUNT, diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5eeeadd9f66a..2c46f697e8ff 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -53,6 +53,7 @@ struct pglist_data *pgdat_list __read_mostly; unsigned long totalram_pages __read_mostly; unsigned long totalhigh_pages __read_mostly; long nr_swap_pages; +int percpu_pagelist_fraction; static void fastcall free_hot_cold_page(struct page *page, int cold); @@ -1831,6 +1832,24 @@ inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch) INIT_LIST_HEAD(&pcp->list); } +/* + * setup_pagelist_highmark() sets the high water mark for hot per_cpu_pagelist + * to the value high for the pageset p. + */ + +static void setup_pagelist_highmark(struct per_cpu_pageset *p, + unsigned long high) +{ + struct per_cpu_pages *pcp; + + pcp = &p->pcp[0]; /* hot list */ + pcp->high = high; + pcp->batch = max(1UL, high/4); + if ((high/4) > (PAGE_SHIFT * 8)) + pcp->batch = PAGE_SHIFT * 8; +} + + #ifdef CONFIG_NUMA /* * Boot pageset table. One per cpu which is going to be used for all @@ -1868,6 +1887,10 @@ static int __devinit process_zones(int cpu) goto bad; setup_pageset(zone->pageset[cpu], zone_batchsize(zone)); + + if (percpu_pagelist_fraction) + setup_pagelist_highmark(zone_pcp(zone, cpu), + (zone->present_pages / percpu_pagelist_fraction)); } return 0; @@ -2567,6 +2590,32 @@ int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write, return 0; } +/* + * percpu_pagelist_fraction - changes the pcp->high for each zone on each + * cpu. It is the fraction of total pages in each zone that a hot per cpu pagelist + * can have before it gets flushed back to buddy allocator. + */ + +int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write, + struct file *file, void __user *buffer, size_t *length, loff_t *ppos) +{ + struct zone *zone; + unsigned int cpu; + int ret; + + ret = proc_dointvec_minmax(table, write, file, buffer, length, ppos); + if (!write || (ret == -EINVAL)) + return ret; + for_each_zone(zone) { + for_each_online_cpu(cpu) { + unsigned long high; + high = zone->present_pages / percpu_pagelist_fraction; + setup_pagelist_highmark(zone_pcp(zone, cpu), high); + } + } + return 0; +} + __initdata int hashdist = HASHDIST_DEFAULT; #ifdef CONFIG_NUMA -- cgit v1.2.3 From 23316bc86fd31c5d644a71c398ec41d9fecacec4 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:00:41 -0800 Subject: [PATCH] mm: cleanup zone_pcp Use zone_pcp everywhere even though NUMA code "knows" the internal details of the zone. Stop other people trying to copy, and it looks nicer. Also, only print the pagesets of online cpus in zoneinfo. Signed-off-by: Nick Piggin Cc: "Seth, Rohit" Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2c46f697e8ff..6b92a945ae6b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -597,7 +597,7 @@ void drain_remote_pages(void) if (zone->zone_pgdat->node_id == numa_node_id()) continue; - pset = zone->pageset[smp_processor_id()]; + pset = zone_pcp(zone, smp_processor_id()); for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { struct per_cpu_pages *pcp; @@ -1881,12 +1881,12 @@ static int __devinit process_zones(int cpu) for_each_zone(zone) { - zone->pageset[cpu] = kmalloc_node(sizeof(struct per_cpu_pageset), + zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset), GFP_KERNEL, cpu_to_node(cpu)); - if (!zone->pageset[cpu]) + if (!zone_pcp(zone, cpu)) goto bad; - setup_pageset(zone->pageset[cpu], zone_batchsize(zone)); + setup_pageset(zone_pcp(zone, cpu), zone_batchsize(zone)); if (percpu_pagelist_fraction) setup_pagelist_highmark(zone_pcp(zone, cpu), @@ -1898,8 +1898,8 @@ bad: for_each_zone(dzone) { if (dzone == zone) break; - kfree(dzone->pageset[cpu]); - dzone->pageset[cpu] = NULL; + kfree(zone_pcp(dzone, cpu)); + zone_pcp(dzone, cpu) = NULL; } return -ENOMEM; } @@ -1984,7 +1984,7 @@ static __devinit void zone_pcp_init(struct zone *zone) for (cpu = 0; cpu < NR_CPUS; cpu++) { #ifdef CONFIG_NUMA /* Early boot. Slab allocator not functional yet */ - zone->pageset[cpu] = &boot_pageset[cpu]; + zone_pcp(zone, cpu) = &boot_pageset[cpu]; setup_pageset(&boot_pageset[cpu],0); #else setup_pageset(zone_pcp(zone,cpu), batch); @@ -2227,7 +2227,7 @@ static int zoneinfo_show(struct seq_file *m, void *arg) seq_printf(m, ")" "\n pagesets"); - for (i = 0; i < ARRAY_SIZE(zone->pageset); i++) { + for_each_online_cpu(i) { struct per_cpu_pageset *pageset; int j; -- cgit v1.2.3 From 48db57f8ff10eb09ab887ccb6150b0da0c7be24e Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:00:42 -0800 Subject: [PATCH] mm: free_pages opt Try to streamline free_pages_bulk by ensuring callers don't pass in a 'count' that exceeds the list size. Some cleanups: Rename __free_pages_bulk to __free_one_page. Put the page list manipulation from __free_pages_ok into free_one_page. Make __free_pages_ok static. Signed-off-by: Nick Piggin Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 58 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6b92a945ae6b..ad3d0202cdef 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -308,7 +308,7 @@ static inline int page_is_buddy(struct page *page, int order) * -- wli */ -static inline void __free_pages_bulk (struct page *page, +static inline void __free_one_page(struct page *page, struct zone *zone, unsigned int order) { unsigned long page_idx; @@ -383,40 +383,42 @@ static inline int free_pages_check(struct page *page) * And clear the zone's pages_scanned counter, to hold off the "all pages are * pinned" detection logic. */ -static int -free_pages_bulk(struct zone *zone, int count, - struct list_head *list, unsigned int order) +static void free_pages_bulk(struct zone *zone, int count, + struct list_head *list, int order) { - struct page *page = NULL; - int ret = 0; - spin_lock(&zone->lock); zone->all_unreclaimable = 0; zone->pages_scanned = 0; - while (!list_empty(list) && count--) { + while (count--) { + struct page *page; + + BUG_ON(list_empty(list)); page = list_entry(list->prev, struct page, lru); - /* have to delete it as __free_pages_bulk list manipulates */ + /* have to delete it as __free_one_page list manipulates */ list_del(&page->lru); - __free_pages_bulk(page, zone, order); - ret++; + __free_one_page(page, zone, order); } spin_unlock(&zone->lock); - return ret; } -void __free_pages_ok(struct page *page, unsigned int order) +static void free_one_page(struct zone *zone, struct page *page, int order) { - unsigned long flags; LIST_HEAD(list); + list_add(&page->lru, &list); + free_pages_bulk(zone, 1, &list, order); +} + +static void __free_pages_ok(struct page *page, unsigned int order) +{ + unsigned long flags; int i; int reserved = 0; arch_free_page(page, order); #ifndef CONFIG_MMU - if (order > 0) - for (i = 1 ; i < (1 << order) ; ++i) - __put_page(page + i); + for (i = 1 ; i < (1 << order) ; ++i) + __put_page(page + i); #endif for (i = 0 ; i < (1 << order) ; ++i) @@ -424,11 +426,10 @@ void __free_pages_ok(struct page *page, unsigned int order) if (reserved) return; - list_add(&page->lru, &list); - kernel_map_pages(page, 1<pcp[i]; - if (pcp->count) - pcp->count -= free_pages_bulk(zone, pcp->count, - &pcp->list, 0); + free_pages_bulk(zone, pcp->count, &pcp->list, 0); + pcp->count = 0; } } local_irq_restore(flags); @@ -627,8 +627,8 @@ static void __drain_pages(unsigned int cpu) pcp = &pset->pcp[i]; local_irq_save(flags); - pcp->count -= free_pages_bulk(zone, pcp->count, - &pcp->list, 0); + free_pages_bulk(zone, pcp->count, &pcp->list, 0); + pcp->count = 0; local_irq_restore(flags); } } @@ -719,8 +719,10 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) __inc_page_state(pgfree); list_add(&page->lru, &pcp->list); pcp->count++; - if (pcp->count >= pcp->high) - pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0); + if (pcp->count >= pcp->high) { + free_pages_bulk(zone, pcp->batch, &pcp->list, 0); + pcp->count -= pcp->batch; + } local_irq_restore(flags); put_cpu(); } @@ -759,7 +761,7 @@ static struct page *buffered_rmqueue(struct zonelist *zonelist, again: cpu = get_cpu(); - if (order == 0) { + if (likely(order == 0)) { struct per_cpu_pages *pcp; pcp = &zone_pcp(zone, cpu)->pcp[cold]; -- cgit v1.2.3 From 15316ba81aee6775d6079fb46c66c801989e7d10 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:43 -0800 Subject: [PATCH] add schedule_on_each_cpu() swap migration's isolate_lru_page() currently uses an IPI to notify other processors that the lru caches need to be drained if the page cannot be found on the LRU. The IPI interrupt may interrupt a processor that is just processing lru requests and cause a race condition. This patch introduces a new function run_on_each_cpu() that uses the keventd() to run the LRU draining on each processor. Processors disable preemption when dealing the LRU caches (these are per processor) and thus executing LRU draining from another process is safe. Thanks to Lee Schermerhorn for finding this race condition. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/workqueue.h | 1 + kernel/workqueue.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index ac39d04d027c..86b111300231 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -65,6 +65,7 @@ extern int FASTCALL(schedule_work(struct work_struct *work)); extern int FASTCALL(schedule_delayed_work(struct work_struct *work, unsigned long delay)); extern int schedule_delayed_work_on(int cpu, struct work_struct *work, unsigned long delay); +extern int schedule_on_each_cpu(void (*func)(void *info), void *info); extern void flush_scheduled_work(void); extern int current_is_keventd(void); extern int keventd_up(void); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2bd5aee1c736..62d47220696a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -419,6 +419,25 @@ int schedule_delayed_work_on(int cpu, return ret; } +int schedule_on_each_cpu(void (*func) (void *info), void *info) +{ + int cpu; + struct work_struct *work; + + work = kmalloc(NR_CPUS * sizeof(struct work_struct), GFP_KERNEL); + + if (!work) + return -ENOMEM; + for_each_online_cpu(cpu) { + INIT_WORK(work + cpu, func, info); + __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), + work + cpu); + } + flush_workqueue(keventd_wq); + kfree(work); + return 0; +} + void flush_scheduled_work(void) { flush_workqueue(keventd_wq); -- cgit v1.2.3 From 21eac81f252fe31c3cf64b805a1e8652192f3a3b Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:45 -0800 Subject: [PATCH] Swap Migration V5: LRU operations This is the start of the `swap migration' patch series. Swap migration allows the moving of the physical location of pages between nodes in a numa system while the process is running. This means that the virtual addresses that the process sees do not change. However, the system rearranges the physical location of those pages. The main intent of page migration patches here is to reduce the latency of memory access by moving pages near to the processor where the process accessing that memory is running. The patchset allows a process to manually relocate the node on which its pages are located through the MF_MOVE and MF_MOVE_ALL options while setting a new memory policy. The pages of process can also be relocated from another process using the sys_migrate_pages() function call. Requires CAP_SYS_ADMIN. The migrate_pages function call takes two sets of nodes and moves pages of a process that are located on the from nodes to the destination nodes. Manual migration is very useful if for example the scheduler has relocated a process to a processor on a distant node. A batch scheduler or an administrator can detect the situation and move the pages of the process nearer to the new processor. sys_migrate_pages() could be used on non-numa machines as well, to force all of a particualr process's pages out to swap, if someone thinks that's useful. Larger installations usually partition the system using cpusets into sections of nodes. Paul has equipped cpusets with the ability to move pages when a task is moved to another cpuset. This allows automatic control over locality of a process. If a task is moved to a new cpuset then also all its pages are moved with it so that the performance of the process does not sink dramatically (as is the case today). Swap migration works by simply evicting the page. The pages must be faulted back in. The pages are then typically reallocated by the system near the node where the process is executing. For swap migration the destination of the move is controlled by the allocation policy. Cpusets set the allocation policy before calling sys_migrate_pages() in order to move the pages as intended. No allocation policy changes are performed for sys_migrate_pages(). This means that the pages may not faulted in to the specified nodes if no allocation policy was set by other means. The pages will just end up near the node where the fault occurred. There's another patch series in the pipeline which implements "direct migration". The direct migration patchset extends the migration functionality to avoid going through swap. The destination node of the relation is controllable during the actual moving of pages. The crutch of using the allocation policy to relocate is not necessary and the pages are moved directly to the target. Its also faster since swap is not used. And sys_migrate_pages() can then move pages directly to the specified node. Implement functions to isolate pages from the LRU and put them back later. This patch: An earlier implementation was provided by Hirokazu Takahashi and IWAMOTO Toshihiro for the memory hotplug project. From: Magnus This breaks out isolate_lru_page() and putpack_lru_page(). Needed for swap migration. Signed-off-by: Magnus Damm Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm_inline.h | 22 ++++++++++ include/linux/swap.h | 3 ++ mm/vmscan.c | 100 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 112 insertions(+), 13 deletions(-) diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 47762ca695a5..49cc68af01f8 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -38,3 +38,25 @@ del_page_from_lru(struct zone *zone, struct page *page) zone->nr_inactive--; } } + +/* + * Isolate one page from the LRU lists. + * + * - zone->lru_lock must be held + */ +static inline int __isolate_lru_page(struct page *page) +{ + if (unlikely(!TestClearPageLRU(page))) + return 0; + + if (get_page_testone(page)) { + /* + * It is being freed elsewhere + */ + __put_page(page); + SetPageLRU(page); + return -ENOENT; + } + + return 1; +} diff --git a/include/linux/swap.h b/include/linux/swap.h index 556617bcf7ac..a49112536c02 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -175,6 +175,9 @@ extern int try_to_free_pages(struct zone **, gfp_t); extern int shrink_all_memory(int); extern int vm_swappiness; +extern int isolate_lru_page(struct page *p); +extern int putback_lru_pages(struct list_head *l); + #ifdef CONFIG_MMU /* linux/mm/shmem.c */ extern int shmem_unuse(swp_entry_t entry, struct page *page); diff --git a/mm/vmscan.c b/mm/vmscan.c index 428c5801d4b4..261a56ee11b6 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -593,20 +593,18 @@ static int isolate_lru_pages(int nr_to_scan, struct list_head *src, page = lru_to_page(src); prefetchw_prev_lru_page(page, src, flags); - if (!TestClearPageLRU(page)) - BUG(); - list_del(&page->lru); - if (get_page_testone(page)) { - /* - * It is being freed elsewhere - */ - __put_page(page); - SetPageLRU(page); - list_add(&page->lru, src); - continue; - } else { - list_add(&page->lru, dst); + switch (__isolate_lru_page(page)) { + case 1: + /* Succeeded to isolate page */ + list_move(&page->lru, dst); nr_taken++; + break; + case -ENOENT: + /* Not possible to isolate */ + list_move(&page->lru, src); + break; + default: + BUG(); } } @@ -614,6 +612,48 @@ static int isolate_lru_pages(int nr_to_scan, struct list_head *src, return nr_taken; } +static void lru_add_drain_per_cpu(void *dummy) +{ + lru_add_drain(); +} + +/* + * Isolate one page from the LRU lists and put it on the + * indicated list. Do necessary cache draining if the + * page is not on the LRU lists yet. + * + * Result: + * 0 = page not on LRU list + * 1 = page removed from LRU list and added to the specified list. + * -ENOENT = page is being freed elsewhere. + */ +int isolate_lru_page(struct page *page) +{ + int rc = 0; + struct zone *zone = page_zone(page); + +redo: + spin_lock_irq(&zone->lru_lock); + rc = __isolate_lru_page(page); + if (rc == 1) { + if (PageActive(page)) + del_page_from_active_list(zone, page); + else + del_page_from_inactive_list(zone, page); + } + spin_unlock_irq(&zone->lru_lock); + if (rc == 0) { + /* + * Maybe this page is still waiting for a cpu to drain it + * from one of the lru lists? + */ + rc = schedule_on_each_cpu(lru_add_drain_per_cpu, NULL); + if (rc == 0 && PageLRU(page)) + goto redo; + } + return rc; +} + /* * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed */ @@ -679,6 +719,40 @@ done: pagevec_release(&pvec); } +static inline void move_to_lru(struct page *page) +{ + list_del(&page->lru); + if (PageActive(page)) { + /* + * lru_cache_add_active checks that + * the PG_active bit is off. + */ + ClearPageActive(page); + lru_cache_add_active(page); + } else { + lru_cache_add(page); + } + put_page(page); +} + +/* + * Add isolated pages on the list back to the LRU + * + * returns the number of pages put back. + */ +int putback_lru_pages(struct list_head *l) +{ + struct page *page; + struct page *page2; + int count = 0; + + list_for_each_entry_safe(page, page2, l, lru) { + move_to_lru(page); + count++; + } + return count; +} + /* * This moves pages from the active list to the inactive list. * -- cgit v1.2.3 From 930d915252edda7042c944ed3c30194a2f9fe163 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:47 -0800 Subject: [PATCH] Swap Migration V5: PF_SWAPWRITE to allow writing to swap Add PF_SWAPWRITE to control a processes permission to write to swap. - Use PF_SWAPWRITE in may_write_to_queue() instead of checking for kswapd and pdflush - Set PF_SWAPWRITE flag for kswapd and pdflush Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 1 + mm/pdflush.c | 2 +- mm/vmscan.c | 6 ++---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 7da33619d5d0..a74662077d60 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -895,6 +895,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ #define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */ #define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */ +#define PF_SWAPWRITE 0x01000000 /* Allowed to write to swap */ /* * Only the _current_ task can read/write to tsk->flags, but other diff --git a/mm/pdflush.c b/mm/pdflush.c index 52822c98c489..c4b6d0afd736 100644 --- a/mm/pdflush.c +++ b/mm/pdflush.c @@ -90,7 +90,7 @@ struct pdflush_work { static int __pdflush(struct pdflush_work *my_work) { - current->flags |= PF_FLUSHER; + current->flags |= PF_FLUSHER | PF_SWAPWRITE; my_work->fn = NULL; my_work->who = current; INIT_LIST_HEAD(&my_work->list); diff --git a/mm/vmscan.c b/mm/vmscan.c index 261a56ee11b6..6c30a8c59795 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -268,9 +268,7 @@ static inline int is_page_cache_freeable(struct page *page) static int may_write_to_queue(struct backing_dev_info *bdi) { - if (current_is_kswapd()) - return 1; - if (current_is_pdflush()) /* This is unlikely, but why not... */ + if (current->flags & PF_SWAPWRITE) return 1; if (!bdi_write_congested(bdi)) return 1; @@ -1299,7 +1297,7 @@ static int kswapd(void *p) * us from recursively trying to free more memory as we're * trying to free the first piece of memory in the first place). */ - tsk->flags |= PF_MEMALLOC|PF_KSWAPD; + tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; order = 0; for ( ; ; ) { -- cgit v1.2.3 From 49d2e9cc4544369635cd6f4ef6d5bb0f757079a7 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:48 -0800 Subject: [PATCH] Swap Migration V5: migrate_pages() function This adds the basic page migration function with a minimal implementation that only allows the eviction of pages to swap space. Page eviction and migration may be useful to migrate pages, to suspend programs or for remapping single pages (useful for faulty pages or pages with soft ECC failures) The process is as follows: The function wanting to migrate pages must first build a list of pages to be migrated or evicted and take them off the lru lists via isolate_lru_page(). isolate_lru_page determines that a page is freeable based on the LRU bit set. Then the actual migration or swapout can happen by calling migrate_pages(). migrate_pages does its best to migrate or swapout the pages and does multiple passes over the list. Some pages may only be swappable if they are not dirty. migrate_pages may start writing out dirty pages in the initial passes over the pages. However, migrate_pages may not be able to migrate or evict all pages for a variety of reasons. The remaining pages may be returned to the LRU lists using putback_lru_pages(). Changelog V4->V5: - Use the lru caches to return pages to the LRU Changelog V3->V4: - Restructure code so that applying patches to support full migration does require minimal changes. Rename swapout_pages() to migrate_pages(). Changelog V2->V3: - Extract common code from shrink_list() and swapout_pages() Signed-off-by: Mike Kravetz Signed-off-by: Christoph Lameter Cc: "Michael Kerrisk" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 2 + mm/vmscan.c | 214 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 182 insertions(+), 34 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index a49112536c02..893096e67bdb 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -178,6 +178,8 @@ extern int vm_swappiness; extern int isolate_lru_page(struct page *p); extern int putback_lru_pages(struct list_head *l); +extern int migrate_pages(struct list_head *l, struct list_head *t); + #ifdef CONFIG_MMU /* linux/mm/shmem.c */ extern int shmem_unuse(swp_entry_t entry, struct page *page); diff --git a/mm/vmscan.c b/mm/vmscan.c index 6c30a8c59795..a537a7f16357 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -373,6 +373,43 @@ static pageout_t pageout(struct page *page, struct address_space *mapping) return PAGE_CLEAN; } +static int remove_mapping(struct address_space *mapping, struct page *page) +{ + if (!mapping) + return 0; /* truncate got there first */ + + write_lock_irq(&mapping->tree_lock); + + /* + * The non-racy check for busy page. It is critical to check + * PageDirty _after_ making sure that the page is freeable and + * not in use by anybody. (pagecache + us == 2) + */ + if (unlikely(page_count(page) != 2)) + goto cannot_free; + smp_rmb(); + if (unlikely(PageDirty(page))) + goto cannot_free; + + if (PageSwapCache(page)) { + swp_entry_t swap = { .val = page_private(page) }; + __delete_from_swap_cache(page); + write_unlock_irq(&mapping->tree_lock); + swap_free(swap); + __put_page(page); /* The pagecache ref */ + return 1; + } + + __remove_from_page_cache(page); + write_unlock_irq(&mapping->tree_lock); + __put_page(page); + return 1; + +cannot_free: + write_unlock_irq(&mapping->tree_lock); + return 0; +} + /* * shrink_list adds the number of reclaimed pages to sc->nr_reclaimed */ @@ -504,36 +541,8 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) goto free_it; } - if (!mapping) - goto keep_locked; /* truncate got there first */ - - write_lock_irq(&mapping->tree_lock); - - /* - * The non-racy check for busy page. It is critical to check - * PageDirty _after_ making sure that the page is freeable and - * not in use by anybody. (pagecache + us == 2) - */ - if (unlikely(page_count(page) != 2)) - goto cannot_free; - smp_rmb(); - if (unlikely(PageDirty(page))) - goto cannot_free; - -#ifdef CONFIG_SWAP - if (PageSwapCache(page)) { - swp_entry_t swap = { .val = page_private(page) }; - __delete_from_swap_cache(page); - write_unlock_irq(&mapping->tree_lock); - swap_free(swap); - __put_page(page); /* The pagecache ref */ - goto free_it; - } -#endif /* CONFIG_SWAP */ - - __remove_from_page_cache(page); - write_unlock_irq(&mapping->tree_lock); - __put_page(page); + if (!remove_mapping(mapping, page)) + goto keep_locked; free_it: unlock_page(page); @@ -542,10 +551,6 @@ free_it: __pagevec_release_nonlru(&freed_pvec); continue; -cannot_free: - write_unlock_irq(&mapping->tree_lock); - goto keep_locked; - activate_locked: SetPageActive(page); pgactivate++; @@ -563,6 +568,147 @@ keep: return reclaimed; } +/* + * swapout a single page + * page is locked upon entry, unlocked on exit + * + * return codes: + * 0 = complete + * 1 = retry + */ +static int swap_page(struct page *page) +{ + struct address_space *mapping = page_mapping(page); + + if (page_mapped(page) && mapping) + if (try_to_unmap(page) != SWAP_SUCCESS) + goto unlock_retry; + + if (PageDirty(page)) { + /* Page is dirty, try to write it out here */ + switch(pageout(page, mapping)) { + case PAGE_KEEP: + case PAGE_ACTIVATE: + goto unlock_retry; + + case PAGE_SUCCESS: + goto retry; + + case PAGE_CLEAN: + ; /* try to free the page below */ + } + } + + if (PagePrivate(page)) { + if (!try_to_release_page(page, GFP_KERNEL) || + (!mapping && page_count(page) == 1)) + goto unlock_retry; + } + + if (remove_mapping(mapping, page)) { + /* Success */ + unlock_page(page); + return 0; + } + +unlock_retry: + unlock_page(page); + +retry: + return 1; +} +/* + * migrate_pages + * + * Two lists are passed to this function. The first list + * contains the pages isolated from the LRU to be migrated. + * The second list contains new pages that the pages isolated + * can be moved to. If the second list is NULL then all + * pages are swapped out. + * + * The function returns after 10 attempts or if no pages + * are movable anymore because t has become empty + * or no retryable pages exist anymore. + * + * SIMPLIFIED VERSION: This implementation of migrate_pages + * is only swapping out pages and never touches the second + * list. The direct migration patchset + * extends this function to avoid the use of swap. + */ +int migrate_pages(struct list_head *l, struct list_head *t) +{ + int retry; + LIST_HEAD(failed); + int nr_failed = 0; + int pass = 0; + struct page *page; + struct page *page2; + int swapwrite = current->flags & PF_SWAPWRITE; + + if (!swapwrite) + current->flags |= PF_SWAPWRITE; + +redo: + retry = 0; + + list_for_each_entry_safe(page, page2, l, lru) { + cond_resched(); + + /* + * Skip locked pages during the first two passes to give the + * functions holding the lock time to release the page. Later we use + * lock_page to have a higher chance of acquiring the lock. + */ + if (pass > 2) + lock_page(page); + else + if (TestSetPageLocked(page)) + goto retry_later; + + /* + * Only wait on writeback if we have already done a pass where + * we we may have triggered writeouts for lots of pages. + */ + if (pass > 0) + wait_on_page_writeback(page); + else + if (PageWriteback(page)) { + unlock_page(page); + goto retry_later; + } + +#ifdef CONFIG_SWAP + if (PageAnon(page) && !PageSwapCache(page)) { + if (!add_to_swap(page)) { + unlock_page(page); + list_move(&page->lru, &failed); + nr_failed++; + continue; + } + } +#endif /* CONFIG_SWAP */ + + /* + * Page is properly locked and writeback is complete. + * Try to migrate the page. + */ + if (swap_page(page)) { +retry_later: + retry++; + } + } + if (retry && pass++ < 10) + goto redo; + + if (!swapwrite) + current->flags &= ~PF_SWAPWRITE; + + if (!list_empty(&failed)) + list_splice(&failed, l); + + return nr_failed + retry; +} + /* * zone->lru_lock is heavily contended. Some of the functions that * shrink the lists perform better by taking out a batch of pages -- cgit v1.2.3 From 7cbe34cf86c673503b177ff47cfa2c7030dabb50 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:49 -0800 Subject: [PATCH] Swap Migration V5: Add CONFIG_MIGRATION for page migration support Include page migration if the system is NUMA or having a memory model that allows distinct areas of memory (SPARSEMEM, DISCONTIGMEM). And: - Only include lru_add_drain_per_cpu if building for an SMP system. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 2 ++ mm/Kconfig | 7 +++++++ mm/vmscan.c | 20 +++++++++++--------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 893096e67bdb..117add066f00 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -178,7 +178,9 @@ extern int vm_swappiness; extern int isolate_lru_page(struct page *p); extern int putback_lru_pages(struct list_head *l); +#ifdef CONFIG_MIGRATION extern int migrate_pages(struct list_head *l, struct list_head *t); +#endif #ifdef CONFIG_MMU /* linux/mm/shmem.c */ diff --git a/mm/Kconfig b/mm/Kconfig index b3db11f137e0..a9cb80ae6409 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -132,3 +132,10 @@ config SPLIT_PTLOCK_CPUS default "4096" if ARM && !CPU_CACHE_VIPT default "4096" if PARISC && !PA20 default "4" + +# +# support for page migration +# +config MIGRATION + def_bool y if NUMA || SPARSEMEM || DISCONTIGMEM + depends on SWAP diff --git a/mm/vmscan.c b/mm/vmscan.c index a537a7f16357..58270aea669a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -568,6 +568,7 @@ keep: return reclaimed; } +#ifdef CONFIG_MIGRATION /* * swapout a single page * page is locked upon entry, unlocked on exit @@ -656,8 +657,9 @@ redo: /* * Skip locked pages during the first two passes to give the - * functions holding the lock time to release the page. Later we use - * lock_page to have a higher chance of acquiring the lock. + * functions holding the lock time to release the page. Later we + * use lock_page() to have a higher chance of acquiring the + * lock. */ if (pass > 2) lock_page(page); @@ -669,15 +671,15 @@ redo: * Only wait on writeback if we have already done a pass where * we we may have triggered writeouts for lots of pages. */ - if (pass > 0) + if (pass > 0) { wait_on_page_writeback(page); - else + } else { if (PageWriteback(page)) { unlock_page(page); goto retry_later; } + } -#ifdef CONFIG_SWAP if (PageAnon(page) && !PageSwapCache(page)) { if (!add_to_swap(page)) { unlock_page(page); @@ -686,16 +688,15 @@ redo: continue; } } -#endif /* CONFIG_SWAP */ /* * Page is properly locked and writeback is complete. * Try to migrate the page. */ - if (swap_page(page)) { + if (!swap_page(page)) + continue; retry_later: - retry++; - } + retry++; } if (retry && pass++ < 10) goto redo; @@ -708,6 +709,7 @@ retry_later: return nr_failed + retry; } +#endif /* * zone->lru_lock is heavily contended. Some of the functions that -- cgit v1.2.3 From dc9aa5b9d65fd11b1f5246b46ec610ee8b83c6dd Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:50 -0800 Subject: [PATCH] Swap Migration V5: MPOL_MF_MOVE interface Add page migration support via swap to the NUMA policy layer This patch adds page migration support to the NUMA policy layer. An additional flag MPOL_MF_MOVE is introduced for mbind. If MPOL_MF_MOVE is specified then pages that do not conform to the memory policy will be evicted from memory. When they get pages back in new pages will be allocated following the numa policy. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mempolicy.h | 3 + mm/mempolicy.c | 155 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 138 insertions(+), 20 deletions(-) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index ed00b278cb93..05443a766cb8 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -22,6 +22,9 @@ /* Flags for mbind */ #define MPOL_MF_STRICT (1<<0) /* Verify existing pages in the mapping */ +#define MPOL_MF_MOVE (1<<1) /* Move pages owned by this process to conform to mapping */ +#define MPOL_MF_MOVE_ALL (1<<2) /* Move every page to conform to mapping */ +#define MPOL_MF_INTERNAL (1<<3) /* Internal flags start here */ #ifdef __KERNEL__ diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 0f1d2b8a952b..9cc6d962831d 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -83,9 +83,14 @@ #include #include #include +#include + #include #include +/* Internal MPOL_MF_xxx flags */ +#define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0) /* Skip checks for continuous vmas */ + static kmem_cache_t *policy_cache; static kmem_cache_t *sn_cache; @@ -174,9 +179,59 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) return policy; } +/* Check if we are the only process mapping the page in question */ +static inline int single_mm_mapping(struct mm_struct *mm, + struct address_space *mapping) +{ + struct vm_area_struct *vma; + struct prio_tree_iter iter; + int rc = 1; + + spin_lock(&mapping->i_mmap_lock); + vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX) + if (mm != vma->vm_mm) { + rc = 0; + goto out; + } + list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list) + if (mm != vma->vm_mm) { + rc = 0; + goto out; + } +out: + spin_unlock(&mapping->i_mmap_lock); + return rc; +} + +/* + * Add a page to be migrated to the pagelist + */ +static void migrate_page_add(struct vm_area_struct *vma, + struct page *page, struct list_head *pagelist, unsigned long flags) +{ + /* + * Avoid migrating a page that is shared by others and not writable. + */ + if ((flags & MPOL_MF_MOVE_ALL) || !page->mapping || PageAnon(page) || + mapping_writably_mapped(page->mapping) || + single_mm_mapping(vma->vm_mm, page->mapping)) { + int rc = isolate_lru_page(page); + + if (rc == 1) + list_add(&page->lru, pagelist); + /* + * If the isolate attempt was not successful then we just + * encountered an unswappable page. Something must be wrong. + */ + WARN_ON(rc == 0); + } +} + /* Ensure all existing pages follow the policy. */ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, - unsigned long addr, unsigned long end, nodemask_t *nodes) + unsigned long addr, unsigned long end, + const nodemask_t *nodes, unsigned long flags, + struct list_head *pagelist) { pte_t *orig_pte; pte_t *pte; @@ -193,15 +248,21 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (!page) continue; nid = page_to_nid(page); - if (!node_isset(nid, *nodes)) - break; + if (!node_isset(nid, *nodes)) { + if (pagelist) + migrate_page_add(vma, page, pagelist, flags); + else + break; + } } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap_unlock(orig_pte, ptl); return addr != end; } static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, - unsigned long addr, unsigned long end, nodemask_t *nodes) + unsigned long addr, unsigned long end, + const nodemask_t *nodes, unsigned long flags, + struct list_head *pagelist) { pmd_t *pmd; unsigned long next; @@ -211,14 +272,17 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, next = pmd_addr_end(addr, end); if (pmd_none_or_clear_bad(pmd)) continue; - if (check_pte_range(vma, pmd, addr, next, nodes)) + if (check_pte_range(vma, pmd, addr, next, nodes, + flags, pagelist)) return -EIO; } while (pmd++, addr = next, addr != end); return 0; } static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, - unsigned long addr, unsigned long end, nodemask_t *nodes) + unsigned long addr, unsigned long end, + const nodemask_t *nodes, unsigned long flags, + struct list_head *pagelist) { pud_t *pud; unsigned long next; @@ -228,14 +292,17 @@ static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, next = pud_addr_end(addr, end); if (pud_none_or_clear_bad(pud)) continue; - if (check_pmd_range(vma, pud, addr, next, nodes)) + if (check_pmd_range(vma, pud, addr, next, nodes, + flags, pagelist)) return -EIO; } while (pud++, addr = next, addr != end); return 0; } static inline int check_pgd_range(struct vm_area_struct *vma, - unsigned long addr, unsigned long end, nodemask_t *nodes) + unsigned long addr, unsigned long end, + const nodemask_t *nodes, unsigned long flags, + struct list_head *pagelist) { pgd_t *pgd; unsigned long next; @@ -245,16 +312,31 @@ static inline int check_pgd_range(struct vm_area_struct *vma, next = pgd_addr_end(addr, end); if (pgd_none_or_clear_bad(pgd)) continue; - if (check_pud_range(vma, pgd, addr, next, nodes)) + if (check_pud_range(vma, pgd, addr, next, nodes, + flags, pagelist)) return -EIO; } while (pgd++, addr = next, addr != end); return 0; } -/* Step 1: check the range */ +/* Check if a vma is migratable */ +static inline int vma_migratable(struct vm_area_struct *vma) +{ + if (vma->vm_flags & ( + VM_LOCKED|VM_IO|VM_HUGETLB|VM_PFNMAP)) + return 0; + return 1; +} + +/* + * Check if all pages in a range are on a set of nodes. + * If pagelist != NULL then isolate pages from the LRU and + * put them on the pagelist. + */ static struct vm_area_struct * check_range(struct mm_struct *mm, unsigned long start, unsigned long end, - nodemask_t *nodes, unsigned long flags) + const nodemask_t *nodes, unsigned long flags, + struct list_head *pagelist) { int err; struct vm_area_struct *first, *vma, *prev; @@ -264,17 +346,24 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, return ERR_PTR(-EFAULT); prev = NULL; for (vma = first; vma && vma->vm_start < end; vma = vma->vm_next) { - if (!vma->vm_next && vma->vm_end < end) - return ERR_PTR(-EFAULT); - if (prev && prev->vm_end < vma->vm_start) - return ERR_PTR(-EFAULT); - if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) { + if (!(flags & MPOL_MF_DISCONTIG_OK)) { + if (!vma->vm_next && vma->vm_end < end) + return ERR_PTR(-EFAULT); + if (prev && prev->vm_end < vma->vm_start) + return ERR_PTR(-EFAULT); + } + if (!is_vm_hugetlb_page(vma) && + ((flags & MPOL_MF_STRICT) || + ((flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) && + vma_migratable(vma)))) { unsigned long endvma = vma->vm_end; + if (endvma > end) endvma = end; if (vma->vm_start > start) start = vma->vm_start; - err = check_pgd_range(vma, start, endvma, nodes); + err = check_pgd_range(vma, start, endvma, nodes, + flags, pagelist); if (err) { first = ERR_PTR(err); break; @@ -348,33 +437,59 @@ long do_mbind(unsigned long start, unsigned long len, struct mempolicy *new; unsigned long end; int err; + LIST_HEAD(pagelist); - if ((flags & ~(unsigned long)(MPOL_MF_STRICT)) || mode > MPOL_MAX) + if ((flags & ~(unsigned long)(MPOL_MF_STRICT|MPOL_MF_MOVE|MPOL_MF_MOVE_ALL)) + || mode > MPOL_MAX) return -EINVAL; + if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_RESOURCE)) + return -EPERM; + if (start & ~PAGE_MASK) return -EINVAL; + if (mode == MPOL_DEFAULT) flags &= ~MPOL_MF_STRICT; + len = (len + PAGE_SIZE - 1) & PAGE_MASK; end = start + len; + if (end < start) return -EINVAL; if (end == start) return 0; + if (mpol_check_policy(mode, nmask)) return -EINVAL; + new = mpol_new(mode, nmask); if (IS_ERR(new)) return PTR_ERR(new); + /* + * If we are using the default policy then operation + * on discontinuous address spaces is okay after all + */ + if (!new) + flags |= MPOL_MF_DISCONTIG_OK; + PDprintk("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len, mode,nodes_addr(nodes)[0]); down_write(&mm->mmap_sem); - vma = check_range(mm, start, end, nmask, flags); + vma = check_range(mm, start, end, nmask, flags, + (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ? &pagelist : NULL); err = PTR_ERR(vma); - if (!IS_ERR(vma)) + if (!IS_ERR(vma)) { err = mbind_range(vma, start, end, new); + if (!list_empty(&pagelist)) + migrate_pages(&pagelist, NULL); + if (!err && !list_empty(&pagelist) && (flags & MPOL_MF_STRICT)) + err = -EIO; + } + if (!list_empty(&pagelist)) + putback_lru_pages(&pagelist); + up_write(&mm->mmap_sem); mpol_free(new); return err; -- cgit v1.2.3 From 39743889aaf76725152f16aa90ca3c45f6d52da3 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:51 -0800 Subject: [PATCH] Swap Migration V5: sys_migrate_pages interface sys_migrate_pages implementation using swap based page migration This is the original API proposed by Ray Bryant in his posts during the first half of 2005 on linux-mm@kvack.org and linux-kernel@vger.kernel.org. The intent of sys_migrate is to migrate memory of a process. A process may have migrated to another node. Memory was allocated optimally for the prior context. sys_migrate_pages allows to shift the memory to the new node. sys_migrate_pages is also useful if the processes available memory nodes have changed through cpuset operations to manually move the processes memory. Paul Jackson is working on an automated mechanism that will allow an automatic migration if the cpuset of a process is changed. However, a user may decide to manually control the migration. This implementation is put into the policy layer since it uses concepts and functions that are also needed for mbind and friends. The patch also provides a do_migrate_pages function that may be useful for cpusets to automatically move memory. sys_migrate_pages does not modify policies in contrast to Ray's implementation. The current code here is based on the swap based page migration capability and thus is not able to preserve the physical layout relative to it containing nodeset (which may be a cpuset). When direct page migration becomes available then the implementation needs to be changed to do a isomorphic move of pages between different nodesets. The current implementation simply evicts all pages in source nodeset that are not in the target nodeset. Patch supports ia64, i386 and x86_64. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/syscall_table.S | 1 + arch/ia64/kernel/entry.S | 1 + arch/x86_64/ia32/ia32entry.S | 1 + include/asm-i386/unistd.h | 3 +- include/asm-ia64/unistd.h | 3 +- include/asm-x86_64/ia32_unistd.h | 3 +- include/asm-x86_64/unistd.h | 4 +- include/linux/mempolicy.h | 3 ++ include/linux/syscalls.h | 2 + kernel/sys_ni.c | 1 + mm/mempolicy.c | 94 +++++++++++++++++++++++++++++++++++++++- 11 files changed, 111 insertions(+), 5 deletions(-) diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index f7ba4acc20ec..6ff3e5243226 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -293,3 +293,4 @@ ENTRY(sys_call_table) .long sys_inotify_init .long sys_inotify_add_watch .long sys_inotify_rm_watch + .long sys_migrate_pages diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 0741b066b98f..7a6ffd613789 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1600,5 +1600,6 @@ sys_call_table: data8 sys_inotify_init data8 sys_inotify_add_watch data8 sys_inotify_rm_watch + data8 sys_migrate_pages // 1280 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index df0773c9bdbe..1f0ff5adc80e 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -643,6 +643,7 @@ ia32_sys_call_table: .quad sys_inotify_init .quad sys_inotify_add_watch .quad sys_inotify_rm_watch + .quad sys_migrate_pages ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 .quad ni_syscall diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index fe38b9a96233..481c3c0ea720 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -299,8 +299,9 @@ #define __NR_inotify_init 291 #define __NR_inotify_add_watch 292 #define __NR_inotify_rm_watch 293 +#define __NR_migrate_pages 294 -#define NR_syscalls 294 +#define NR_syscalls 295 /* * user-visible error numbers are in the range -1 - -128: see diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 2bf543493cb8..962f9bd1bdff 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -269,12 +269,13 @@ #define __NR_inotify_init 1277 #define __NR_inotify_add_watch 1278 #define __NR_inotify_rm_watch 1279 +#define __NR_migrate_pages 1280 #ifdef __KERNEL__ #include -#define NR_syscalls 256 /* length of syscall table */ +#define NR_syscalls 270 /* length of syscall table */ #define __ARCH_WANT_SYS_RT_SIGACTION diff --git a/include/asm-x86_64/ia32_unistd.h b/include/asm-x86_64/ia32_unistd.h index d5166ec3868d..e8843362a6cc 100644 --- a/include/asm-x86_64/ia32_unistd.h +++ b/include/asm-x86_64/ia32_unistd.h @@ -299,7 +299,8 @@ #define __NR_ia32_inotify_init 291 #define __NR_ia32_inotify_add_watch 292 #define __NR_ia32_inotify_rm_watch 293 +#define __NR_ia32_migrate_pages 294 -#define IA32_NR_syscalls 294 /* must be > than biggest syscall! */ +#define IA32_NR_syscalls 295 /* must be > than biggest syscall! */ #endif /* _ASM_X86_64_IA32_UNISTD_H_ */ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 2c42150bce0c..e6f896161c11 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -571,8 +571,10 @@ __SYSCALL(__NR_inotify_init, sys_inotify_init) __SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch) #define __NR_inotify_rm_watch 255 __SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch) +#define __NR_migrate_pages 256 +__SYSCALL(__NR_migrate_pages, sys_migrate_pages) -#define __NR_syscall_max __NR_inotify_rm_watch +#define __NR_syscall_max __NR_migrate_pages #ifndef __NO_STUBS /* user-visible error numbers are in the range -1 - -4095 */ diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 05443a766cb8..3e61e829681d 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -162,6 +162,9 @@ static inline void check_highest_zone(int k) policy_zone = k; } +int do_migrate_pages(struct mm_struct *mm, + const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags); + #else struct mempolicy {}; diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index c7007b1db91d..e910d1a481df 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -511,5 +511,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio); asmlinkage long sys_ioprio_get(int which, int who); asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, unsigned long maxnode); +asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, + const unsigned long __user *from, const unsigned long __user *to); #endif diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 1ab2370e2efa..7a8bc7f60d91 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -82,6 +82,7 @@ cond_syscall(compat_sys_socketcall); cond_syscall(sys_inotify_init); cond_syscall(sys_inotify_add_watch); cond_syscall(sys_inotify_rm_watch); +cond_syscall(sys_migrate_pages); /* arch-specific weak syscall entries */ cond_syscall(sys_pciconfig_read); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 9cc6d962831d..20d5ad39fa41 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -614,12 +614,42 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask, return err; } +/* + * For now migrate_pages simply swaps out the pages from nodes that are in + * the source set but not in the target set. In the future, we would + * want a function that moves pages between the two nodesets in such + * a way as to preserve the physical layout as much as possible. + * + * Returns the number of page that could not be moved. + */ +int do_migrate_pages(struct mm_struct *mm, + const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags) +{ + LIST_HEAD(pagelist); + int count = 0; + nodemask_t nodes; + + nodes_andnot(nodes, *from_nodes, *to_nodes); + nodes_complement(nodes, nodes); + + down_read(&mm->mmap_sem); + check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nodes, + flags | MPOL_MF_DISCONTIG_OK, &pagelist); + if (!list_empty(&pagelist)) { + migrate_pages(&pagelist, NULL); + if (!list_empty(&pagelist)) + count = putback_lru_pages(&pagelist); + } + up_read(&mm->mmap_sem); + return count; +} + /* * User space interface with variable sized bitmaps for nodelists. */ /* Copy a node mask from user space. */ -static int get_nodes(nodemask_t *nodes, unsigned long __user *nmask, +static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, unsigned long maxnode) { unsigned long k; @@ -708,6 +738,68 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, return do_set_mempolicy(mode, &nodes); } +/* Macro needed until Paul implements this function in kernel/cpusets.c */ +#define cpuset_mems_allowed(task) node_online_map + +asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, + const unsigned long __user *old_nodes, + const unsigned long __user *new_nodes) +{ + struct mm_struct *mm; + struct task_struct *task; + nodemask_t old; + nodemask_t new; + nodemask_t task_nodes; + int err; + + err = get_nodes(&old, old_nodes, maxnode); + if (err) + return err; + + err = get_nodes(&new, new_nodes, maxnode); + if (err) + return err; + + /* Find the mm_struct */ + read_lock(&tasklist_lock); + task = pid ? find_task_by_pid(pid) : current; + if (!task) { + read_unlock(&tasklist_lock); + return -ESRCH; + } + mm = get_task_mm(task); + read_unlock(&tasklist_lock); + + if (!mm) + return -EINVAL; + + /* + * Check if this process has the right to modify the specified + * process. The right exists if the process has administrative + * capabilities, superuser priviledges or the same + * userid as the target process. + */ + if ((current->euid != task->suid) && (current->euid != task->uid) && + (current->uid != task->suid) && (current->uid != task->uid) && + !capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + task_nodes = cpuset_mems_allowed(task); + /* Is the user allowed to access the target nodes? */ + if (!nodes_subset(new, task_nodes) && !capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + err = do_migrate_pages(mm, &old, &new, MPOL_MF_MOVE); +out: + mmput(mm); + return err; +} + + /* Retrieve NUMA policy */ asmlinkage long sys_get_mempolicy(int __user *policy, unsigned long __user *nmask, -- cgit v1.2.3 From 8419c3181086c86664e8246bc997afc2e4ffba4f Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:52 -0800 Subject: [PATCH] SwapMig: CONFIG_MIGRATION fixes Move move_to_lru, putback_lru_pages and isolate_lru in section surrounded by CONFIG_MIGRATION saving some codesize for single processor kernels. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 3 +- mm/vmscan.c | 152 +++++++++++++++++++++++++-------------------------- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 117add066f00..997d838f0e70 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -175,10 +175,9 @@ extern int try_to_free_pages(struct zone **, gfp_t); extern int shrink_all_memory(int); extern int vm_swappiness; +#ifdef CONFIG_MIGRATION extern int isolate_lru_page(struct page *p); extern int putback_lru_pages(struct list_head *l); - -#ifdef CONFIG_MIGRATION extern int migrate_pages(struct list_head *l, struct list_head *t); #endif diff --git a/mm/vmscan.c b/mm/vmscan.c index 58270aea669a..daed4a73b761 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -569,6 +569,40 @@ keep: } #ifdef CONFIG_MIGRATION +static inline void move_to_lru(struct page *page) +{ + list_del(&page->lru); + if (PageActive(page)) { + /* + * lru_cache_add_active checks that + * the PG_active bit is off. + */ + ClearPageActive(page); + lru_cache_add_active(page); + } else { + lru_cache_add(page); + } + put_page(page); +} + +/* + * Add isolated pages on the list back to the LRU + * + * returns the number of pages put back. + */ +int putback_lru_pages(struct list_head *l) +{ + struct page *page; + struct page *page2; + int count = 0; + + list_for_each_entry_safe(page, page2, l, lru) { + move_to_lru(page); + count++; + } + return count; +} + /* * swapout a single page * page is locked upon entry, unlocked on exit @@ -709,6 +743,48 @@ retry_later: return nr_failed + retry; } + +static void lru_add_drain_per_cpu(void *dummy) +{ + lru_add_drain(); +} + +/* + * Isolate one page from the LRU lists and put it on the + * indicated list. Do necessary cache draining if the + * page is not on the LRU lists yet. + * + * Result: + * 0 = page not on LRU list + * 1 = page removed from LRU list and added to the specified list. + * -ENOENT = page is being freed elsewhere. + */ +int isolate_lru_page(struct page *page) +{ + int rc = 0; + struct zone *zone = page_zone(page); + +redo: + spin_lock_irq(&zone->lru_lock); + rc = __isolate_lru_page(page); + if (rc == 1) { + if (PageActive(page)) + del_page_from_active_list(zone, page); + else + del_page_from_inactive_list(zone, page); + } + spin_unlock_irq(&zone->lru_lock); + if (rc == 0) { + /* + * Maybe this page is still waiting for a cpu to drain it + * from one of the lru lists? + */ + rc = schedule_on_each_cpu(lru_add_drain_per_cpu, NULL); + if (rc == 0 && PageLRU(page)) + goto redo; + } + return rc; +} #endif /* @@ -758,48 +834,6 @@ static int isolate_lru_pages(int nr_to_scan, struct list_head *src, return nr_taken; } -static void lru_add_drain_per_cpu(void *dummy) -{ - lru_add_drain(); -} - -/* - * Isolate one page from the LRU lists and put it on the - * indicated list. Do necessary cache draining if the - * page is not on the LRU lists yet. - * - * Result: - * 0 = page not on LRU list - * 1 = page removed from LRU list and added to the specified list. - * -ENOENT = page is being freed elsewhere. - */ -int isolate_lru_page(struct page *page) -{ - int rc = 0; - struct zone *zone = page_zone(page); - -redo: - spin_lock_irq(&zone->lru_lock); - rc = __isolate_lru_page(page); - if (rc == 1) { - if (PageActive(page)) - del_page_from_active_list(zone, page); - else - del_page_from_inactive_list(zone, page); - } - spin_unlock_irq(&zone->lru_lock); - if (rc == 0) { - /* - * Maybe this page is still waiting for a cpu to drain it - * from one of the lru lists? - */ - rc = schedule_on_each_cpu(lru_add_drain_per_cpu, NULL); - if (rc == 0 && PageLRU(page)) - goto redo; - } - return rc; -} - /* * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed */ @@ -865,40 +899,6 @@ done: pagevec_release(&pvec); } -static inline void move_to_lru(struct page *page) -{ - list_del(&page->lru); - if (PageActive(page)) { - /* - * lru_cache_add_active checks that - * the PG_active bit is off. - */ - ClearPageActive(page); - lru_cache_add_active(page); - } else { - lru_cache_add(page); - } - put_page(page); -} - -/* - * Add isolated pages on the list back to the LRU - * - * returns the number of pages put back. - */ -int putback_lru_pages(struct list_head *l) -{ - struct page *page; - struct page *page2; - int count = 0; - - list_for_each_entry_safe(page, page2, l, lru) { - move_to_lru(page); - count++; - } - return count; -} - /* * This moves pages from the active list to the inactive list. * -- cgit v1.2.3 From 1480a540c98525640174a7eadd712378fcd6fd63 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:53 -0800 Subject: [PATCH] SwapMig: add_to_swap() avoid atomic allocations Add gfp_mask to add_to_swap add_to_swap does allocations with GFP_ATOMIC in order not to interfere with swapping. During migration we may have use add_to_swap extensively which may lead to out of memory errors. This patch makes add_to_swap take a parameter that specifies the gfp mask. The page migration code can then make add_to_swap use GFP_KERNEL. Signed-off-by: Hirokazu Takahashi Signed-off-by: Dave Hansen Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 2 +- mm/swap_state.c | 4 ++-- mm/vmscan.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 997d838f0e70..eb591eaad1b7 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -198,7 +198,7 @@ extern int rw_swap_page_sync(int, swp_entry_t, struct page *); extern struct address_space swapper_space; #define total_swapcache_pages swapper_space.nrpages extern void show_swap_cache_info(void); -extern int add_to_swap(struct page *); +extern int add_to_swap(struct page *, gfp_t); extern void __delete_from_swap_cache(struct page *); extern void delete_from_swap_cache(struct page *); extern int move_to_swap_cache(struct page *, swp_entry_t); diff --git a/mm/swap_state.c b/mm/swap_state.c index fc2aecb70a95..7b09ac503fec 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -141,7 +141,7 @@ void __delete_from_swap_cache(struct page *page) * Allocate swap space for the page and add the page to the * swap cache. Caller needs to hold the page lock. */ -int add_to_swap(struct page * page) +int add_to_swap(struct page * page, gfp_t gfp_mask) { swp_entry_t entry; int err; @@ -166,7 +166,7 @@ int add_to_swap(struct page * page) * Add it to the swap cache and mark it dirty */ err = __add_to_swap_cache(page, entry, - GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN); + gfp_mask|__GFP_NOMEMALLOC|__GFP_NOWARN); switch (err) { case 0: /* Success */ diff --git a/mm/vmscan.c b/mm/vmscan.c index daed4a73b761..5393b093a87b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -458,7 +458,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) * Try to allocate it some swap space here. */ if (PageAnon(page) && !PageSwapCache(page)) { - if (!add_to_swap(page)) + if (!add_to_swap(page, GFP_ATOMIC)) goto activate_locked; } #endif /* CONFIG_SWAP */ @@ -715,7 +715,7 @@ redo: } if (PageAnon(page) && !PageSwapCache(page)) { - if (!add_to_swap(page)) { + if (!add_to_swap(page, GFP_KERNEL)) { unlock_page(page); list_move(&page->lru, &failed); nr_failed++; -- cgit v1.2.3 From ee27497df36823f2793212cad0997c044eb0e1eb Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:54 -0800 Subject: [PATCH] SwapMig: Drop unused pages immediately Drop unused pages immediately If a page is encountered that is only referenced by the migration code then there is no reason to swap or migrate the page. Release the page by calling move_to_lru(). Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mm/vmscan.c b/mm/vmscan.c index 5393b093a87b..73ba4046ed27 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -689,6 +689,11 @@ redo: list_for_each_entry_safe(page, page2, l, lru) { cond_resched(); + if (page_count(page) == 1) { + /* page was freed from under us. So we are done. */ + move_to_lru(page); + continue; + } /* * Skip locked pages during the first two passes to give the * functions holding the lock time to release the page. Later we -- cgit v1.2.3 From d498471133ff1f9586a06820beaeebc575fe2814 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:55 -0800 Subject: [PATCH] SwapMig: Extend parameters for migrate_pages() Extend the parameters of migrate_pages() to allow the caller control over the fate of successfully migrated or impossible to migrate pages. Swap migration and direct migration will have the same interface after this patch so that patches can be independently applied to the policy layer and the core migration code. Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 3 ++- mm/mempolicy.c | 27 ++++++++++++++++++++++----- mm/vmscan.c | 17 ++++++++--------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index eb591eaad1b7..389d1c382e20 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -178,7 +178,8 @@ extern int vm_swappiness; #ifdef CONFIG_MIGRATION extern int isolate_lru_page(struct page *p); extern int putback_lru_pages(struct list_head *l); -extern int migrate_pages(struct list_head *l, struct list_head *t); +extern int migrate_pages(struct list_head *l, struct list_head *t, + struct list_head *moved, struct list_head *failed); #endif #ifdef CONFIG_MMU diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 20d5ad39fa41..30bdafba52d8 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -429,6 +429,19 @@ static int contextualize_policy(int mode, nodemask_t *nodes) return mpol_check_policy(mode, nodes); } +static int swap_pages(struct list_head *pagelist) +{ + LIST_HEAD(moved); + LIST_HEAD(failed); + int n; + + n = migrate_pages(pagelist, NULL, &moved, &failed); + putback_lru_pages(&failed); + putback_lru_pages(&moved); + + return n; +} + long do_mbind(unsigned long start, unsigned long len, unsigned long mode, nodemask_t *nmask, unsigned long flags) { @@ -481,10 +494,13 @@ long do_mbind(unsigned long start, unsigned long len, (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ? &pagelist : NULL); err = PTR_ERR(vma); if (!IS_ERR(vma)) { + int nr_failed = 0; + err = mbind_range(vma, start, end, new); if (!list_empty(&pagelist)) - migrate_pages(&pagelist, NULL); - if (!err && !list_empty(&pagelist) && (flags & MPOL_MF_STRICT)) + nr_failed = swap_pages(&pagelist); + + if (!err && nr_failed && (flags & MPOL_MF_STRICT)) err = -EIO; } if (!list_empty(&pagelist)) @@ -635,11 +651,12 @@ int do_migrate_pages(struct mm_struct *mm, down_read(&mm->mmap_sem); check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nodes, flags | MPOL_MF_DISCONTIG_OK, &pagelist); + if (!list_empty(&pagelist)) { - migrate_pages(&pagelist, NULL); - if (!list_empty(&pagelist)) - count = putback_lru_pages(&pagelist); + count = swap_pages(&pagelist); + putback_lru_pages(&pagelist); } + up_read(&mm->mmap_sem); return count; } diff --git a/mm/vmscan.c b/mm/vmscan.c index 73ba4046ed27..5eecb514ccea 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -670,10 +670,10 @@ retry: * list. The direct migration patchset * extends this function to avoid the use of swap. */ -int migrate_pages(struct list_head *l, struct list_head *t) +int migrate_pages(struct list_head *from, struct list_head *to, + struct list_head *moved, struct list_head *failed) { int retry; - LIST_HEAD(failed); int nr_failed = 0; int pass = 0; struct page *page; @@ -686,12 +686,12 @@ int migrate_pages(struct list_head *l, struct list_head *t) redo: retry = 0; - list_for_each_entry_safe(page, page2, l, lru) { + list_for_each_entry_safe(page, page2, from, lru) { cond_resched(); if (page_count(page) == 1) { /* page was freed from under us. So we are done. */ - move_to_lru(page); + list_move(&page->lru, moved); continue; } /* @@ -722,7 +722,7 @@ redo: if (PageAnon(page) && !PageSwapCache(page)) { if (!add_to_swap(page, GFP_KERNEL)) { unlock_page(page); - list_move(&page->lru, &failed); + list_move(&page->lru, failed); nr_failed++; continue; } @@ -732,8 +732,10 @@ redo: * Page is properly locked and writeback is complete. * Try to migrate the page. */ - if (!swap_page(page)) + if (!swap_page(page)) { + list_move(&page->lru, moved); continue; + } retry_later: retry++; } @@ -743,9 +745,6 @@ retry_later: if (!swapwrite) current->flags &= ~PF_SWAPWRITE; - if (!list_empty(&failed)) - list_splice(&failed, l); - return nr_failed + retry; } -- cgit v1.2.3 From d0d963281ccb22e6f339bfdd75c6b2e31351929f Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:55 -0800 Subject: [PATCH] SwapMig: Switch error handling in migrate_pages to use -Exx Use -Exxx instead of numeric return codes and cleanup the code in migrate_pages() using -Exx error codes. Consolidate successful migration handling Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 56 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 5eecb514ccea..bf903b2d198f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -606,10 +606,6 @@ int putback_lru_pages(struct list_head *l) /* * swapout a single page * page is locked upon entry, unlocked on exit - * - * return codes: - * 0 = complete - * 1 = retry */ static int swap_page(struct page *page) { @@ -650,7 +646,7 @@ unlock_retry: unlock_page(page); retry: - return 1; + return -EAGAIN; } /* * migrate_pages @@ -669,6 +665,8 @@ retry: * is only swapping out pages and never touches the second * list. The direct migration patchset * extends this function to avoid the use of swap. + * + * Return: Number of pages not migrated when "to" ran empty. */ int migrate_pages(struct list_head *from, struct list_head *to, struct list_head *moved, struct list_head *failed) @@ -679,6 +677,7 @@ int migrate_pages(struct list_head *from, struct list_head *to, struct page *page; struct page *page2; int swapwrite = current->flags & PF_SWAPWRITE; + int rc; if (!swapwrite) current->flags |= PF_SWAPWRITE; @@ -689,22 +688,23 @@ redo: list_for_each_entry_safe(page, page2, from, lru) { cond_resched(); - if (page_count(page) == 1) { + rc = 0; + if (page_count(page) == 1) /* page was freed from under us. So we are done. */ - list_move(&page->lru, moved); - continue; - } + goto next; + /* * Skip locked pages during the first two passes to give the * functions holding the lock time to release the page. Later we * use lock_page() to have a higher chance of acquiring the * lock. */ + rc = -EAGAIN; if (pass > 2) lock_page(page); else if (TestSetPageLocked(page)) - goto retry_later; + goto next; /* * Only wait on writeback if we have already done a pass where @@ -713,18 +713,19 @@ redo: if (pass > 0) { wait_on_page_writeback(page); } else { - if (PageWriteback(page)) { - unlock_page(page); - goto retry_later; - } + if (PageWriteback(page)) + goto unlock_page; } + /* + * Anonymous pages must have swap cache references otherwise + * the information contained in the page maps cannot be + * preserved. + */ if (PageAnon(page) && !PageSwapCache(page)) { if (!add_to_swap(page, GFP_KERNEL)) { - unlock_page(page); - list_move(&page->lru, failed); - nr_failed++; - continue; + rc = -ENOMEM; + goto unlock_page; } } @@ -732,12 +733,23 @@ redo: * Page is properly locked and writeback is complete. * Try to migrate the page. */ - if (!swap_page(page)) { + rc = swap_page(page); + goto next; + +unlock_page: + unlock_page(page); + +next: + if (rc == -EAGAIN) { + retry++; + } else if (rc) { + /* Permanent failure */ + list_move(&page->lru, failed); + nr_failed++; + } else { + /* Success */ list_move(&page->lru, moved); - continue; } -retry_later: - retry++; } if (retry && pass++ < 10) goto redo; -- cgit v1.2.3 From 45b07ef31d1182d2cfde7711327e3afb268bb1ac Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:00:56 -0800 Subject: [PATCH] cpusets: swap migration interface Add a boolean "memory_migrate" to each cpuset, represented by a file containing "0" or "1" in each directory below /dev/cpuset. It defaults to false (file contains "0"). It can be set true by writing "1" to the file. If true, then anytime that a task is attached to the cpuset so marked, the pages of that task will be moved to that cpuset, preserving, to the extent practical, the cpuset-relative placement of the pages. Also anytime that a cpuset so marked has its memory placement changed (by writing to its "mems" file), the tasks in that cpuset will have their pages moved to the cpusets new nodes, preserving, to the extent practical, the cpuset-relative placement of the moved pages. Signed-off-by: Paul Jackson Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpusets.txt | 25 +++++++++++++++++++++++++ include/linux/mempolicy.h | 7 +++++++ kernel/cpuset.c | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index a09a8eb80665..e2d9afc30d2d 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -192,6 +192,7 @@ containing the following files describing that cpuset: - cpus: list of CPUs in that cpuset - mems: list of Memory Nodes in that cpuset + - memory_migrate flag: if set, move pages to cpusets nodes - cpu_exclusive flag: is cpu placement exclusive? - mem_exclusive flag: is memory placement exclusive? - tasks: list of tasks (by pid) attached to that cpuset @@ -277,6 +278,30 @@ rewritten to the 'tasks' file of its cpuset. This is done to avoid impacting the scheduler code in the kernel with a check for changes in a tasks processor placement. +Normally, once a page is allocated (given a physical page +of main memory) then that page stays on whatever node it +was allocated, so long as it remains allocated, even if the +cpusets memory placement policy 'mems' subsequently changes. +If the cpuset flag file 'memory_migrate' is set true, then when +tasks are attached to that cpuset, any pages that task had +allocated to it on nodes in its previous cpuset are migrated +to the tasks new cpuset. Depending on the implementation, +this migration may either be done by swapping the page out, +so that the next time the page is referenced, it will be paged +into the tasks new cpuset, usually on the node where it was +referenced, or this migration may be done by directly copying +the pages from the tasks previous cpuset to the new cpuset, +where possible to the same node, relative to the new cpuset, +as the node that held the page, relative to the old cpuset. +Also if 'memory_migrate' is set true, then if that cpusets +'mems' file is modified, pages allocated to tasks in that +cpuset, that were on nodes in the previous setting of 'mems', +will be moved to nodes in the new setting of 'mems.' Again, +depending on the implementation, this might be done by swapping, +or by direct copying. In either case, pages that were not in +the tasks prior cpuset, or in the cpusets prior 'mems' setting, +will not be moved. + There is an exception to the above. If hotplug functionality is used to remove all the CPUs that are currently assigned to a cpuset, then the kernel will automatically update the cpus_allowed of all diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 3e61e829681d..66247eff24a0 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -235,6 +235,13 @@ static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma, return NODE_DATA(0)->node_zonelists + gfp_zone(GFP_HIGHUSER); } +static inline int do_migrate_pages(struct mm_struct *mm, + const nodemask_t *from_nodes, + const nodemask_t *to_nodes, int flags) +{ + return 0; +} + static inline void check_highest_zone(int k) { } diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 7430640f9816..f63383e01ec7 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -87,6 +87,7 @@ struct cpuset { typedef enum { CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, + CS_MEMORY_MIGRATE, CS_REMOVED, CS_NOTIFY_ON_RELEASE } cpuset_flagbits_t; @@ -112,6 +113,11 @@ static inline int notify_on_release(const struct cpuset *cs) return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags); } +static inline int is_memory_migrate(const struct cpuset *cs) +{ + return !!test_bit(CS_MEMORY_MIGRATE, &cs->flags); +} + /* * Increment this atomic integer everytime any cpuset changes its * mems_allowed value. Users of cpusets can track this generation @@ -602,16 +608,24 @@ static void refresh_mems(void) if (current->cpuset_mems_generation != my_cpusets_mem_gen) { struct cpuset *cs; nodemask_t oldmem = current->mems_allowed; + int migrate; down(&callback_sem); task_lock(current); cs = current->cpuset; + migrate = is_memory_migrate(cs); guarantee_online_mems(cs, ¤t->mems_allowed); current->cpuset_mems_generation = cs->mems_generation; task_unlock(current); up(&callback_sem); - if (!nodes_equal(oldmem, current->mems_allowed)) + if (!nodes_equal(oldmem, current->mems_allowed)) { numa_policy_rebind(&oldmem, ¤t->mems_allowed); + if (migrate) { + do_migrate_pages(current->mm, &oldmem, + ¤t->mems_allowed, + MPOL_MF_MOVE_ALL); + } + } } } @@ -795,7 +809,7 @@ static int update_nodemask(struct cpuset *cs, char *buf) /* * update_flag - read a 0 or a 1 in a file and update associated flag * bit: the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, - * CS_NOTIFY_ON_RELEASE) + * CS_NOTIFY_ON_RELEASE, CS_MEMORY_MIGRATE) * cs: the cpuset to update * buf: the buffer where we read the 0 or 1 * @@ -848,6 +862,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) struct task_struct *tsk; struct cpuset *oldcs; cpumask_t cpus; + nodemask_t from, to; if (sscanf(pidbuf, "%d", &pid) != 1) return -EIO; @@ -893,7 +908,12 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) guarantee_online_cpus(cs, &cpus); set_cpus_allowed(tsk, cpus); + from = oldcs->mems_allowed; + to = cs->mems_allowed; + up(&callback_sem); + if (is_memory_migrate(cs)) + do_migrate_pages(tsk->mm, &from, &to, MPOL_MF_MOVE_ALL); put_task_struct(tsk); if (atomic_dec_and_test(&oldcs->count)) check_for_release(oldcs, ppathbuf); @@ -905,6 +925,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) typedef enum { FILE_ROOT, FILE_DIR, + FILE_MEMORY_MIGRATE, FILE_CPULIST, FILE_MEMLIST, FILE_CPU_EXCLUSIVE, @@ -960,6 +981,9 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us case FILE_NOTIFY_ON_RELEASE: retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer); break; + case FILE_MEMORY_MIGRATE: + retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer); + break; case FILE_TASKLIST: retval = attach_task(cs, buffer, &pathbuf); break; @@ -1060,6 +1084,9 @@ static ssize_t cpuset_common_file_read(struct file *file, char __user *buf, case FILE_NOTIFY_ON_RELEASE: *s++ = notify_on_release(cs) ? '1' : '0'; break; + case FILE_MEMORY_MIGRATE: + *s++ = is_memory_migrate(cs) ? '1' : '0'; + break; default: retval = -EINVAL; goto out; @@ -1408,6 +1435,11 @@ static struct cftype cft_notify_on_release = { .private = FILE_NOTIFY_ON_RELEASE, }; +static struct cftype cft_memory_migrate = { + .name = "memory_migrate", + .private = FILE_MEMORY_MIGRATE, +}; + static int cpuset_populate_dir(struct dentry *cs_dentry) { int err; @@ -1422,6 +1454,8 @@ static int cpuset_populate_dir(struct dentry *cs_dentry) return err; if ((err = cpuset_add_file(cs_dentry, &cft_notify_on_release)) < 0) return err; + if ((err = cpuset_add_file(cs_dentry, &cft_memory_migrate)) < 0) + return err; if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0) return err; return 0; -- cgit v1.2.3 From aea47ff363c15b0be5fc27ed991b1fdee338f0a7 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:00:57 -0800 Subject: [PATCH] mm: make hugepages obey cpusets. See http://marc.theaimsgroup.com/?l=linux-kernel&m=113167000201265&w=2 http://marc.theaimsgroup.com/?l=linux-mm&m=113167267527312&w=2 Make hugepages obey cpusets. Signed-off-by: Christoph Lameter Acked-by: William Irwin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index f4c43d7980ba..b21d78c941b5 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,8 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma, for (z = zonelist->zones; *z; z++) { nid = (*z)->zone_pgdat->node_id; - if (!list_empty(&hugepage_freelists[nid])) + if (cpuset_zone_allowed(*z, GFP_HIGHUSER) && + !list_empty(&hugepage_freelists[nid])) break; } -- cgit v1.2.3 From 152194aaa6266d71dfee57882a23def339ef17a4 Mon Sep 17 00:00:00 2001 From: Avishay Traeger Date: Sun, 8 Jan 2006 01:00:58 -0800 Subject: [PATCH] set_page_count() macro safety Fix set_page_count() macro to handle complex arguments. Signed-off-by: Avishay Traeger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 83c651f25188..7ff54242c5d7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -308,7 +308,7 @@ struct page { */ #define get_page_testone(p) atomic_inc_and_test(&(p)->_count) -#define set_page_count(p,v) atomic_set(&(p)->_count, v - 1) +#define set_page_count(p,v) atomic_set(&(p)->_count, (v) - 1) #define __put_page(p) atomic_dec(&(p)->_count) extern void FASTCALL(__page_cache_release(struct page *)); -- cgit v1.2.3 From cd105df4590c89837a1c300843238148cfef9b5f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 8 Jan 2006 01:00:59 -0800 Subject: [PATCH] mm: clean up local variables Clean up a local variable with the same name as a variable in a larger block. Also move a variable into the block where it's actually used. Spotted by http://linuxicc.sourceforge.net/ Signed-off-by: Tobias Klauser Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 3 ++- mm/swapfile.c | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index f71d8be2f4e0..76b092bd0bf7 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -854,7 +854,6 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, struct kmem_list3 *l3 = NULL; int node = cpu_to_node(cpu); int memsize = sizeof(struct kmem_list3); - struct array_cache *nc = NULL; switch (action) { case CPU_UP_PREPARE: @@ -891,6 +890,8 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, /* Now we can go ahead with allocating the shared array's & array cache's */ list_for_each_entry(cachep, &cache_chain, next) { + struct array_cache *nc; + nc = alloc_arraycache(node, cachep->limit, cachep->batchcount); if (!nc) diff --git a/mm/swapfile.c b/mm/swapfile.c index 6da4b28b896b..80f948a2028b 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1493,7 +1493,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) goto bad_swap; if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES) goto bad_swap; - + /* OK, set up the swap map and apply the bad block list */ if (!(p->swap_map = vmalloc(maxpages * sizeof(short)))) { error = -ENOMEM; @@ -1502,17 +1502,17 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) error = 0; memset(p->swap_map, 0, maxpages * sizeof(short)); - for (i=0; iinfo.nr_badpages; i++) { - int page = swap_header->info.badpages[i]; - if (page <= 0 || page >= swap_header->info.last_page) + for (i = 0; i < swap_header->info.nr_badpages; i++) { + int page_nr = swap_header->info.badpages[i]; + if (page_nr <= 0 || page_nr >= swap_header->info.last_page) error = -EINVAL; else - p->swap_map[page] = SWAP_MAP_BAD; + p->swap_map[page_nr] = SWAP_MAP_BAD; } nr_good_pages = swap_header->info.last_page - swap_header->info.nr_badpages - 1 /* header page */; - if (error) + if (error) goto bad_swap; } -- cgit v1.2.3 From ef2bf0dc8675e14cf8cba3b7fb9f48d72640a70e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 8 Jan 2006 01:01:00 -0800 Subject: [PATCH] rmap: additional diagnostics in page_remove_rmap() We seem to be hitting this assertion failure too often for it to be hardware bugs. Cc: Hugh Dickins Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/rmap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/rmap.c b/mm/rmap.c index 6f3f7db27128..66ec43053a4d 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -514,6 +514,13 @@ void page_add_file_rmap(struct page *page) void page_remove_rmap(struct page *page) { if (atomic_add_negative(-1, &page->_mapcount)) { + if (page_mapcount(page) < 0) { + printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page)); + printk (KERN_EMERG " page->flags = %lx\n", page->flags); + printk (KERN_EMERG " page->count = %x\n", page_count(page)); + printk (KERN_EMERG " page->mapping = %p\n", page->mapping); + } + BUG_ON(page_mapcount(page) < 0); /* * It would be tidy to reset the PageAnon mapping here, -- cgit v1.2.3 From 38e35860dbe6197a4b42eb6e8b47da940b7695dd Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:01:01 -0800 Subject: [PATCH] mempolicies: private pointer in check_range and MPOL_MF_INVERT This was was first posted at http://marc.theaimsgroup.com/?l=linux-mm&m=113149240227584&w=2 (Part of this functionality is also contained in the direct migration pathset. The functionality here is more generic and independent of that patchset.) - Add internal flags MPOL_MF_INVERT to control check_range() behavior. - Replace the pagelist passed through by check_range by a general private pointer that may be used for other purposes. (The following patches will use that to merge numa_maps into mempolicy.c and to better group the page migration code in the policy layer) - Improve some comments. Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 30bdafba52d8..270e9a39ec15 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -88,8 +88,9 @@ #include #include -/* Internal MPOL_MF_xxx flags */ +/* Internal flags */ #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0) /* Skip checks for continuous vmas */ +#define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1) /* Invert check for nodemask */ static kmem_cache_t *policy_cache; static kmem_cache_t *sn_cache; @@ -227,11 +228,11 @@ static void migrate_page_add(struct vm_area_struct *vma, } } -/* Ensure all existing pages follow the policy. */ +/* Scan through pages checking if pages follow certain conditions. */ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, unsigned long end, const nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + void *private) { pte_t *orig_pte; pte_t *pte; @@ -248,12 +249,13 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (!page) continue; nid = page_to_nid(page); - if (!node_isset(nid, *nodes)) { - if (pagelist) - migrate_page_add(vma, page, pagelist, flags); - else - break; - } + if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT)) + continue; + + if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) + migrate_page_add(vma, page, private, flags); + else + break; } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap_unlock(orig_pte, ptl); return addr != end; @@ -262,7 +264,7 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, unsigned long addr, unsigned long end, const nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + void *private) { pmd_t *pmd; unsigned long next; @@ -273,7 +275,7 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, if (pmd_none_or_clear_bad(pmd)) continue; if (check_pte_range(vma, pmd, addr, next, nodes, - flags, pagelist)) + flags, private)) return -EIO; } while (pmd++, addr = next, addr != end); return 0; @@ -282,7 +284,7 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, unsigned long addr, unsigned long end, const nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + void *private) { pud_t *pud; unsigned long next; @@ -293,7 +295,7 @@ static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, if (pud_none_or_clear_bad(pud)) continue; if (check_pmd_range(vma, pud, addr, next, nodes, - flags, pagelist)) + flags, private)) return -EIO; } while (pud++, addr = next, addr != end); return 0; @@ -302,7 +304,7 @@ static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, static inline int check_pgd_range(struct vm_area_struct *vma, unsigned long addr, unsigned long end, const nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + void *private) { pgd_t *pgd; unsigned long next; @@ -313,7 +315,7 @@ static inline int check_pgd_range(struct vm_area_struct *vma, if (pgd_none_or_clear_bad(pgd)) continue; if (check_pud_range(vma, pgd, addr, next, nodes, - flags, pagelist)) + flags, private)) return -EIO; } while (pgd++, addr = next, addr != end); return 0; @@ -335,8 +337,7 @@ static inline int vma_migratable(struct vm_area_struct *vma) */ static struct vm_area_struct * check_range(struct mm_struct *mm, unsigned long start, unsigned long end, - const nodemask_t *nodes, unsigned long flags, - struct list_head *pagelist) + const nodemask_t *nodes, unsigned long flags, void *private) { int err; struct vm_area_struct *first, *vma, *prev; @@ -363,7 +364,7 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, if (vma->vm_start > start) start = vma->vm_start; err = check_pgd_range(vma, start, endvma, nodes, - flags, pagelist); + flags, private); if (err) { first = ERR_PTR(err); break; @@ -452,7 +453,8 @@ long do_mbind(unsigned long start, unsigned long len, int err; LIST_HEAD(pagelist); - if ((flags & ~(unsigned long)(MPOL_MF_STRICT|MPOL_MF_MOVE|MPOL_MF_MOVE_ALL)) + if ((flags & ~(unsigned long)(MPOL_MF_STRICT | + MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) || mode > MPOL_MAX) return -EINVAL; if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_RESOURCE)) @@ -490,8 +492,9 @@ long do_mbind(unsigned long start, unsigned long len, mode,nodes_addr(nodes)[0]); down_write(&mm->mmap_sem); - vma = check_range(mm, start, end, nmask, flags, - (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) ? &pagelist : NULL); + vma = check_range(mm, start, end, nmask, + flags | MPOL_MF_INVERT, &pagelist); + err = PTR_ERR(vma); if (!IS_ERR(vma)) { int nr_failed = 0; @@ -646,7 +649,6 @@ int do_migrate_pages(struct mm_struct *mm, nodemask_t nodes; nodes_andnot(nodes, *from_nodes, *to_nodes); - nodes_complement(nodes, nodes); down_read(&mm->mmap_sem); check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nodes, -- cgit v1.2.3 From 1a75a6c825c17249ca49f050a872a04ce0997ce3 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:01:02 -0800 Subject: [PATCH] Fold numa_maps into mempolicies.c First discussed at http://marc.theaimsgroup.com/?t=113149255100001&r=1&w=2 - Use the check_range() in mempolicy.c to gather statistics. - Improve the numa_maps code in general and fix some comments. Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 127 ++---------------------------------------------- mm/mempolicy.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 123 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 50bd5a8f0446..0eaad41f4658 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -390,129 +390,12 @@ struct seq_operations proc_pid_smaps_op = { }; #ifdef CONFIG_NUMA - -struct numa_maps { - unsigned long pages; - unsigned long anon; - unsigned long mapped; - unsigned long mapcount_max; - unsigned long node[MAX_NUMNODES]; -}; - -/* - * Calculate numa node maps for a vma - */ -static struct numa_maps *get_numa_maps(struct vm_area_struct *vma) -{ - int i; - struct page *page; - unsigned long vaddr; - struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL); - - if (!md) - return NULL; - md->pages = 0; - md->anon = 0; - md->mapped = 0; - md->mapcount_max = 0; - for_each_node(i) - md->node[i] =0; - - for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { - page = follow_page(vma, vaddr, 0); - if (page) { - int count = page_mapcount(page); - - if (count) - md->mapped++; - if (count > md->mapcount_max) - md->mapcount_max = count; - md->pages++; - if (PageAnon(page)) - md->anon++; - md->node[page_to_nid(page)]++; - } - cond_resched(); - } - return md; -} - -static int show_numa_map(struct seq_file *m, void *v) -{ - struct task_struct *task = m->private; - struct vm_area_struct *vma = v; - struct mempolicy *pol; - struct numa_maps *md; - struct zone **z; - int n; - int first; - - if (!vma->vm_mm) - return 0; - - md = get_numa_maps(vma); - if (!md) - return 0; - - seq_printf(m, "%08lx", vma->vm_start); - pol = get_vma_policy(task, vma, vma->vm_start); - /* Print policy */ - switch (pol->policy) { - case MPOL_PREFERRED: - seq_printf(m, " prefer=%d", pol->v.preferred_node); - break; - case MPOL_BIND: - seq_printf(m, " bind={"); - first = 1; - for (z = pol->v.zonelist->zones; *z; z++) { - - if (!first) - seq_putc(m, ','); - else - first = 0; - seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id, - (*z)->name); - } - seq_putc(m, '}'); - break; - case MPOL_INTERLEAVE: - seq_printf(m, " interleave={"); - first = 1; - for_each_node(n) { - if (node_isset(n, pol->v.nodes)) { - if (!first) - seq_putc(m,','); - else - first = 0; - seq_printf(m, "%d",n); - } - } - seq_putc(m, '}'); - break; - default: - seq_printf(m," default"); - break; - } - seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu", - md->mapcount_max, md->pages, md->mapped); - if (md->anon) - seq_printf(m," Anon=%lu",md->anon); - - for_each_online_node(n) { - if (md->node[n]) - seq_printf(m, " N%d=%lu", n, md->node[n]); - } - seq_putc(m, '\n'); - kfree(md); - if (m->count < m->size) /* vma is copied successfully */ - m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; - return 0; -} +extern int show_numa_map(struct seq_file *m, void *v); struct seq_operations proc_pid_numa_maps_op = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_numa_map + .start = m_start, + .next = m_next, + .stop = m_stop, + .show = show_numa_map }; #endif diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 270e9a39ec15..44b9d69900bc 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -84,6 +84,8 @@ #include #include #include +#include +#include #include #include @@ -91,6 +93,7 @@ /* Internal flags */ #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0) /* Skip checks for continuous vmas */ #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1) /* Invert check for nodemask */ +#define MPOL_MF_STATS (MPOL_MF_INTERNAL << 2) /* Gather statistics */ static kmem_cache_t *policy_cache; static kmem_cache_t *sn_cache; @@ -228,6 +231,8 @@ static void migrate_page_add(struct vm_area_struct *vma, } } +static void gather_stats(struct page *, void *); + /* Scan through pages checking if pages follow certain conditions. */ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, unsigned long end, @@ -252,7 +257,9 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT)) continue; - if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) + if (flags & MPOL_MF_STATS) + gather_stats(page, private); + else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) migrate_page_add(vma, page, private, flags); else break; @@ -1460,3 +1467,132 @@ void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new) { rebind_policy(current->mempolicy, old, new); } + +/* + * Display pages allocated per node and memory policy via /proc. + */ + +static const char *policy_types[] = { "default", "prefer", "bind", + "interleave" }; + +/* + * Convert a mempolicy into a string. + * Returns the number of characters in buffer (if positive) + * or an error (negative) + */ +static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) +{ + char *p = buffer; + int l; + nodemask_t nodes; + int mode = pol ? pol->policy : MPOL_DEFAULT; + + switch (mode) { + case MPOL_DEFAULT: + nodes_clear(nodes); + break; + + case MPOL_PREFERRED: + nodes_clear(nodes); + node_set(pol->v.preferred_node, nodes); + break; + + case MPOL_BIND: + get_zonemask(pol, &nodes); + break; + + case MPOL_INTERLEAVE: + nodes = pol->v.nodes; + break; + + default: + BUG(); + return -EFAULT; + } + + l = strlen(policy_types[mode]); + if (buffer + maxlen < p + l + 1) + return -ENOSPC; + + strcpy(p, policy_types[mode]); + p += l; + + if (!nodes_empty(nodes)) { + if (buffer + maxlen < p + 2) + return -ENOSPC; + *p++ = '='; + p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); + } + return p - buffer; +} + +struct numa_maps { + unsigned long pages; + unsigned long anon; + unsigned long mapped; + unsigned long mapcount_max; + unsigned long node[MAX_NUMNODES]; +}; + +static void gather_stats(struct page *page, void *private) +{ + struct numa_maps *md = private; + int count = page_mapcount(page); + + if (count) + md->mapped++; + + if (count > md->mapcount_max) + md->mapcount_max = count; + + md->pages++; + + if (PageAnon(page)) + md->anon++; + + md->node[page_to_nid(page)]++; + cond_resched(); +} + +int show_numa_map(struct seq_file *m, void *v) +{ + struct task_struct *task = m->private; + struct vm_area_struct *vma = v; + struct numa_maps *md; + int n; + char buffer[50]; + + if (!vma->vm_mm) + return 0; + + md = kzalloc(sizeof(struct numa_maps), GFP_KERNEL); + if (!md) + return 0; + + check_pgd_range(vma, vma->vm_start, vma->vm_end, + &node_online_map, MPOL_MF_STATS, md); + + if (md->pages) { + mpol_to_str(buffer, sizeof(buffer), + get_vma_policy(task, vma, vma->vm_start)); + + seq_printf(m, "%08lx %s pages=%lu mapped=%lu maxref=%lu", + vma->vm_start, buffer, md->pages, + md->mapped, md->mapcount_max); + + if (md->anon) + seq_printf(m," anon=%lu",md->anon); + + for_each_online_node(n) + if (md->node[n]) + seq_printf(m, " N%d=%lu", n, md->node[n]); + + seq_putc(m, '\n'); + } + kfree(md); + + if (m->count < m->size) + m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; + return 0; +} + -- cgit v1.2.3 From 132beacf9785d2e6e8aecb59aa078f3ca5668fa6 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:01:02 -0800 Subject: [PATCH] Drop page table lock before calling migrate_page_add() migrate_page_add cannot be called with a spinlock held (calls isolate_lru_page which calles schedule_on_each_cpu). Drop ptl lock in check_pte_range before calling migrate_page_add(). Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 44b9d69900bc..4c0510e9e7f6 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -259,8 +259,11 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (flags & MPOL_MF_STATS) gather_stats(page, private); - else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) + else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) { + spin_unlock(ptl); migrate_page_add(vma, page, private, flags); + spin_lock(ptl); + } else break; } while (pte++, addr += PAGE_SIZE, addr != end); -- cgit v1.2.3 From 48fce3429df84a94766fbbc845fa8450d0715b48 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:01:03 -0800 Subject: [PATCH] mempolicies: unexport get_vma_policy() Since the numa_maps functionality is now in mempolicy.c we no longer need to export get_vma_policy(). Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mempolicy.h | 3 --- mm/mempolicy.c | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 66247eff24a0..05fddd5bee5d 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -144,9 +144,6 @@ void mpol_free_shared_policy(struct shared_policy *p); struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx); -struct mempolicy *get_vma_policy(struct task_struct *task, - struct vm_area_struct *vma, unsigned long addr); - extern void numa_default_policy(void); extern void numa_policy_init(void); extern void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 4c0510e9e7f6..4b077ec6c005 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -935,8 +935,8 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len, #endif /* Return effective policy for a VMA */ -struct mempolicy * -get_vma_policy(struct task_struct *task, struct vm_area_struct *vma, unsigned long addr) +static struct mempolicy * get_vma_policy(struct task_struct *task, + struct vm_area_struct *vma, unsigned long addr) { struct mempolicy *pol = task->mempolicy; -- cgit v1.2.3 From 6ce3c4c0ff62ca6391019b7832fb41a7f28b9e26 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 8 Jan 2006 01:01:04 -0800 Subject: [PATCH] Move page migration related functions near do_migrate_pages() Group page migration functions in mempolicy.c Add a forward declaration for migrate_page_add (like gather_stats()) and use our new found mobility to group all page migration related function around do_migrate_pages(). Signed-off-by: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 270 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 138 insertions(+), 132 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 4b077ec6c005..7051fe450e96 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -183,55 +183,9 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) return policy; } -/* Check if we are the only process mapping the page in question */ -static inline int single_mm_mapping(struct mm_struct *mm, - struct address_space *mapping) -{ - struct vm_area_struct *vma; - struct prio_tree_iter iter; - int rc = 1; - - spin_lock(&mapping->i_mmap_lock); - vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX) - if (mm != vma->vm_mm) { - rc = 0; - goto out; - } - list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list) - if (mm != vma->vm_mm) { - rc = 0; - goto out; - } -out: - spin_unlock(&mapping->i_mmap_lock); - return rc; -} - -/* - * Add a page to be migrated to the pagelist - */ -static void migrate_page_add(struct vm_area_struct *vma, - struct page *page, struct list_head *pagelist, unsigned long flags) -{ - /* - * Avoid migrating a page that is shared by others and not writable. - */ - if ((flags & MPOL_MF_MOVE_ALL) || !page->mapping || PageAnon(page) || - mapping_writably_mapped(page->mapping) || - single_mm_mapping(vma->vm_mm, page->mapping)) { - int rc = isolate_lru_page(page); - - if (rc == 1) - list_add(&page->lru, pagelist); - /* - * If the isolate attempt was not successful then we just - * encountered an unswappable page. Something must be wrong. - */ - WARN_ON(rc == 0); - } -} - static void gather_stats(struct page *, void *); +static void migrate_page_add(struct vm_area_struct *vma, + struct page *page, struct list_head *pagelist, unsigned long flags); /* Scan through pages checking if pages follow certain conditions. */ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, @@ -440,90 +394,6 @@ static int contextualize_policy(int mode, nodemask_t *nodes) return mpol_check_policy(mode, nodes); } -static int swap_pages(struct list_head *pagelist) -{ - LIST_HEAD(moved); - LIST_HEAD(failed); - int n; - - n = migrate_pages(pagelist, NULL, &moved, &failed); - putback_lru_pages(&failed); - putback_lru_pages(&moved); - - return n; -} - -long do_mbind(unsigned long start, unsigned long len, - unsigned long mode, nodemask_t *nmask, unsigned long flags) -{ - struct vm_area_struct *vma; - struct mm_struct *mm = current->mm; - struct mempolicy *new; - unsigned long end; - int err; - LIST_HEAD(pagelist); - - if ((flags & ~(unsigned long)(MPOL_MF_STRICT | - MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) - || mode > MPOL_MAX) - return -EINVAL; - if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - if (start & ~PAGE_MASK) - return -EINVAL; - - if (mode == MPOL_DEFAULT) - flags &= ~MPOL_MF_STRICT; - - len = (len + PAGE_SIZE - 1) & PAGE_MASK; - end = start + len; - - if (end < start) - return -EINVAL; - if (end == start) - return 0; - - if (mpol_check_policy(mode, nmask)) - return -EINVAL; - - new = mpol_new(mode, nmask); - if (IS_ERR(new)) - return PTR_ERR(new); - - /* - * If we are using the default policy then operation - * on discontinuous address spaces is okay after all - */ - if (!new) - flags |= MPOL_MF_DISCONTIG_OK; - - PDprintk("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len, - mode,nodes_addr(nodes)[0]); - - down_write(&mm->mmap_sem); - vma = check_range(mm, start, end, nmask, - flags | MPOL_MF_INVERT, &pagelist); - - err = PTR_ERR(vma); - if (!IS_ERR(vma)) { - int nr_failed = 0; - - err = mbind_range(vma, start, end, new); - if (!list_empty(&pagelist)) - nr_failed = swap_pages(&pagelist); - - if (!err && nr_failed && (flags & MPOL_MF_STRICT)) - err = -EIO; - } - if (!list_empty(&pagelist)) - putback_lru_pages(&pagelist); - - up_write(&mm->mmap_sem); - mpol_free(new); - return err; -} - /* Set the process memory policy */ long do_set_mempolicy(int mode, nodemask_t *nodes) { @@ -643,6 +513,71 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask, return err; } +/* + * page migration + */ + +/* Check if we are the only process mapping the page in question */ +static inline int single_mm_mapping(struct mm_struct *mm, + struct address_space *mapping) +{ + struct vm_area_struct *vma; + struct prio_tree_iter iter; + int rc = 1; + + spin_lock(&mapping->i_mmap_lock); + vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX) + if (mm != vma->vm_mm) { + rc = 0; + goto out; + } + list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list) + if (mm != vma->vm_mm) { + rc = 0; + goto out; + } +out: + spin_unlock(&mapping->i_mmap_lock); + return rc; +} + +/* + * Add a page to be migrated to the pagelist + */ +static void migrate_page_add(struct vm_area_struct *vma, + struct page *page, struct list_head *pagelist, unsigned long flags) +{ + /* + * Avoid migrating a page that is shared by others and not writable. + */ + if ((flags & MPOL_MF_MOVE_ALL) || !page->mapping || PageAnon(page) || + mapping_writably_mapped(page->mapping) || + single_mm_mapping(vma->vm_mm, page->mapping)) { + int rc = isolate_lru_page(page); + + if (rc == 1) + list_add(&page->lru, pagelist); + /* + * If the isolate attempt was not successful then we just + * encountered an unswappable page. Something must be wrong. + */ + WARN_ON(rc == 0); + } +} + +static int swap_pages(struct list_head *pagelist) +{ + LIST_HEAD(moved); + LIST_HEAD(failed); + int n; + + n = migrate_pages(pagelist, NULL, &moved, &failed); + putback_lru_pages(&failed); + putback_lru_pages(&moved); + + return n; +} + /* * For now migrate_pages simply swaps out the pages from nodes that are in * the source set but not in the target set. In the future, we would @@ -673,6 +608,77 @@ int do_migrate_pages(struct mm_struct *mm, return count; } +long do_mbind(unsigned long start, unsigned long len, + unsigned long mode, nodemask_t *nmask, unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + struct mempolicy *new; + unsigned long end; + int err; + LIST_HEAD(pagelist); + + if ((flags & ~(unsigned long)(MPOL_MF_STRICT | + MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) + || mode > MPOL_MAX) + return -EINVAL; + if ((flags & MPOL_MF_MOVE_ALL) && !capable(CAP_SYS_RESOURCE)) + return -EPERM; + + if (start & ~PAGE_MASK) + return -EINVAL; + + if (mode == MPOL_DEFAULT) + flags &= ~MPOL_MF_STRICT; + + len = (len + PAGE_SIZE - 1) & PAGE_MASK; + end = start + len; + + if (end < start) + return -EINVAL; + if (end == start) + return 0; + + if (mpol_check_policy(mode, nmask)) + return -EINVAL; + + new = mpol_new(mode, nmask); + if (IS_ERR(new)) + return PTR_ERR(new); + + /* + * If we are using the default policy then operation + * on discontinuous address spaces is okay after all + */ + if (!new) + flags |= MPOL_MF_DISCONTIG_OK; + + PDprintk("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len, + mode,nodes_addr(nodes)[0]); + + down_write(&mm->mmap_sem); + vma = check_range(mm, start, end, nmask, + flags | MPOL_MF_INVERT, &pagelist); + + err = PTR_ERR(vma); + if (!IS_ERR(vma)) { + int nr_failed = 0; + + err = mbind_range(vma, start, end, new); + if (!list_empty(&pagelist)) + nr_failed = swap_pages(&pagelist); + + if (!err && nr_failed && (flags & MPOL_MF_STRICT)) + err = -EIO; + } + if (!list_empty(&pagelist)) + putback_lru_pages(&pagelist); + + up_write(&mm->mmap_sem); + mpol_free(new); + return err; +} + /* * User space interface with variable sized bitmaps for nodelists. */ -- cgit v1.2.3 From 2f659f462d2ab519068d0e2bb677d7a700decb8d Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Sun, 8 Jan 2006 01:01:05 -0800 Subject: [PATCH] Optimise oom kill of current task When oom_killer kills current there's no need to call schedule_timeout_interruptible() since task must die ASAP. Signed-Off-By: Pavel Emelianov Signed-Off-By: Kirill Korotaev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/oom_kill.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index d348b9035955..4748b906aff2 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -298,7 +298,8 @@ retry: /* * Give "p" a good chance of killing itself before we - * retry to allocate memory. + * retry to allocate memory unless "p" is current */ - schedule_timeout_interruptible(1); + if (!test_thread_flag(TIF_MEMDIE)) + schedule_timeout_interruptible(1); } -- cgit v1.2.3 From 974dffc2dd72d499a3ff150f61c8025b097a2c34 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:06 -0800 Subject: [PATCH] cs89x0: make {read,write}word take base_addr readword() and writeword() take a 'struct net_device *' and deref its ->base_addr member. Make them take the base_addr directly instead, so that we can switch the other occurences of inw/outw in the file over to readword/writeword as well. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index a6078ad9b654..29a7c0cf84bc 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -353,15 +353,15 @@ writereg(struct net_device *dev, int portno, int value) } static int -readword(struct net_device *dev, int portno) +readword(unsigned long base_addr, int portno) { - return inw(dev->base_addr + portno); + return inw(base_addr + portno); } static void -writeword(struct net_device *dev, int portno, int value) +writeword(unsigned long base_addr, int portno, int value) { - outw(value, dev->base_addr + portno); + outw(value, base_addr + portno); } static int __init @@ -1104,8 +1104,8 @@ send_test_pkt(struct net_device *dev) memcpy(test_packet, dev->dev_addr, ETH_ALEN); memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN); - writeword(dev, TX_CMD_PORT, TX_AFTER_ALL); - writeword(dev, TX_LEN_PORT, ETH_ZLEN); + writeword(dev->base_addr, TX_CMD_PORT, TX_AFTER_ALL); + writeword(dev->base_addr, TX_LEN_PORT, ETH_ZLEN); /* Test to see if the chip has allocated memory for the packet */ while (jiffies - timenow < 5) @@ -1457,8 +1457,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); /* initiate a transmit sequence */ - writeword(dev, TX_CMD_PORT, lp->send_cmd); - writeword(dev, TX_LEN_PORT, skb->len); + writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd); + writeword(dev->base_addr, TX_LEN_PORT, skb->len); /* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { @@ -1512,7 +1512,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs) course, if you're on a slow machine, and packets are arriving faster than you can read them off, you're screwed. Hasta la vista, baby! */ - while ((status = readword(dev, ISQ_PORT))) { + while ((status = readword(dev->base_addr, ISQ_PORT))) { if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); handled = 1; switch(status & ISQ_EVENT_MASK) { -- cgit v1.2.3 From fc8c7d79b117f7a5b17640bf657d95afe4025bb8 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:08 -0800 Subject: [PATCH] cs89x0: convert {inw,outw} calls to {read,write}word Switch all occurences of inw/outw in the driver over to readword/writeword. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 29a7c0cf84bc..04fca31f1733 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -491,8 +491,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) #ifdef CONFIG_SH_HICOSH4 /* truely reset the chip */ - outw(0x0114, ioaddr + ADD_PORT); - outw(0x0040, ioaddr + DATA_PORT); + writeword(ioaddr, ADD_PORT, 0x0114); + writeword(ioaddr, DATA_PORT, 0x0040); #endif /* if they give us an odd I/O address, then do ONE write to @@ -503,24 +503,24 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) if (net_debug > 1) printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); if ((ioaddr & 2) != 2) - if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) { + if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) { printk(KERN_ERR "%s: bad signature 0x%x\n", - dev->name, inw((ioaddr & ~3)+ ADD_PORT)); + dev->name, readword(ioaddr & ~3, ADD_PORT)); retval = -ENODEV; goto out2; } } - printk(KERN_DEBUG "PP_addr at %x: 0x%x\n", - ioaddr + ADD_PORT, inw(ioaddr + ADD_PORT)); + printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n", + ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT)); ioaddr &= ~3; - outw(PP_ChipID, ioaddr + ADD_PORT); + writeword(ioaddr, ADD_PORT, PP_ChipID); - tmp = inw(ioaddr + DATA_PORT); + tmp = readword(ioaddr, DATA_PORT); if (tmp != CHIP_EISA_ID_SIG) { - printk(KERN_DEBUG "%s: incorrect signature at %x: 0x%x!=" + printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!=" CHIP_EISA_ID_SIG_STR "\n", - dev->name, ioaddr + DATA_PORT, tmp); + dev->name, ioaddr, DATA_PORT, tmp); retval = -ENODEV; goto out2; } @@ -790,7 +790,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) goto out3; return 0; out3: - outw(PP_ChipID, dev->base_addr + ADD_PORT); + writeword(dev->base_addr, ADD_PORT, PP_ChipID); out2: release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: @@ -970,11 +970,11 @@ void __init reset_chip(struct net_device *dev) #ifndef CONFIG_ARCH_IXDP2X01 if (lp->chip_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ - outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT); + writeword(ioaddr, ADD_PORT, PP_CS8920_ISAINT); outb(dev->irq, ioaddr + DATA_PORT); outb(0, ioaddr + DATA_PORT + 1); - outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT); + writeword(ioaddr, ADD_PORT, PP_CS8920_ISAMemB); outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } @@ -1606,8 +1606,8 @@ net_rx(struct net_device *dev) int status, length; int ioaddr = dev->base_addr; - status = inw(ioaddr + RX_FRAME_PORT); - length = inw(ioaddr + RX_FRAME_PORT); + status = readword(ioaddr, RX_FRAME_PORT); + length = readword(ioaddr, RX_FRAME_PORT); if ((status & RX_OK) == 0) { count_rx_errors(status, lp); @@ -1628,7 +1628,7 @@ net_rx(struct net_device *dev) insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1); if (length & 1) - skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT); + skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT); if (net_debug > 3) { printk( "%s: received %d byte packet of type %x\n", @@ -1901,7 +1901,7 @@ void cleanup_module(void) { unregister_netdev(dev_cs89x0); - outw(PP_ChipID, dev_cs89x0->base_addr + ADD_PORT); + writeword(dev_cs89x0->base_addr, ADD_PORT, PP_ChipID); release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); free_netdev(dev_cs89x0); } -- cgit v1.2.3 From 0d5affcfe23ade8c4c01154e7e381e2a9a916399 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:09 -0800 Subject: [PATCH] cs89x0: swap {read,write}reg and {read,write}word Reverse the order of readreg/writereg and readword/writeword in the file, so that we can make readreg/writereg use readword/writeword. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 04fca31f1733..221f92e45ec7 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -339,29 +339,29 @@ out: #endif static int -readreg(struct net_device *dev, int portno) +readword(unsigned long base_addr, int portno) { - outw(portno, dev->base_addr + ADD_PORT); - return inw(dev->base_addr + DATA_PORT); + return inw(base_addr + portno); } static void -writereg(struct net_device *dev, int portno, int value) +writeword(unsigned long base_addr, int portno, int value) { - outw(portno, dev->base_addr + ADD_PORT); - outw(value, dev->base_addr + DATA_PORT); + outw(value, base_addr + portno); } static int -readword(unsigned long base_addr, int portno) +readreg(struct net_device *dev, int portno) { - return inw(base_addr + portno); + outw(portno, dev->base_addr + ADD_PORT); + return inw(dev->base_addr + DATA_PORT); } static void -writeword(unsigned long base_addr, int portno, int value) +writereg(struct net_device *dev, int portno, int value) { - outw(value, base_addr + portno); + outw(portno, dev->base_addr + ADD_PORT); + outw(value, dev->base_addr + DATA_PORT); } static int __init -- cgit v1.2.3 From 3eaa5e7dcce0653d2bfd2ab85a623687da49f8d5 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:10 -0800 Subject: [PATCH] cs89x0: make {read,write}reg use {read,write}word Make readreg/writereg use readword/writeword. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 221f92e45ec7..756d80adc47b 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -351,17 +351,17 @@ writeword(unsigned long base_addr, int portno, int value) } static int -readreg(struct net_device *dev, int portno) +readreg(struct net_device *dev, int regno) { - outw(portno, dev->base_addr + ADD_PORT); - return inw(dev->base_addr + DATA_PORT); + writeword(dev->base_addr, ADD_PORT, regno); + return readword(dev->base_addr, DATA_PORT); } static void -writereg(struct net_device *dev, int portno, int value) +writereg(struct net_device *dev, int regno, int value) { - outw(portno, dev->base_addr + ADD_PORT); - outw(value, dev->base_addr + DATA_PORT); + writeword(dev->base_addr, ADD_PORT, regno); + writeword(dev->base_addr, DATA_PORT, value); } static int __init -- cgit v1.2.3 From 3b68d70dffe255e7681d5725d96bc2b92a24bb9d Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:11 -0800 Subject: [PATCH] cs89x0: cleanly implement ixdp2x01 and pnx0501 support Implement suitable versions of the readword/writeword macros for ixdp2x01 and pnx0501. Handle the 32-bit spacing of the registers in these functions instead of in the header file. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 28 ++++++++++++++++++++++++++++ drivers/net/cs89x0.h | 19 ++++++------------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 756d80adc47b..7abc9f858f98 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -338,6 +338,32 @@ out: } #endif +#if defined(CONFIG_ARCH_IXDP2X01) +static int +readword(unsigned long base_addr, int portno) +{ + return (u16)__raw_readl(base_addr + (portno << 1)); +} + +static void +writeword(unsigned long base_addr, int portno, int value) +{ + __raw_writel((u16)value, base_addr + (portno << 1)); +} +#else +#if defined(CONFIG_ARCH_PNX0501) +static int +readword(unsigned long base_addr, int portno) +{ + return inw(base_addr + (portno << 1)); +} + +static void +writeword(unsigned long base_addr, int portno, int value) +{ + outw(value, base_addr + (portno << 1)); +} +#else static int readword(unsigned long base_addr, int portno) { @@ -349,6 +375,8 @@ writeword(unsigned long base_addr, int portno, int value) { outw(value, base_addr + portno); } +#endif +#endif static int readreg(struct net_device *dev, int regno) diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index decea264f121..bd954aaa636f 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -16,13 +16,6 @@ #include -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) -/* IXDP2401/IXDP2801 uses dword-aligned register addressing */ -#define CS89x0_PORT(reg) ((reg) * 2) -#else -#define CS89x0_PORT(reg) (reg) -#endif - #define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ /* offset 2h -> Model/Product Number */ /* offset 3h -> Chip Revision Number */ @@ -332,16 +325,16 @@ #define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ #define PKT_START PP_TxFrame /* Start of packet RAM */ -#define RX_FRAME_PORT CS89x0_PORT(0x0000) +#define RX_FRAME_PORT 0x0000 #define TX_FRAME_PORT RX_FRAME_PORT -#define TX_CMD_PORT CS89x0_PORT(0x0004) +#define TX_CMD_PORT 0x0004 #define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ #define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ #define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ -#define TX_LEN_PORT CS89x0_PORT(0x0006) -#define ISQ_PORT CS89x0_PORT(0x0008) -#define ADD_PORT CS89x0_PORT(0x000A) -#define DATA_PORT CS89x0_PORT(0x000C) +#define TX_LEN_PORT 0x0006 +#define ISQ_PORT 0x0008 +#define ADD_PORT 0x000A +#define DATA_PORT 0x000C #define EEPROM_WRITE_EN 0x00F0 #define EEPROM_WRITE_DIS 0x0000 -- cgit v1.2.3 From 084f746a01ca026920e388e76e913cc7a26d5a3f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:12 -0800 Subject: [PATCH] cs89x0: switch {in,out}sw to {read,write}words Implement readwords/writewords that use readword/writeword, and switch the rest of the driver over to use these. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 7abc9f858f98..f7ec590e80ea 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -378,6 +378,34 @@ writeword(unsigned long base_addr, int portno, int value) #endif #endif +static void +readwords(unsigned long base_addr, int portno, void *buf, int length) +{ + u8 *buf8 = (u8 *)buf; + + do { + u32 tmp32; + + tmp32 = readword(base_addr, portno); + *buf8++ = (u8)tmp32; + *buf8++ = (u8)(tmp32 >> 8); + } while (--length); +} + +static void +writewords(unsigned long base_addr, int portno, void *buf, int length) +{ + u8 *buf8 = (u8 *)buf; + + do { + u32 tmp32; + + tmp32 = *buf8++; + tmp32 |= (*buf8++) << 8; + writeword(base_addr, portno, tmp32); + } while (--length); +} + static int readreg(struct net_device *dev, int regno) { @@ -1143,7 +1171,7 @@ send_test_pkt(struct net_device *dev) return 0; /* this shouldn't happen */ /* Write the contents of the packet */ - outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); + writewords(dev->base_addr, TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); if (net_debug > 1) printk("Sending test packet "); /* wait a couple of jiffies for packet to be received */ @@ -1500,7 +1528,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) return 1; } /* Write the contents of the packet */ - outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); + writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); spin_unlock_irq(&lp->lock); lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; @@ -1654,7 +1682,7 @@ net_rx(struct net_device *dev) skb_reserve(skb, 2); /* longword align L3 header */ skb->dev = dev; - insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1); + readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1); if (length & 1) skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT); -- cgit v1.2.3 From 37610ff3cb63f59b89370681ff780687d8a7bed3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:13 -0800 Subject: [PATCH] fix Kconfig depends for cs89x0 (PNX010X support) PNX010X support for CS89x0 should be conditional on NET_PCI, as it is an 'on board controller' and NET_PCI includes that category of NICs. Since ARCH_PNX0105 was recently changed to ARCH_PNX010X, incorporate that change as well while we're at it. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e2fa29b612cd..1960961bf28e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1374,7 +1374,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on NET_PCI && (ISA || ARCH_IXDP2X01 || ARCH_PNX010X) ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the -- cgit v1.2.3 From 277cb103e3d7b31b8f4941b6a495b1b80236b05c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sun, 8 Jan 2006 01:01:14 -0800 Subject: [PATCH] cs89x0: fix up after pnx0105 Kconfig symbol renaming The Kconfig symbol for pnx0105 was recently renamed to ARCH_PNX010X. Signed-off-by: Lennert Buytenhek Cc: dmitry pervushin Cc: Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/cs89x0.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index f7ec590e80ea..907c01009746 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -175,7 +175,7 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0}; #include static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; -#elif defined(CONFIG_ARCH_PNX0105) +#elif defined(CONFIG_ARCH_PNX010X) #include #include #define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */ @@ -351,7 +351,7 @@ writeword(unsigned long base_addr, int portno, int value) __raw_writel((u16)value, base_addr + (portno << 1)); } #else -#if defined(CONFIG_ARCH_PNX0501) +#if defined(CONFIG_ARCH_PNX010X) static int readword(unsigned long base_addr, int portno) { @@ -512,7 +512,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) #endif } -#ifdef CONFIG_ARCH_PNX0105 +#ifdef CONFIG_ARCH_PNX010X initialize_ebi(); /* Map GPIO registers for the pins connected to the CS8900a. */ @@ -780,7 +780,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } else { i = lp->isa_config & INT_NO_MASK; if (lp->chip_type == CS8900) { -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) +#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X) i = cs8900_irq_map[0]; #else /* Translate the IRQ using the IRQ mapping table. */ @@ -1256,7 +1256,7 @@ net_open(struct net_device *dev) int i; int ret; -#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */ +#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) /* uses irq#1, so this won't work */ if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ /* Cirrus' release had this: */ @@ -1287,7 +1287,7 @@ net_open(struct net_device *dev) else #endif { -#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) +#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X) if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); @@ -1372,7 +1372,7 @@ net_open(struct net_device *dev) case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break; default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); } -#ifdef CONFIG_ARCH_PNX0105 +#ifdef CONFIG_ARCH_PNX010X result = A_CNF_10B_T; #endif if (!result) { -- cgit v1.2.3 From f3f6ec4b77f627a6427460d6f8884e1042eef134 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 8 Jan 2006 20:12:58 -0800 Subject: [CIFS] Fix cifs trying to write to f_ops patch 2ea55c01e0c5dfead8699484b0bae2a375b1f61c fixed CIFS clobbering the global fops structure for some per mount setting, by duplicating and having 2 fops structs. However the write to the fops was left behind, which is a NOP in practice (due to the fact that we KNOW the fops has that field set to NULL already due to the duplication). So remove it... In addition, another instance of the same bug was forgotten in november. Signed-off-by: Arjan van de Ven Signed-off-by: Steve French --- fs/cifs/readdir.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9bdaaecae36f..288cc048d37f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -214,8 +214,7 @@ static void fill_in_inode(struct inode *tmp_inode, tmp_inode->i_fop = &cifs_file_nobrl_ops; else tmp_inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - tmp_inode->i_fop->lock = NULL; + tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < @@ -327,12 +326,18 @@ static void unix_fill_in_inode(struct inode *tmp_inode, if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - tmp_inode->i_fop = &cifs_file_direct_ops; + + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; + else + tmp_inode->i_fop = &cifs_file_direct_ops; + + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_nobrl_ops; else tmp_inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - tmp_inode->i_fop->lock = NULL; + tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < -- cgit v1.2.3 From 88ced0314938814e1772b4d0d7ab20c52e4472b6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Dec 2005 22:43:46 +0100 Subject: [PATCH] powerpc: sanitize header files for user space includes include/asm-ppc/ had #ifdef __KERNEL__ in all header files that are not meant for use by user space, include/asm-powerpc does not have this yet. This patch gets us a lot closer there. There are a few cases where I was not sure, so I left them out. I have verified that no CONFIG_* symbols are used outside of __KERNEL__ any more and that there are no obvious compile errors when including any of the headers in user space libraries. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- include/asm-powerpc/abs_addr.h | 2 ++ include/asm-powerpc/agp.h | 2 ++ include/asm-powerpc/asm-compat.h | 3 ++- include/asm-powerpc/bootx.h | 5 +++++ include/asm-powerpc/bug.h | 2 ++ include/asm-powerpc/checksum.h | 2 ++ include/asm-powerpc/compat.h | 2 ++ include/asm-powerpc/cputable.h | 1 - include/asm-powerpc/current.h | 2 ++ include/asm-powerpc/delay.h | 2 ++ include/asm-powerpc/dma-mapping.h | 2 ++ include/asm-powerpc/dma.h | 2 ++ include/asm-powerpc/eeh.h | 2 ++ include/asm-powerpc/eeh_event.h | 2 ++ include/asm-powerpc/elf.h | 3 +++ include/asm-powerpc/floppy.h | 2 ++ include/asm-powerpc/grackle.h | 5 +++++ include/asm-powerpc/hardirq.h | 2 ++ include/asm-powerpc/heathrow.h | 5 +++++ include/asm-powerpc/hvcall.h | 2 ++ include/asm-powerpc/hvconsole.h | 2 ++ include/asm-powerpc/hvcserver.h | 2 ++ include/asm-powerpc/i8259.h | 2 ++ include/asm-powerpc/ibmebus.h | 2 ++ include/asm-powerpc/io.h | 6 +----- include/asm-powerpc/iommu.h | 2 ++ include/asm-powerpc/kdebug.h | 2 ++ include/asm-powerpc/kexec.h | 2 ++ include/asm-powerpc/keylargo.h | 5 +++++ include/asm-powerpc/kprobes.h | 2 ++ include/asm-powerpc/lmb.h | 2 ++ include/asm-powerpc/lppaca.h | 2 ++ include/asm-powerpc/macio.h | 2 ++ include/asm-powerpc/mmu.h | 2 ++ include/asm-powerpc/mmu_context.h | 2 ++ include/asm-powerpc/mmzone.h | 2 ++ include/asm-powerpc/module.h | 2 ++ include/asm-powerpc/mpic.h | 2 ++ include/asm-powerpc/numnodes.h | 2 ++ include/asm-powerpc/nvram.h | 4 ++++ include/asm-powerpc/of_device.h | 2 ++ include/asm-powerpc/ohare.h | 6 ++++++ include/asm-powerpc/oprofile_impl.h | 2 ++ include/asm-powerpc/pSeries_reconfig.h | 2 ++ include/asm-powerpc/paca.h | 2 ++ include/asm-powerpc/page_32.h | 2 ++ include/asm-powerpc/page_64.h | 2 ++ include/asm-powerpc/param.h | 2 -- include/asm-powerpc/parport.h | 2 ++ include/asm-powerpc/pci-bridge.h | 2 ++ include/asm-powerpc/pgalloc.h | 2 ++ include/asm-powerpc/pgtable-64k.h | 6 ++++++ include/asm-powerpc/pgtable.h | 2 ++ include/asm-powerpc/pmac_low_i2c.h | 2 ++ include/asm-powerpc/pmc.h | 2 ++ include/asm-powerpc/ppc-pci.h | 2 ++ include/asm-powerpc/ppc_asm.h | 3 +++ include/asm-powerpc/processor.h | 4 ++-- include/asm-powerpc/rtas.h | 2 ++ include/asm-powerpc/seccomp.h | 4 ++++ include/asm-powerpc/sections.h | 2 ++ include/asm-powerpc/signal.h | 7 +++++-- include/asm-powerpc/smu.h | 22 ++++++++++++---------- include/asm-powerpc/sparsemem.h | 2 ++ include/asm-powerpc/spinlock.h | 2 ++ include/asm-powerpc/spu.h | 3 +++ include/asm-powerpc/spu_csa.h | 3 +-- include/asm-powerpc/synch.h | 4 ++-- include/asm-powerpc/system.h | 3 +-- include/asm-powerpc/tce.h | 2 ++ include/asm-powerpc/tlb.h | 2 ++ include/asm-powerpc/topology.h | 2 ++ include/asm-powerpc/udbg.h | 2 ++ include/asm-powerpc/vdso_datapage.h | 2 ++ include/asm-powerpc/vio.h | 2 ++ 75 files changed, 183 insertions(+), 29 deletions(-) diff --git a/include/asm-powerpc/abs_addr.h b/include/asm-powerpc/abs_addr.h index 18415108fc56..c5c3259e0f86 100644 --- a/include/asm-powerpc/abs_addr.h +++ b/include/asm-powerpc/abs_addr.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_ABS_ADDR_H #define _ASM_POWERPC_ABS_ADDR_H +#ifdef __KERNEL__ #include @@ -70,4 +71,5 @@ static inline unsigned long phys_to_abs(unsigned long pa) #define iseries_hv_addr(virtaddr) \ (0x8000000000000000 | virt_to_abs(virtaddr)) +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_ABS_ADDR_H */ diff --git a/include/asm-powerpc/agp.h b/include/asm-powerpc/agp.h index 885b4631a6cf..e5ccaca2f5a4 100644 --- a/include/asm-powerpc/agp.h +++ b/include/asm-powerpc/agp.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_AGP_H #define _ASM_POWERPC_AGP_H +#ifdef __KERNEL__ #include @@ -18,4 +19,5 @@ #define free_gatt_pages(table, order) \ free_pages((unsigned long)(table), (order)) +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_AGP_H */ diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h index 8b133efc9f79..8e64be0cc47d 100644 --- a/include/asm-powerpc/asm-compat.h +++ b/include/asm-powerpc/asm-compat.h @@ -1,7 +1,6 @@ #ifndef _ASM_POWERPC_ASM_COMPAT_H #define _ASM_POWERPC_ASM_COMPAT_H -#include #include #ifdef __ASSEMBLY__ @@ -41,6 +40,7 @@ #endif +#ifdef __KERNEL__ #ifdef CONFIG_IBM405_ERR77 /* Erratum #77 on the 405 means we need a sync or dcbt before every * stwcx. The old ATOMIC_SYNC_FIX covered some but not all of this. @@ -51,5 +51,6 @@ #define PPC405_ERR77(ra,rb) #define PPC405_ERR77_SYNC #endif +#endif #endif /* _ASM_POWERPC_ASM_COMPAT_H */ diff --git a/include/asm-powerpc/bootx.h b/include/asm-powerpc/bootx.h index ed626b7cbf22..57b82e3f89ce 100644 --- a/include/asm-powerpc/bootx.h +++ b/include/asm-powerpc/bootx.h @@ -9,6 +9,8 @@ #ifndef __ASM_BOOTX_H__ #define __ASM_BOOTX_H__ +#include + #ifdef macintosh #include #include "linux_type_defs.h" @@ -122,6 +124,7 @@ typedef struct boot_infos } boot_infos_t; +#ifdef __KERNEL__ /* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index * is represented by 3 short words containing a 16 bits (unsigned) color * component. Later versions may contain the gamma table for direct-color @@ -159,6 +162,8 @@ struct bootx_dt_node { extern void bootx_init(unsigned long r4, unsigned long phys); +#endif /* __KERNEL__ */ + #ifdef macintosh #pragma options align=reset #endif diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h index b001ecb3cd99..99817a802ca4 100644 --- a/include/asm-powerpc/bug.h +++ b/include/asm-powerpc/bug.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_BUG_H #define _ASM_POWERPC_BUG_H +#ifdef __KERNEL__ #include /* @@ -67,4 +68,5 @@ struct bug_entry *find_bug(unsigned long bugaddr); #include +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_BUG_H */ diff --git a/include/asm-powerpc/checksum.h b/include/asm-powerpc/checksum.h index d8354d8a49ce..609ecbbd7210 100644 --- a/include/asm-powerpc/checksum.h +++ b/include/asm-powerpc/checksum.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_CHECKSUM_H #define _ASM_POWERPC_CHECKSUM_H +#ifdef __KERNEL__ /* * This program is free software; you can redistribute it and/or @@ -129,4 +130,5 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, } #endif +#endif /* __KERNEL__ */ #endif diff --git a/include/asm-powerpc/compat.h b/include/asm-powerpc/compat.h index 4db4360c4d4a..accb80c9a339 100644 --- a/include/asm-powerpc/compat.h +++ b/include/asm-powerpc/compat.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_COMPAT_H #define _ASM_POWERPC_COMPAT_H +#ifdef __KERNEL__ /* * Architecture specific compatibility types */ @@ -202,4 +203,5 @@ struct compat_shmid64_ds { compat_ulong_t __unused6; }; +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_COMPAT_H */ diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index 4b6f03444ffe..f4d508932467 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -1,7 +1,6 @@ #ifndef __ASM_POWERPC_CPUTABLE_H #define __ASM_POWERPC_CPUTABLE_H -#include #include #define PPC_FEATURE_32 0x80000000 diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h index 82cd4a9ca99a..1938d6abd255 100644 --- a/include/asm-powerpc/current.h +++ b/include/asm-powerpc/current.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_CURRENT_H #define _ASM_POWERPC_CURRENT_H +#ifdef __KERNEL__ /* * This program is free software; you can redistribute it and/or @@ -24,4 +25,5 @@ register struct task_struct *current asm ("r2"); #endif +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_CURRENT_H */ diff --git a/include/asm-powerpc/delay.h b/include/asm-powerpc/delay.h index 54fe1f4f8fd0..057a60955474 100644 --- a/include/asm-powerpc/delay.h +++ b/include/asm-powerpc/delay.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_DELAY_H #define _ASM_POWERPC_DELAY_H +#ifdef __KERNEL__ /* * Copyright 1996, Paul Mackerras. @@ -16,4 +17,5 @@ extern void __delay(unsigned long loops); extern void udelay(unsigned long usecs); +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_DELAY_H */ diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h index 59a80163f75f..58a25b13a5b3 100644 --- a/include/asm-powerpc/dma-mapping.h +++ b/include/asm-powerpc/dma-mapping.h @@ -6,6 +6,7 @@ */ #ifndef _ASM_DMA_MAPPING_H #define _ASM_DMA_MAPPING_H +#ifdef __KERNEL__ #include #include @@ -282,4 +283,5 @@ struct dma_mapping_ops { int (*dac_dma_supported)(struct device *dev, u64 mask); }; +#endif /* __KERNEL__ */ #endif /* _ASM_DMA_MAPPING_H */ diff --git a/include/asm-powerpc/dma.h b/include/asm-powerpc/dma.h index 926378d2cd94..4bb57fe37097 100644 --- a/include/asm-powerpc/dma.h +++ b/include/asm-powerpc/dma.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_DMA_H #define _ASM_POWERPC_DMA_H +#ifdef __KERNEL__ /* * Defines for using and allocating dma channels. @@ -387,4 +388,5 @@ extern int isa_dma_bridge_buggy; #endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_DMA_H */ diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h index e4ca35ad3338..14c9e8ab3e5f 100644 --- a/include/asm-powerpc/eeh.h +++ b/include/asm-powerpc/eeh.h @@ -19,6 +19,7 @@ #ifndef _PPC64_EEH_H #define _PPC64_EEH_H +#ifdef __KERNEL__ #include #include @@ -373,4 +374,5 @@ static inline void eeh_insl_ns(unsigned long port, void * buf, int nl) eeh_check_failure((void __iomem *)(port), *(u32*)buf); } +#endif /* __KERNEL__ */ #endif /* _PPC64_EEH_H */ diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h index d168a30b3866..5e11a00b6fa0 100644 --- a/include/asm-powerpc/eeh_event.h +++ b/include/asm-powerpc/eeh_event.h @@ -20,6 +20,7 @@ #ifndef ASM_PPC64_EEH_EVENT_H #define ASM_PPC64_EEH_EVENT_H +#ifdef __KERNEL__ /** EEH event -- structure holding pci controller data that describes * a change in the isolation status of a PCI slot. A pointer @@ -49,4 +50,5 @@ int eeh_send_failure_event (struct device_node *dn, int reset_state, int time_unavail); +#endif /* __KERNEL__ */ #endif /* ASM_PPC64_EEH_EVENT_H */ diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index 3dcd65edf978..c5a635d9bba4 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -1,7 +1,10 @@ #ifndef _ASM_POWERPC_ELF_H #define _ASM_POWERPC_ELF_H +#ifdef __KERNEL__ #include /* for task_struct */ +#endif + #include #include #include diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h index 64276a3f6153..e258778ca429 100644 --- a/include/asm-powerpc/floppy.h +++ b/include/asm-powerpc/floppy.h @@ -9,6 +9,7 @@ */ #ifndef __ASM_POWERPC_FLOPPY_H #define __ASM_POWERPC_FLOPPY_H +#ifdef __KERNEL__ #include #include @@ -102,4 +103,5 @@ static int FDC2 = -1; #define EXTRA_FLOPPY_PARAMS +#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_FLOPPY_H */ diff --git a/include/asm-powerpc/grackle.h b/include/asm-powerpc/grackle.h index 563c7a5e64c9..bd7812a519d4 100644 --- a/include/asm-powerpc/grackle.h +++ b/include/asm-powerpc/grackle.h @@ -1,3 +1,6 @@ +#ifndef _ASM_POWERPC_GRACKLE_H +#define _ASM_POWERPC_GRACKLE_H +#ifdef __KERNEL__ /* * Functions for setting up and using a MPC106 northbridge */ @@ -5,3 +8,5 @@ #include extern void setup_grackle(struct pci_controller *hose); +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_GRACKLE_H */ diff --git a/include/asm-powerpc/hardirq.h b/include/asm-powerpc/hardirq.h index 3b3e3b49ec12..288e14d53b7f 100644 --- a/include/asm-powerpc/hardirq.h +++ b/include/asm-powerpc/hardirq.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_HARDIRQ_H #define _ASM_POWERPC_HARDIRQ_H +#ifdef __KERNEL__ #include #include @@ -24,4 +25,5 @@ static inline void ack_bad_irq(int irq) BUG(); } +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HARDIRQ_H */ diff --git a/include/asm-powerpc/heathrow.h b/include/asm-powerpc/heathrow.h index 22ac179856b9..470ab7be20a2 100644 --- a/include/asm-powerpc/heathrow.h +++ b/include/asm-powerpc/heathrow.h @@ -1,3 +1,6 @@ +#ifndef _ASM_POWERPC_HEATHROW_H +#define _ASM_POWERPC_HEATHROW_H +#ifndef __KERNEL__ /* * heathrow.h: definitions for using the "Heathrow" I/O controller chip. * @@ -60,3 +63,5 @@ /* Looks like Heathrow has some sort of GPIOs as well... */ #define HRW_GPIO_MODEM_RESET 0x6d +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_HEATHROW_H */ diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h index d36da61dbc53..da7af5a720e0 100644 --- a/include/asm-powerpc/hvcall.h +++ b/include/asm-powerpc/hvcall.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_HVCALL_H #define _ASM_POWERPC_HVCALL_H +#ifdef __KERNEL__ #define HVSC .long 0x44000022 @@ -170,4 +171,5 @@ long plpar_hcall_4out(unsigned long opcode, unsigned long *out4); #endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HVCALL_H */ diff --git a/include/asm-powerpc/hvconsole.h b/include/asm-powerpc/hvconsole.h index 6da93ce74dc0..34daf7b9b62f 100644 --- a/include/asm-powerpc/hvconsole.h +++ b/include/asm-powerpc/hvconsole.h @@ -21,6 +21,7 @@ #ifndef _PPC64_HVCONSOLE_H #define _PPC64_HVCONSOLE_H +#ifdef __KERNEL__ /* * This is the max number of console adapters that can/will be found as @@ -46,4 +47,5 @@ extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, struct hv_ops *ops); /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ extern int __devexit hvc_remove(struct hvc_struct *hp); +#endif /* __KERNEL__ */ #endif /* _PPC64_HVCONSOLE_H */ diff --git a/include/asm-powerpc/hvcserver.h b/include/asm-powerpc/hvcserver.h index aecba9665796..67d7da3a4da4 100644 --- a/include/asm-powerpc/hvcserver.h +++ b/include/asm-powerpc/hvcserver.h @@ -21,6 +21,7 @@ #ifndef _PPC64_HVCSERVER_H #define _PPC64_HVCSERVER_H +#ifdef __KERNEL__ #include @@ -54,4 +55,5 @@ extern int hvcs_register_connection(uint32_t unit_address, uint32_t p_partition_ID, uint32_t p_unit_address); extern int hvcs_free_connection(uint32_t unit_address); +#endif /* __KERNEL__ */ #endif /* _PPC64_HVCSERVER_H */ diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h index fc4bfee124d7..0392159e16e4 100644 --- a/include/asm-powerpc/i8259.h +++ b/include/asm-powerpc/i8259.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_I8259_H #define _ASM_POWERPC_I8259_H +#ifdef __KERNEL__ #include @@ -9,4 +10,5 @@ extern void i8259_init(unsigned long intack_addr, int offset); extern int i8259_irq(struct pt_regs *regs); extern int i8259_irq_cascade(struct pt_regs *regs, void *unused); +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_I8259_H */ diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h index 55982b8e5b98..7a42723d107c 100644 --- a/include/asm-powerpc/ibmebus.h +++ b/include/asm-powerpc/ibmebus.h @@ -37,6 +37,7 @@ #ifndef _ASM_EBUS_H #define _ASM_EBUS_H +#ifdef __KERNEL__ #include #include @@ -80,4 +81,5 @@ static inline struct ibmebus_dev *to_ibmebus_dev(struct device *dev) } +#endif /* __KERNEL__ */ #endif /* _ASM_IBMEBUS_H */ diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index 48938d84d055..68efbea379c9 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_IO_H #define _ASM_POWERPC_IO_H +#ifdef __KERNEL__ /* * This program is free software; you can redistribute it and/or @@ -186,7 +187,6 @@ extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl); #define IO_SPACE_LIMIT ~(0UL) -#ifdef __KERNEL__ extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr, unsigned long size, unsigned long flags); extern void __iomem *__ioremap(unsigned long address, unsigned long size, @@ -256,8 +256,6 @@ static inline void * phys_to_virt(unsigned long address) */ #define BIO_VMERGE_BOUNDARY 0 -#endif /* __KERNEL__ */ - static inline void iosync(void) { __asm__ __volatile__ ("sync" : : : "memory"); @@ -405,8 +403,6 @@ static inline void out_be64(volatile unsigned long __iomem *addr, unsigned long #include #endif -#ifdef __KERNEL__ - /** * check_signature - find BIOS signatures * @io_addr: mmio address to check diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index 59f062668997..8a8393e50774 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h @@ -20,6 +20,7 @@ #ifndef _ASM_IOMMU_H #define _ASM_IOMMU_H +#ifdef __KERNEL__ #include #include @@ -115,4 +116,5 @@ static inline void pci_iommu_init(void) { } extern void alloc_dart_table(void); +#endif /* __KERNEL__ */ #endif /* _ASM_IOMMU_H */ diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h index 9dcbac674811..7c16265568e0 100644 --- a/include/asm-powerpc/kdebug.h +++ b/include/asm-powerpc/kdebug.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_KDEBUG_H #define _ASM_POWERPC_KDEBUG_H +#ifdef __KERNEL__ /* nearly identical to x86_64/i386 code */ @@ -39,4 +40,5 @@ static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,lon return notifier_call_chain(&powerpc_die_chain, val, &args); } +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KDEBUG_H */ diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h index c0f6d6b0d935..4263af3cadfd 100644 --- a/include/asm-powerpc/kexec.h +++ b/include/asm-powerpc/kexec.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_KEXEC_H #define _ASM_POWERPC_KEXEC_H +#ifdef __KERNEL__ /* * Maximum page that is mapped directly into kernel memory. @@ -58,4 +59,5 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs); #endif /* !CONFIG_KEXEC */ #endif /* ! __ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KEXEC_H */ diff --git a/include/asm-powerpc/keylargo.h b/include/asm-powerpc/keylargo.h index 334d4c9356f3..d8520ef121f9 100644 --- a/include/asm-powerpc/keylargo.h +++ b/include/asm-powerpc/keylargo.h @@ -1,3 +1,6 @@ +#ifndef _ASM_POWERPC_KEYLARGO_H +#define _ASM_POWERPC_KEYLARGO_H +#ifdef __KERNEL__ /* * keylargo.h: definitions for using the "KeyLargo" I/O controller chip. * @@ -254,3 +257,5 @@ #define SH_FCR1_I2S2_ENABLE 0x00000080 #define SH_FCR3_I2S2_CLK18_ENABLE 0x00008000 +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_KEYLARGO_H */ diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index 6cd0a3bfa280..0654f79b06df 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_KPROBES_H #define _ASM_POWERPC_KPROBES_H +#ifdef __KERNEL__ /* * Kernel Probes (KProbes) * @@ -78,4 +79,5 @@ static inline int kprobe_exceptions_notify(struct notifier_block *self, return 0; } #endif +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_KPROBES_H */ diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h index ea0afe343545..d3546c4c9f46 100644 --- a/include/asm-powerpc/lmb.h +++ b/include/asm-powerpc/lmb.h @@ -1,5 +1,6 @@ #ifndef _PPC64_LMB_H #define _PPC64_LMB_H +#ifdef __KERNEL__ /* * Definitions for talking to the Open Firmware PROM on @@ -78,4 +79,5 @@ lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) lmb_size_pages(type, region_nr); } +#endif /* __KERNEL__ */ #endif /* _PPC64_LMB_H */ diff --git a/include/asm-powerpc/lppaca.h b/include/asm-powerpc/lppaca.h index c1bedab1515b..ff82ea7c4829 100644 --- a/include/asm-powerpc/lppaca.h +++ b/include/asm-powerpc/lppaca.h @@ -18,6 +18,7 @@ */ #ifndef _ASM_POWERPC_LPPACA_H #define _ASM_POWERPC_LPPACA_H +#ifdef __KERNEL__ //============================================================================= // @@ -128,4 +129,5 @@ struct lppaca { u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF }; +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_LPPACA_H */ diff --git a/include/asm-powerpc/macio.h b/include/asm-powerpc/macio.h index b553dd4b139e..3a6cb1a513b7 100644 --- a/include/asm-powerpc/macio.h +++ b/include/asm-powerpc/macio.h @@ -1,5 +1,6 @@ #ifndef __MACIO_ASIC_H__ #define __MACIO_ASIC_H__ +#ifdef __KERNEL__ #include @@ -137,4 +138,5 @@ struct macio_driver extern int macio_register_driver(struct macio_driver *); extern void macio_unregister_driver(struct macio_driver *); +#endif /* __KERNEL__ */ #endif /* __MACIO_ASIC_H__ */ diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index 0a7323f0083b..d096d9e76ad7 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_MMU_H_ #define _ASM_POWERPC_MMU_H_ +#ifdef __KERNEL__ #ifndef CONFIG_PPC64 #include @@ -402,4 +403,5 @@ typedef unsigned long phys_addr_t; #endif /* __ASSEMBLY */ #endif /* CONFIG_PPC64 */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MMU_H_ */ diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h index ea6798c7d5fc..1b8a25fd48f3 100644 --- a/include/asm-powerpc/mmu_context.h +++ b/include/asm-powerpc/mmu_context.h @@ -1,5 +1,6 @@ #ifndef __ASM_POWERPC_MMU_CONTEXT_H #define __ASM_POWERPC_MMU_CONTEXT_H +#ifdef __KERNEL__ #ifndef CONFIG_PPC64 #include @@ -86,4 +87,5 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) } #endif /* CONFIG_PPC64 */ +#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_MMU_CONTEXT_H */ diff --git a/include/asm-powerpc/mmzone.h b/include/asm-powerpc/mmzone.h index 54958d6cae04..88d70bae7769 100644 --- a/include/asm-powerpc/mmzone.h +++ b/include/asm-powerpc/mmzone.h @@ -6,6 +6,7 @@ */ #ifndef _ASM_MMZONE_H_ #define _ASM_MMZONE_H_ +#ifdef __KERNEL__ #include @@ -47,4 +48,5 @@ extern unsigned long max_pfn; extern int __init early_pfn_to_nid(unsigned long pfn); #endif +#endif /* __KERNEL__ */ #endif /* _ASM_MMZONE_H_ */ diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h index 7ecd05e03051..584fabfb4f08 100644 --- a/include/asm-powerpc/module.h +++ b/include/asm-powerpc/module.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_MODULE_H #define _ASM_POWERPC_MODULE_H +#ifdef __KERNEL__ /* * This program is free software; you can redistribute it and/or @@ -74,4 +75,5 @@ struct exception_table_entry; void sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish); +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MODULE_H */ diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index bf7e71793205..6b9e78142f4f 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_MPIC_H #define _ASM_POWERPC_MPIC_H +#ifdef __KERNEL__ #include @@ -286,4 +287,5 @@ extern int mpic_get_irq(struct pt_regs *regs); /* global mpic for pSeries */ extern struct mpic *pSeries_mpic; +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MPIC_H */ diff --git a/include/asm-powerpc/numnodes.h b/include/asm-powerpc/numnodes.h index 795533aca095..e138edae09dd 100644 --- a/include/asm-powerpc/numnodes.h +++ b/include/asm-powerpc/numnodes.h @@ -1,7 +1,9 @@ #ifndef _ASM_POWERPC_MAX_NUMNODES_H #define _ASM_POWERPC_MAX_NUMNODES_H +#ifdef __KERNEL__ /* Max 16 Nodes */ #define NODES_SHIFT 4 +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MAX_NUMNODES_H */ diff --git a/include/asm-powerpc/nvram.h b/include/asm-powerpc/nvram.h index 24bd8c2388ea..f3563e11e260 100644 --- a/include/asm-powerpc/nvram.h +++ b/include/asm-powerpc/nvram.h @@ -55,6 +55,7 @@ struct nvram_header { char name[12]; }; +#ifdef __KERNEL__ struct nvram_partition { struct list_head partition; struct nvram_header header; @@ -69,6 +70,7 @@ extern struct nvram_partition *nvram_find_partition(int sig, const char *name); extern int pSeries_nvram_init(void); extern int mmio_nvram_init(void); +#endif /* __KERNEL__ */ /* PowerMac specific nvram stuffs */ @@ -78,6 +80,7 @@ enum { pmac_nvram_NR /* MacOS Name Registry partition */ }; +#ifdef __KERNEL__ /* Return partition offset in nvram */ extern int pmac_get_partition(int partition); @@ -91,6 +94,7 @@ extern void nvram_sync(void); /* Normal access to NVRAM */ extern unsigned char nvram_read_byte(int i); extern void nvram_write_byte(unsigned char c, int i); +#endif /* Some offsets in XPRAM */ #define PMAC_XPRAM_MACHINE_LOC 0xe4 diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h index ddb16aae0bd6..6249a7c39639 100644 --- a/include/asm-powerpc/of_device.h +++ b/include/asm-powerpc/of_device.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_OF_DEVICE_H #define _ASM_POWERPC_OF_DEVICE_H +#ifdef __KERNEL__ #include #include @@ -61,4 +62,5 @@ extern struct of_device *of_platform_device_create(struct device_node *np, struct device *parent); extern void of_release_dev(struct device *dev); +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_OF_DEVICE_H */ diff --git a/include/asm-powerpc/ohare.h b/include/asm-powerpc/ohare.h index 023b59772231..b42037cf4ad0 100644 --- a/include/asm-powerpc/ohare.h +++ b/include/asm-powerpc/ohare.h @@ -1,3 +1,6 @@ +#ifndef _ASM_POWERPC_OHARE_H +#define _ASM_POWERPC_OHARE_H +#ifndef __KERNEL__ /* * ohare.h: definitions for using the "O'Hare" I/O controller chip. * @@ -46,3 +49,6 @@ * Contributed by Harry Eaton. */ #define STARMAX_FEATURES 0xbeff7a + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_OHARE_H */ diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h index b48d35e40172..338e6a7cff4a 100644 --- a/include/asm-powerpc/oprofile_impl.h +++ b/include/asm-powerpc/oprofile_impl.h @@ -11,6 +11,7 @@ #ifndef _ASM_POWERPC_OPROFILE_IMPL_H #define _ASM_POWERPC_OPROFILE_IMPL_H +#ifdef __KERNEL__ #define OP_MAX_COUNTER 8 @@ -133,4 +134,5 @@ static inline void ctr_write(unsigned int i, unsigned int val) } #endif /* !CONFIG_FSL_BOOKE */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_OPROFILE_IMPL_H */ diff --git a/include/asm-powerpc/pSeries_reconfig.h b/include/asm-powerpc/pSeries_reconfig.h index c0db1ea7f7d1..ea6cfb8efb84 100644 --- a/include/asm-powerpc/pSeries_reconfig.h +++ b/include/asm-powerpc/pSeries_reconfig.h @@ -1,5 +1,6 @@ #ifndef _PPC64_PSERIES_RECONFIG_H #define _PPC64_PSERIES_RECONFIG_H +#ifdef __KERNEL__ #include @@ -22,4 +23,5 @@ static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } #endif /* CONFIG_PPC_PSERIES */ +#endif /* __KERNEL__ */ #endif /* _PPC64_PSERIES_RECONFIG_H */ diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index 59a41dbbf73c..3ae52d9dc9ff 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -14,6 +14,7 @@ */ #ifndef _ASM_POWERPC_PACA_H #define _ASM_POWERPC_PACA_H +#ifdef __KERNEL__ #include #include @@ -110,4 +111,5 @@ struct paca_struct { extern struct paca_struct paca[]; +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PACA_H */ diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h index 7259cfd85da9..2677bad70f40 100644 --- a/include/asm-powerpc/page_32.h +++ b/include/asm-powerpc/page_32.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_PAGE_32_H #define _ASM_POWERPC_PAGE_32_H +#ifdef __KERNEL__ #define VM_DATA_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS32 @@ -37,4 +38,5 @@ extern __inline__ int get_order(unsigned long size) #endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PAGE_32_H */ diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h index 8a07a93b0321..3fb061bab9ec 100644 --- a/include/asm-powerpc/page_64.h +++ b/include/asm-powerpc/page_64.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_PAGE_64_H #define _ASM_POWERPC_PAGE_64_H +#ifdef __KERNEL__ /* * Copyright (C) 2001 PPC64 Team, IBM Corp @@ -170,4 +171,5 @@ extern unsigned int HPAGE_SHIFT; #include +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PAGE_64_H */ diff --git a/include/asm-powerpc/param.h b/include/asm-powerpc/param.h index bdc724f70884..094f63d4d5ca 100644 --- a/include/asm-powerpc/param.h +++ b/include/asm-powerpc/param.h @@ -1,8 +1,6 @@ #ifndef _ASM_POWERPC_PARAM_H #define _ASM_POWERPC_PARAM_H -#include - #ifdef __KERNEL__ #define HZ CONFIG_HZ /* internal kernel timer frequency */ #define USER_HZ 100 /* for user interfaces in "ticks" */ diff --git a/include/asm-powerpc/parport.h b/include/asm-powerpc/parport.h index d86b410a6f8b..897e49a88a6b 100644 --- a/include/asm-powerpc/parport.h +++ b/include/asm-powerpc/parport.h @@ -8,6 +8,7 @@ #ifndef _ASM_POWERPC_PARPORT_H #define _ASM_POWERPC_PARPORT_H +#ifdef __KERNEL__ static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma); static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) @@ -15,4 +16,5 @@ static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) return parport_pc_find_isa_ports (autoirq, autodma); } +#endif /* __KERNEL__ */ #endif /* !(_ASM_POWERPC_PARPORT_H) */ diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 443c75a16571..1a08860e789e 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_PCI_BRIDGE_H #define _ASM_POWERPC_PCI_BRIDGE_H +#ifdef __KERNEL__ #ifndef CONFIG_PPC64 #include @@ -172,4 +173,5 @@ static inline unsigned long pci_address_to_pio(phys_addr_t address) #define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */ #endif /* CONFIG_PPC64 */ +#endif /* __KERNEL__ */ #endif diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h index bfc2113b3630..9f5b052784a5 100644 --- a/include/asm-powerpc/pgalloc.h +++ b/include/asm-powerpc/pgalloc.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_PGALLOC_H #define _ASM_POWERPC_PGALLOC_H +#ifdef __KERNEL__ #ifndef CONFIG_PPC64 #include @@ -153,4 +154,5 @@ extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); #define check_pgt_cache() do { } while (0) #endif /* CONFIG_PPC64 */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PGALLOC_H */ diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h index 154f1840ece4..653915014dcd 100644 --- a/include/asm-powerpc/pgtable-64k.h +++ b/include/asm-powerpc/pgtable-64k.h @@ -1,3 +1,7 @@ +#ifndef _ASM_POWERPC_PGTABLE_64K_H +#define _ASM_POWERPC_PGTABLE_64K_H +#ifdef __KERNEL__ + #include @@ -88,3 +92,5 @@ #endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_PGTABLE_64K_H */ diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h index 3518adb2cc18..e38931379a72 100644 --- a/include/asm-powerpc/pgtable.h +++ b/include/asm-powerpc/pgtable.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_PGTABLE_H #define _ASM_POWERPC_PGTABLE_H +#ifdef __KERNEL__ #ifndef CONFIG_PPC64 #include @@ -532,4 +533,5 @@ void pgtable_cache_init(void); #endif /* __ASSEMBLY__ */ #endif /* CONFIG_PPC64 */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PGTABLE_H */ diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h index 809a5963d5e7..3fb8d51540dd 100644 --- a/include/asm-powerpc/pmac_low_i2c.h +++ b/include/asm-powerpc/pmac_low_i2c.h @@ -11,6 +11,7 @@ */ #ifndef __PMAC_LOW_I2C_H__ #define __PMAC_LOW_I2C_H__ +#ifdef __KERNEL__ /* i2c mode (based on the platform functions format) */ enum { @@ -40,4 +41,5 @@ int pmac_low_i2c_setmode(struct device_node *np, int mode); int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len); +#endif /* __KERNEL__ */ #endif /* __PMAC_LOW_I2C_H__ */ diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h index 5f41f3a2b293..07d6a4279319 100644 --- a/include/asm-powerpc/pmc.h +++ b/include/asm-powerpc/pmc.h @@ -18,6 +18,7 @@ */ #ifndef _POWERPC_PMC_H #define _POWERPC_PMC_H +#ifdef __KERNEL__ #include @@ -44,4 +45,5 @@ void dump_pmcs(void); extern struct op_powerpc_model op_model_fsl_booke; #endif +#endif /* __KERNEL__ */ #endif /* _POWERPC_PMC_H */ diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h index 36cdc869e580..bdef312900a1 100644 --- a/include/asm-powerpc/ppc-pci.h +++ b/include/asm-powerpc/ppc-pci.h @@ -8,6 +8,7 @@ */ #ifndef _ASM_POWERPC_PPC_PCI_H #define _ASM_POWERPC_PPC_PCI_H +#ifdef __KERNEL__ #include #include @@ -93,4 +94,5 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag); #endif +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_PPC_PCI_H */ diff --git a/include/asm-powerpc/ppc_asm.h b/include/asm-powerpc/ppc_asm.h index c27baa0563fe..0dc798d46ea4 100644 --- a/include/asm-powerpc/ppc_asm.h +++ b/include/asm-powerpc/ppc_asm.h @@ -94,6 +94,7 @@ #define RFDI .long 0x4c00004e /* rfdi instruction */ #define RFMCI .long 0x4c00004c /* rfmci instruction */ +#ifdef __KERNEL__ #ifdef CONFIG_PPC64 #define XGLUE(a,b) a##b @@ -325,6 +326,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define CLR_TOP32(r) #endif +#endif /* __KERNEL__ */ + /* The boring bits... */ /* Condition Register Bit Fields */ diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index f3db98454c4d..415fa393b00c 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h @@ -10,7 +10,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #ifndef __ASSEMBLY__ @@ -50,6 +49,7 @@ #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ #define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */ +#ifdef __KERNEL__ #define platform_is_pseries() (_machine == PLATFORM_PSERIES || \ _machine == PLATFORM_PSERIES_LPAR) #define platform_is_lpar() (!!(_machine & PLATFORM_LPAR)) @@ -81,7 +81,7 @@ extern unsigned char ucBoardRevMaj, ucBoardRevMin; #else #define _machine 0 #endif /* CONFIG_PPC_MULTIPLATFORM */ - +#endif /* __KERNEL__ */ /* * Default implementation of macro that returns current * instruction pointer ("program counter"). diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h index d1bb611ea626..3428889e27b7 100644 --- a/include/asm-powerpc/rtas.h +++ b/include/asm-powerpc/rtas.h @@ -1,5 +1,6 @@ #ifndef _POWERPC_RTAS_H #define _POWERPC_RTAS_H +#ifdef __KERNEL__ #include #include @@ -229,4 +230,5 @@ extern unsigned long rtas_rmo_buf; #define GLOBAL_INTERRUPT_QUEUE 9005 +#endif /* __KERNEL__ */ #endif /* _POWERPC_RTAS_H */ diff --git a/include/asm-powerpc/seccomp.h b/include/asm-powerpc/seccomp.h index 1e1cfe12882b..cc8137b77b90 100644 --- a/include/asm-powerpc/seccomp.h +++ b/include/asm-powerpc/seccomp.h @@ -1,6 +1,10 @@ #ifndef _ASM_POWERPC_SECCOMP_H +#define _ASM_POWERPC_SECCOMP_H +#ifndef __KERNEL__ #include +#endif + #include #define __NR_seccomp_read __NR_read diff --git a/include/asm-powerpc/sections.h b/include/asm-powerpc/sections.h index 47be2ac2a925..916018e425c4 100644 --- a/include/asm-powerpc/sections.h +++ b/include/asm-powerpc/sections.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_SECTIONS_H #define _ASM_POWERPC_SECTIONS_H +#ifdef __KERNEL__ #include @@ -17,4 +18,5 @@ static inline int in_kernel_text(unsigned long addr) #endif +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SECTIONS_H */ diff --git a/include/asm-powerpc/signal.h b/include/asm-powerpc/signal.h index 694c8d2dab87..a4d8f8648541 100644 --- a/include/asm-powerpc/signal.h +++ b/include/asm-powerpc/signal.h @@ -2,10 +2,13 @@ #define _ASM_POWERPC_SIGNAL_H #include -#include #define _NSIG 64 -#define _NSIG_BPW BITS_PER_LONG +#ifdef __powerpc64__ +#define _NSIG_BPW 64 +#else +#define _NSIG_BPW 32 +#endif #define _NSIG_WORDS (_NSIG / _NSIG_BPW) typedef unsigned long old_sigset_t; /* at least 32 bits */ diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h index 76c29a9784dd..7fae3ce9a8c1 100644 --- a/include/asm-powerpc/smu.h +++ b/include/asm-powerpc/smu.h @@ -4,9 +4,11 @@ /* * Definitions for talking to the SMU chip in newer G5 PowerMacs */ - +#ifdef __KERNEL__ #include #include +#endif +#include /* * Known SMU commands @@ -487,8 +489,8 @@ struct smu_sdbp_slotspow { #define SMU_SDB_SENSORTREE_ID 0x25 struct smu_sdbp_sensortree { - u8 model_id; - u8 unknown[3]; + __u8 model_id; + __u8 unknown[3]; }; /* This partition contains CPU thermal control PID informations. So far @@ -498,13 +500,13 @@ struct smu_sdbp_sensortree { #define SMU_SDB_CPUPIDDATA_ID 0x17 struct smu_sdbp_cpupiddata { - u8 unknown1; - u8 target_temp_delta; - u8 unknown2; - u8 history_len; - s16 power_adj; - u16 max_power; - s32 gp,gr,gd; + __u8 unknown1; + __u8 target_temp_delta; + __u8 unknown2; + __u8 history_len; + __s16 power_adj; + __u16 max_power; + __s32 gp,gr,gd; }; diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h index c3f17d442f7d..38b1ea3b58fd 100644 --- a/include/asm-powerpc/sparsemem.h +++ b/include/asm-powerpc/sparsemem.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_SPARSEMEM_H #define _ASM_POWERPC_SPARSEMEM_H 1 +#ifdef __KERNEL__ #ifdef CONFIG_SPARSEMEM /* @@ -25,4 +26,5 @@ static inline int hot_add_scn_to_nid(unsigned long scn_addr) #endif /* CONFIG_SPARSEMEM */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SPARSEMEM_H */ diff --git a/include/asm-powerpc/spinlock.h b/include/asm-powerpc/spinlock.h index caa4b14e0e94..754900901cd8 100644 --- a/include/asm-powerpc/spinlock.h +++ b/include/asm-powerpc/spinlock.h @@ -1,5 +1,6 @@ #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H +#ifdef __KERNEL__ /* * Simple spin lock operations. @@ -266,4 +267,5 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) rw->lock = 0; } +#endif /* __KERNEL__ */ #endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 698c4cb08c60..ee337e37195c 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -22,6 +22,8 @@ #ifndef _SPU_H #define _SPU_H +#ifdef __KERNEL__ + #include #include #include @@ -578,4 +580,5 @@ struct spu_priv1 { u64 spu_trace_cntl; /* 0x1070 */ } __attribute__ ((aligned(0x2000))); +#endif /* __KERNEL__ */ #endif diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h index 2a8af416638f..ba18d7d4dde2 100644 --- a/include/asm-powerpc/spu_csa.h +++ b/include/asm-powerpc/spu_csa.h @@ -22,6 +22,7 @@ #ifndef _SPU_CSA_H_ #define _SPU_CSA_H_ +#ifdef __KERNEL__ /* * Total number of 128-bit registers. @@ -89,8 +90,6 @@ struct spu_lscsa { unsigned char ls[LS_SIZE]; }; -#ifdef __KERNEL__ - /* * struct spu_problem_collapsed - condensed problem state area, w/o pads. */ diff --git a/include/asm-powerpc/synch.h b/include/asm-powerpc/synch.h index 4660c0394a77..794870ab8fd3 100644 --- a/include/asm-powerpc/synch.h +++ b/include/asm-powerpc/synch.h @@ -1,7 +1,6 @@ #ifndef _ASM_POWERPC_SYNCH_H #define _ASM_POWERPC_SYNCH_H - -#include +#ifdef __KERNEL__ #ifdef __powerpc64__ #define __SUBARCH_HAS_LWSYNC @@ -47,5 +46,6 @@ static inline void isync(void) #define isync_on_smp() __asm__ __volatile__("": : :"memory") #endif +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SYNCH_H */ diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 5341b75c75cb..0c58e32a9570 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -4,7 +4,6 @@ #ifndef _ASM_POWERPC_SYSTEM_H #define _ASM_POWERPC_SYSTEM_H -#include #include #include @@ -42,6 +41,7 @@ #define set_mb(var, value) do { var = value; mb(); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) +#ifdef __KERNEL__ #ifdef CONFIG_SMP #define smp_mb() mb() #define smp_rmb() rmb() @@ -54,7 +54,6 @@ #define smp_read_barrier_depends() do { } while(0) #endif /* CONFIG_SMP */ -#ifdef __KERNEL__ struct task_struct; struct pt_regs; diff --git a/include/asm-powerpc/tce.h b/include/asm-powerpc/tce.h index 980a094fd5a7..6fa200ad7a7f 100644 --- a/include/asm-powerpc/tce.h +++ b/include/asm-powerpc/tce.h @@ -20,6 +20,7 @@ #ifndef _ASM_POWERPC_TCE_H #define _ASM_POWERPC_TCE_H +#ifdef __KERNEL__ /* * Tces come in two formats, one for the virtual bus and a different @@ -61,4 +62,5 @@ union tce_entry { }; +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_TCE_H */ diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h index 56659f121779..601a53cf96d5 100644 --- a/include/asm-powerpc/tlb.h +++ b/include/asm-powerpc/tlb.h @@ -11,6 +11,7 @@ */ #ifndef _ASM_POWERPC_TLB_H #define _ASM_POWERPC_TLB_H +#ifdef __KERNEL__ #include #ifndef __powerpc64__ @@ -67,4 +68,5 @@ static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, } #endif +#endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_TLB_H */ diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h index f8a130af7d09..9f3d4da261c4 100644 --- a/include/asm-powerpc/topology.h +++ b/include/asm-powerpc/topology.h @@ -1,5 +1,6 @@ #ifndef _ASM_POWERPC_TOPOLOGY_H #define _ASM_POWERPC_TOPOLOGY_H +#ifdef __KERNEL__ #include @@ -65,4 +66,5 @@ static inline void dump_numa_cpu_topology(void) {} #endif /* CONFIG_NUMA */ +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_TOPOLOGY_H */ diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index 58cdc883e38c..6c8abc924b28 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -9,6 +9,7 @@ #ifndef _ASM_POWERPC_UDBG_H #define _ASM_POWERPC_UDBG_H +#ifdef __KERNEL__ #include #include @@ -34,4 +35,5 @@ extern void udbg_scc_init(int force_scc); extern int udbg_adb_init(int force_btext); extern void udbg_adb_init_early(void); +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/include/asm-powerpc/vdso_datapage.h b/include/asm-powerpc/vdso_datapage.h index 411832d5bbdb..7aa92086c3fb 100644 --- a/include/asm-powerpc/vdso_datapage.h +++ b/include/asm-powerpc/vdso_datapage.h @@ -1,5 +1,6 @@ #ifndef _VDSO_DATAPAGE_H #define _VDSO_DATAPAGE_H +#ifdef __KERNEL__ /* * Copyright (C) 2002 Peter Bergner , IBM @@ -105,4 +106,5 @@ extern struct vdso_data *vdso_data; #endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _SYSTEMCFG_H */ diff --git a/include/asm-powerpc/vio.h b/include/asm-powerpc/vio.h index e0ccf108277c..0544ece51761 100644 --- a/include/asm-powerpc/vio.h +++ b/include/asm-powerpc/vio.h @@ -13,6 +13,7 @@ #ifndef _ASM_POWERPC_VIO_H #define _ASM_POWERPC_VIO_H +#ifdef __KERNEL__ #include #include @@ -103,4 +104,5 @@ static inline struct vio_dev *to_vio_dev(struct device *dev) return container_of(dev, struct vio_dev, dev); } +#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_VIO_H */ -- cgit v1.2.3 From 2919b51075b3906c2f476e5a932244af1947bf80 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:16 -0800 Subject: [PATCH] frv: suppress configuration of certain features for FRV Suppress configuration of certain features for the FRV arch as they can't be built for FRV at the moment: (*) RTC (*) HISAX_* (*) PARPORT_PC (*) VGA_CONSOLE (*) BINFMT_ELF Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 4 ++-- drivers/isdn/hisax/Kconfig | 10 +++++----- drivers/parport/Kconfig | 2 +- drivers/video/console/Kconfig | 2 +- fs/Kconfig.binfmt | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 5ebd06b1b4ca..b1b34edcd70c 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -687,7 +687,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) + depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -735,7 +735,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC + depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index c82105920d71..0ef560144be3 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -110,7 +110,7 @@ config HISAX_16_3 config HISAX_TELESPCI bool "Teles PCI" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Teles PCI. See on how to configure it. @@ -238,7 +238,7 @@ config HISAX_MIC config HISAX_NETJET bool "NETjet card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the NetJet from Traverse Technologies. @@ -249,7 +249,7 @@ config HISAX_NETJET config HISAX_NETJET_U bool "NETspider U card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Netspider U interface ISDN card from Traverse Technologies. @@ -317,7 +317,7 @@ config HISAX_GAZEL config HISAX_HFC_PCI bool "HFC PCI-Bus cards" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the HFC-S PCI 2BDS0 based cards. @@ -344,7 +344,7 @@ config HISAX_HFC_SX config HISAX_ENTERNOW_PCI bool "Formula-n enter:now PCI card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Formula-n enter:now PCI ISDN card. diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index b8241561da45..a665951b1586 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -34,7 +34,7 @@ config PARPORT config PARPORT_PC tristate "PC-style hardware" - depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R + depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index a5d09e159cd1..6ee449858a5c 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !ARCH_VERSATILE + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 175b2e8177c1..f3d3d81eb7e9 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -1,6 +1,6 @@ config BINFMT_ELF bool "Kernel support for ELF binaries" - depends on MMU + depends on MMU && (BROKEN || !FRV) default y ---help--- ELF (Executable and Linkable Format) is a format for libraries and -- cgit v1.2.3 From 2fa9e7e2dce6aafecc1890461bdc00d78897be8b Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:17 -0800 Subject: [PATCH] frv: drop 8/16-bit xchg and cmpxchg Drop support for 8-bit and 16-bit xchg and cmpxchg emulation and implements 32-bit xchg with the SWAP/SWAPI instruction. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/lib/atomic-ops.S | 92 --------------------------------------------- include/asm-frv/atomic.h | 96 +++-------------------------------------------- 2 files changed, 5 insertions(+), 183 deletions(-) diff --git a/arch/frv/lib/atomic-ops.S b/arch/frv/lib/atomic-ops.S index b03d510a89e4..545cd325ac57 100644 --- a/arch/frv/lib/atomic-ops.S +++ b/arch/frv/lib/atomic-ops.S @@ -127,48 +127,6 @@ atomic_sub_return: .size atomic_sub_return, .-atomic_sub_return -############################################################################### -# -# uint8_t __xchg_8(uint8_t i, uint8_t *v) -# -############################################################################### - .globl __xchg_8 - .type __xchg_8,@function -__xchg_8: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ldub.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - cstb.p gr10,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size __xchg_8, .-__xchg_8 - -############################################################################### -# -# uint16_t __xchg_16(uint16_t i, uint16_t *v) -# -############################################################################### - .globl __xchg_16 - .type __xchg_16,@function -__xchg_16: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - lduh.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - csth.p gr10,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size __xchg_16, .-__xchg_16 - ############################################################################### # # uint32_t __xchg_32(uint32_t i, uint32_t *v) @@ -190,56 +148,6 @@ __xchg_32: .size __xchg_32, .-__xchg_32 -############################################################################### -# -# uint8_t __cmpxchg_8(uint8_t *v, uint8_t test, uint8_t new) -# -############################################################################### - .globl __cmpxchg_8 - .type __cmpxchg_8,@function -__cmpxchg_8: - or.p gr8,gr8,gr11 -0: - orcc gr0,gr0,gr0,icc3 - ckeq icc3,cc7 - ldub.p @(gr11,gr0),gr8 - orcr cc7,cc7,cc3 - sub gr8,gr9,gr7 - sllicc gr7,#24,gr0,icc0 - bne icc0,#0,1f - cstb.p gr10,@(gr11,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 - beq icc3,#0,0b -1: - bralr - - .size __cmpxchg_8, .-__cmpxchg_8 - -############################################################################### -# -# uint16_t __cmpxchg_16(uint16_t *v, uint16_t test, uint16_t new) -# -############################################################################### - .globl __cmpxchg_16 - .type __cmpxchg_16,@function -__cmpxchg_16: - or.p gr8,gr8,gr11 -0: - orcc gr0,gr0,gr0,icc3 - ckeq icc3,cc7 - lduh.p @(gr11,gr0),gr8 - orcr cc7,cc7,cc3 - sub gr8,gr9,gr7 - sllicc gr7,#16,gr0,icc0 - bne icc0,#0,1f - csth.p gr10,@(gr11,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 - beq icc3,#0,0b -1: - bralr - - .size __cmpxchg_16, .-__cmpxchg_16 - ############################################################################### # # uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new) diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h index 3f54fea2b051..9c9e9499cfd8 100644 --- a/include/asm-frv/atomic.h +++ b/include/asm-frv/atomic.h @@ -218,51 +218,12 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig __typeof__(*(ptr)) __xg_orig; \ \ switch (sizeof(__xg_orig)) { \ - case 1: \ - asm volatile( \ - "0: \n" \ - " orcc gr0,gr0,gr0,icc3 \n" \ - " ckeq icc3,cc7 \n" \ - " ldub.p %M0,%1 \n" \ - " orcr cc7,cc7,cc3 \n" \ - " cstb.p %2,%M0 ,cc3,#1 \n" \ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ - " beq icc3,#0,0b \n" \ - : "+U"(*__xg_ptr), "=&r"(__xg_orig) \ - : "r"(x) \ - : "memory", "cc7", "cc3", "icc3" \ - ); \ - break; \ - \ - case 2: \ - asm volatile( \ - "0: \n" \ - " orcc gr0,gr0,gr0,icc3 \n" \ - " ckeq icc3,cc7 \n" \ - " lduh.p %M0,%1 \n" \ - " orcr cc7,cc7,cc3 \n" \ - " csth.p %2,%M0 ,cc3,#1 \n" \ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ - " beq icc3,#0,0b \n" \ - : "+U"(*__xg_ptr), "=&r"(__xg_orig) \ - : "r"(x) \ - : "memory", "cc7", "cc3", "icc3" \ - ); \ - break; \ - \ case 4: \ asm volatile( \ - "0: \n" \ - " orcc gr0,gr0,gr0,icc3 \n" \ - " ckeq icc3,cc7 \n" \ - " ld.p %M0,%1 \n" \ - " orcr cc7,cc7,cc3 \n" \ - " cst.p %2,%M0 ,cc3,#1 \n" \ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ - " beq icc3,#0,0b \n" \ - : "+U"(*__xg_ptr), "=&r"(__xg_orig) \ + "swap%I0 %2,%M0" \ + : "+m"(*__xg_ptr), "=&r"(__xg_orig) \ : "r"(x) \ - : "memory", "cc7", "cc3", "icc3" \ + : "memory" \ ); \ break; \ \ @@ -277,8 +238,6 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig #else -extern uint8_t __xchg_8 (uint8_t i, volatile void *v); -extern uint16_t __xchg_16(uint16_t i, volatile void *v); extern uint32_t __xchg_32(uint32_t i, volatile void *v); #define xchg(ptr, x) \ @@ -287,8 +246,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v); __typeof__(*(ptr)) __xg_orig; \ \ switch (sizeof(__xg_orig)) { \ - case 1: __xg_orig = (__typeof__(*(ptr))) __xchg_8 ((uint8_t) x, __xg_ptr); break; \ - case 2: __xg_orig = (__typeof__(*(ptr))) __xchg_16((uint16_t) x, __xg_ptr); break; \ case 4: __xg_orig = (__typeof__(*(ptr))) __xchg_32((uint32_t) x, __xg_ptr); break; \ default: \ __xg_orig = 0; \ @@ -318,46 +275,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v); __typeof__(*(ptr)) __xg_new = (new); \ \ switch (sizeof(__xg_orig)) { \ - case 1: \ - asm volatile( \ - "0: \n" \ - " orcc gr0,gr0,gr0,icc3 \n" \ - " ckeq icc3,cc7 \n" \ - " ldub.p %M0,%1 \n" \ - " orcr cc7,cc7,cc3 \n" \ - " sub%I4 %1,%4,%2 \n" \ - " sllcc %2,#24,gr0,icc0 \n" \ - " bne icc0,#0,1f \n" \ - " cstb.p %3,%M0 ,cc3,#1 \n" \ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ - " beq icc3,#0,0b \n" \ - "1: \n" \ - : "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp) \ - : "r"(__xg_new), "NPr"(__xg_test) \ - : "memory", "cc7", "cc3", "icc3", "icc0" \ - ); \ - break; \ - \ - case 2: \ - asm volatile( \ - "0: \n" \ - " orcc gr0,gr0,gr0,icc3 \n" \ - " ckeq icc3,cc7 \n" \ - " lduh.p %M0,%1 \n" \ - " orcr cc7,cc7,cc3 \n" \ - " sub%I4 %1,%4,%2 \n" \ - " sllcc %2,#16,gr0,icc0 \n" \ - " bne icc0,#0,1f \n" \ - " csth.p %3,%M0 ,cc3,#1 \n" \ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ - " beq icc3,#0,0b \n" \ - "1: \n" \ - : "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp) \ - : "r"(__xg_new), "NPr"(__xg_test) \ - : "memory", "cc7", "cc3", "icc3", "icc0" \ - ); \ - break; \ - \ case 4: \ asm volatile( \ "0: \n" \ @@ -388,8 +305,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v); #else -extern uint8_t __cmpxchg_8 (uint8_t *v, uint8_t test, uint8_t new); -extern uint16_t __cmpxchg_16(uint16_t *v, uint16_t test, uint16_t new); extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new); #define cmpxchg(ptr, test, new) \ @@ -400,8 +315,6 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new); __typeof__(*(ptr)) __xg_new = (new); \ \ switch (sizeof(__xg_orig)) { \ - case 1: __xg_orig = __cmpxchg_8 (__xg_ptr, __xg_test, __xg_new); break; \ - case 2: __xg_orig = __cmpxchg_16(__xg_ptr, __xg_test, __xg_new); break; \ case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break; \ default: \ __xg_orig = 0; \ @@ -414,7 +327,7 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new); #endif -#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new)) +#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) #define atomic_add_unless(v, a, u) \ ({ \ @@ -424,6 +337,7 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new); c = old; \ c != (u); \ }) + #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) #include -- cgit v1.2.3 From 8369ce4cfe18decc3ea0afcf91e67c665479c78e Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:18 -0800 Subject: [PATCH] frv: drop unsupported debugging features Drop support for debugging features that aren't supported on FRV: (*) EARLY_PRINTK The on-chip UARTs are set up early enough that this isn't required, and VGA support isn't available. There's also a gdbstub available. (*) DEBUG_PAGEALLOC This can't be easily be done since we use huge static mappings to cover the kernel, not pages. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/Kconfig.debug | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/arch/frv/Kconfig.debug b/arch/frv/Kconfig.debug index 0034b654995d..211f01bc4caa 100644 --- a/arch/frv/Kconfig.debug +++ b/arch/frv/Kconfig.debug @@ -2,32 +2,10 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config EARLY_PRINTK - bool "Early printk" - depends on EMBEDDED && DEBUG_KERNEL - default n - help - Write kernel log output directly into the VGA buffer or to a serial - port. - - This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks ugly and doesn't cooperate - with klogd/syslogd or the X server. You should normally N here, - unless you want to debug such a crash. - config DEBUG_STACKOVERFLOW bool "Check for stack overflows" depends on DEBUG_KERNEL -config DEBUG_PAGEALLOC - bool "Page alloc debugging" - depends on DEBUG_KERNEL - help - Unmap pages from the kernel linear mapping after free_pages(). - This results in a large slowdown, but helps to find certain types - of memory corruptions. - config GDBSTUB bool "Remote GDB kernel debugging" depends on DEBUG_KERNEL -- cgit v1.2.3 From 402344012ebe696d9353bbf056889ddaaec83079 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:19 -0800 Subject: [PATCH] frv: implement and export various things required by modules Export a number of features required to build all the modules. It also implements the following simple features: (*) csum_partial_copy_from_user() for MMU as well as no-MMU. (*) __ucmpdi2(). so that they can be exported too. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/frv_ksyms.c | 25 +++++++++++++------ arch/frv/kernel/irq.c | 17 +++++++++++++ arch/frv/kernel/pm.c | 2 ++ arch/frv/kernel/time.c | 3 +++ arch/frv/kernel/traps.c | 3 +++ arch/frv/kernel/uaccess.c | 7 ++++++ arch/frv/lib/Makefile | 2 +- arch/frv/lib/__ucmpdi2.S | 45 +++++++++++++++++++++++++++++++++++ arch/frv/lib/checksum.c | 31 +++++++++++++++++++----- arch/frv/mb93090-mb00/pci-dma-nommu.c | 8 +++++++ arch/frv/mb93090-mb00/pci-dma.c | 10 ++++++++ arch/frv/mm/cache-page.c | 5 ++++ arch/frv/mm/highmem.c | 8 +++++++ lib/find_next_bit.c | 3 +++ 14 files changed, 155 insertions(+), 14 deletions(-) create mode 100644 arch/frv/lib/__ucmpdi2.S diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index 1a76d5247190..5f118c89d091 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -16,10 +16,11 @@ #include #include #include -#include +#include extern void dump_thread(struct pt_regs *, struct user *); extern long __memcpy_user(void *dst, const void *src, size_t count); +extern long __memset_user(void *dst, const void *src, size_t count); /* platform dependent support */ @@ -50,7 +51,11 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(__res_bus_clock_speed_HZ); EXPORT_SYMBOL(__page_offset); EXPORT_SYMBOL(__memcpy_user); -EXPORT_SYMBOL(flush_dcache_page); +EXPORT_SYMBOL(__memset_user); +EXPORT_SYMBOL(frv_dcache_writeback); +EXPORT_SYMBOL(frv_cache_invalidate); +EXPORT_SYMBOL(frv_icache_invalidate); +EXPORT_SYMBOL(frv_cache_wback_inv); #ifndef CONFIG_MMU EXPORT_SYMBOL(memory_start); @@ -72,6 +77,9 @@ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(__outsl_ns); +EXPORT_SYMBOL(__insl_ns); + EXPORT_SYMBOL(get_wchan); #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS @@ -80,14 +88,13 @@ EXPORT_SYMBOL(atomic_test_and_OR_mask); EXPORT_SYMBOL(atomic_test_and_XOR_mask); EXPORT_SYMBOL(atomic_add_return); EXPORT_SYMBOL(atomic_sub_return); -EXPORT_SYMBOL(__xchg_8); -EXPORT_SYMBOL(__xchg_16); EXPORT_SYMBOL(__xchg_32); -EXPORT_SYMBOL(__cmpxchg_8); -EXPORT_SYMBOL(__cmpxchg_16); EXPORT_SYMBOL(__cmpxchg_32); #endif +EXPORT_SYMBOL(__debug_bug_printk); +EXPORT_SYMBOL(__delay_loops_MHz); + /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that @@ -101,6 +108,8 @@ extern void __divdi3(void); extern void __lshrdi3(void); extern void __moddi3(void); extern void __muldi3(void); +extern void __mulll(void); +extern void __umulll(void); extern void __negdi2(void); extern void __ucmpdi2(void); extern void __udivdi3(void); @@ -116,8 +125,10 @@ EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__lshrdi3); //EXPORT_SYMBOL(__moddi3); EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulll); +EXPORT_SYMBOL(__umulll); EXPORT_SYMBOL(__negdi2); -//EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__ucmpdi2); //EXPORT_SYMBOL(__udivdi3); //EXPORT_SYMBOL(__udivmoddi4); //EXPORT_SYMBOL(__umoddi3); diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 8c524cdd2717..59580c59c62c 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,8 @@ void disable_irq_nosync(unsigned int irq) spin_unlock_irqrestore(&level->lock, flags); } +EXPORT_SYMBOL(disable_irq_nosync); + /** * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable @@ -204,6 +207,8 @@ void disable_irq(unsigned int irq) #endif } +EXPORT_SYMBOL(disable_irq); + /** * enable_irq - enable handling of an irq * @irq: Interrupt to enable @@ -268,6 +273,8 @@ void enable_irq(unsigned int irq) spin_unlock_irqrestore(&level->lock, flags); } +EXPORT_SYMBOL(enable_irq); + /*****************************************************************************/ /* * handles all normal device IRQ's @@ -425,6 +432,8 @@ int request_irq(unsigned int irq, return retval; } +EXPORT_SYMBOL(request_irq); + /** * free_irq - free an interrupt * @irq: Interrupt line to free @@ -496,6 +505,8 @@ void free_irq(unsigned int irq, void *dev_id) } } +EXPORT_SYMBOL(free_irq); + /* * IRQ autodetection code.. * @@ -519,6 +530,8 @@ unsigned long probe_irq_on(void) return 0; } +EXPORT_SYMBOL(probe_irq_on); + /* * Return a mask of triggered interrupts (this * can handle only legacy ISA interrupts). @@ -542,6 +555,8 @@ unsigned int probe_irq_mask(unsigned long xmask) return 0; } +EXPORT_SYMBOL(probe_irq_mask); + /* * Return the one interrupt that triggered (this can * handle any interrupt source). @@ -571,6 +586,8 @@ int probe_irq_off(unsigned long xmask) return -1; } +EXPORT_SYMBOL(probe_irq_off); + /* this was setup_x86_irq but it seems pretty generic */ int setup_irq(unsigned int irq, struct irqaction *new) { diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index 712c3c24c954..f0b8fff3e733 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "local.h" void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); extern void frv_change_cmode(int); diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 2e9741227b73..24cf85f89e40 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -189,6 +189,8 @@ void do_gettimeofday(struct timeval *tv) tv->tv_usec = usec; } +EXPORT_SYMBOL(do_gettimeofday); + int do_settimeofday(struct timespec *tv) { time_t wtm_sec, sec = tv->tv_sec; @@ -218,6 +220,7 @@ int do_settimeofday(struct timespec *tv) clock_was_set(); return 0; } + EXPORT_SYMBOL(do_settimeofday); /* diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c index 89073cae4b5d..9eb84b2e6abc 100644 --- a/arch/frv/kernel/traps.c +++ b/arch/frv/kernel/traps.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -250,6 +251,8 @@ void dump_stack(void) show_stack(NULL, NULL); } +EXPORT_SYMBOL(dump_stack); + void show_stack(struct task_struct *task, unsigned long *sp) { } diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c index f3fd58a5bc4a..9b751c0f0e84 100644 --- a/arch/frv/kernel/uaccess.c +++ b/arch/frv/kernel/uaccess.c @@ -10,6 +10,7 @@ */ #include +#include #include /*****************************************************************************/ @@ -58,8 +59,11 @@ long strncpy_from_user(char *dst, const char *src, long count) memset(p, 0, count); /* clear remainder of buffer [security] */ return err; + } /* end strncpy_from_user() */ +EXPORT_SYMBOL(strncpy_from_user); + /*****************************************************************************/ /* * Return the size of a string (including the ending 0) @@ -92,4 +96,7 @@ long strnlen_user(const char *src, long count) } return p - src + 1; /* return length including NUL */ + } /* end strnlen_user() */ + +EXPORT_SYMBOL(strnlen_user); diff --git a/arch/frv/lib/Makefile b/arch/frv/lib/Makefile index 19be2626d5e6..08be305c9f44 100644 --- a/arch/frv/lib/Makefile +++ b/arch/frv/lib/Makefile @@ -3,6 +3,6 @@ # lib-y := \ - __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o \ + __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \ checksum.o memcpy.o memset.o atomic-ops.o \ outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o diff --git a/arch/frv/lib/__ucmpdi2.S b/arch/frv/lib/__ucmpdi2.S new file mode 100644 index 000000000000..d892f16ffaa9 --- /dev/null +++ b/arch/frv/lib/__ucmpdi2.S @@ -0,0 +1,45 @@ +/* __ucmpdi2.S: 64-bit unsigned compare + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + + .text + .p2align 4 + +############################################################################### +# +# int __ucmpdi2(unsigned long long a [GR8:GR9], +# unsigned long long b [GR10:GR11]) +# +# - returns 0, 1, or 2 as a <, =, > b respectively. +# +############################################################################### + .globl __ucmpdi2 + .type __ucmpdi2,@function +__ucmpdi2: + or.p gr8,gr0,gr4 + subcc gr8,gr10,gr0,icc0 + setlos.p #0,gr8 + bclr icc0,#2 ; a.msw < b.msw + + setlos.p #2,gr8 + bhilr icc0,#0 ; a.msw > b.msw + + subcc.p gr9,gr11,gr0,icc1 + setlos #0,gr8 + setlos.p #2,gr9 + setlos #1,gr7 + cknc icc1,cc6 + cor.p gr9,gr0,gr8, cc6,#1 + cckls icc1,cc4, cc6,#1 + andcr cc6,cc4,cc4 + cor gr7,gr0,gr8, cc4,#1 + bralr + .size __ucmpdi2, .-__ucmpdi2 diff --git a/arch/frv/lib/checksum.c b/arch/frv/lib/checksum.c index 7bf5bd6cac8a..20e7dfc474ef 100644 --- a/arch/frv/lib/checksum.c +++ b/arch/frv/lib/checksum.c @@ -33,6 +33,7 @@ #include #include +#include static inline unsigned short from32to16(unsigned long x) { @@ -115,34 +116,52 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) return result; } +EXPORT_SYMBOL(csum_partial); + /* * this routine is used for miscellaneous IP-like checksums, mainly * in icmp.c */ unsigned short ip_compute_csum(const unsigned char * buff, int len) { - return ~do_csum(buff,len); + return ~do_csum(buff, len); } +EXPORT_SYMBOL(ip_compute_csum); + /* * copy from fs while checksumming, otherwise like csum_partial */ - unsigned int -csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err) +csum_partial_copy_from_user(const char __user *src, char *dst, + int len, int sum, int *csum_err) { - if (csum_err) *csum_err = 0; - memcpy(dst, src, len); + int rem; + + if (csum_err) + *csum_err = 0; + + rem = copy_from_user(dst, src, len); + if (rem != 0) { + if (csum_err) + *csum_err = -EFAULT; + memset(dst + len - rem, 0, rem); + len = rem; + } + return csum_partial(dst, len, sum); } +EXPORT_SYMBOL(csum_partial_copy_from_user); + /* * copy from ds while checksumming, otherwise like csum_partial */ - unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum) { memcpy(dst, src, len); return csum_partial(dst, len, sum); } + +EXPORT_SYMBOL(csum_partial_copy); diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c index 2082a9647f4f..4985466b1a7c 100644 --- a/arch/frv/mb93090-mb00/pci-dma-nommu.c +++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c @@ -83,6 +83,8 @@ void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_hand return NULL; } +EXPORT_SYMBOL(dma_alloc_coherent); + void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { struct dma_alloc_record *rec; @@ -102,6 +104,8 @@ void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_ BUG(); } +EXPORT_SYMBOL(dma_free_coherent); + /* * Map a single buffer of the indicated size for DMA in streaming mode. * The 32-bit bus address to use is returned. @@ -120,6 +124,8 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, return virt_to_bus(ptr); } +EXPORT_SYMBOL(dma_map_single); + /* * Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the @@ -150,3 +156,5 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, return nents; } + +EXPORT_SYMBOL(dma_map_sg); diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c index 86fbdadc51b6..671ce1e8434f 100644 --- a/arch/frv/mb93090-mb00/pci-dma.c +++ b/arch/frv/mb93090-mb00/pci-dma.c @@ -28,11 +28,15 @@ void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_hand return ret; } +EXPORT_SYMBOL(dma_alloc_coherent); + void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { consistent_free(vaddr); } +EXPORT_SYMBOL(dma_free_coherent); + /* * Map a single buffer of the indicated size for DMA in streaming mode. * The 32-bit bus address to use is returned. @@ -51,6 +55,8 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, return virt_to_bus(ptr); } +EXPORT_SYMBOL(dma_map_single); + /* * Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the @@ -96,6 +102,8 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, return nents; } +EXPORT_SYMBOL(dma_map_sg); + dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction) { @@ -103,3 +111,5 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long off flush_dcache_page(page); return (dma_addr_t) page_to_phys(page) + offset; } + +EXPORT_SYMBOL(dma_map_page); diff --git a/arch/frv/mm/cache-page.c b/arch/frv/mm/cache-page.c index 683b5e344318..0261cbe153b5 100644 --- a/arch/frv/mm/cache-page.c +++ b/arch/frv/mm/cache-page.c @@ -11,6 +11,7 @@ #include #include #include +#include #include /*****************************************************************************/ @@ -38,6 +39,8 @@ void flush_dcache_page(struct page *page) } /* end flush_dcache_page() */ +EXPORT_SYMBOL(flush_dcache_page); + /*****************************************************************************/ /* * ICI takes a virtual address and the page may not currently have one @@ -64,3 +67,5 @@ void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, } } /* end flush_icache_user_range() */ + +EXPORT_SYMBOL(flush_icache_user_range); diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c index 7dc8fbf3af97..7f77db7fabc7 100644 --- a/arch/frv/mm/highmem.c +++ b/arch/frv/mm/highmem.c @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ #include +#include void *kmap(struct page *page) { @@ -18,6 +19,8 @@ void *kmap(struct page *page) return kmap_high(page); } +EXPORT_SYMBOL(kmap); + void kunmap(struct page *page) { if (in_interrupt()) @@ -27,7 +30,12 @@ void kunmap(struct page *page) kunmap_high(page); } +EXPORT_SYMBOL(kunmap); + struct page *kmap_atomic_to_page(void *ptr) { return virt_to_page(ptr); } + + +EXPORT_SYMBOL(kmap_atomic_to_page); diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c index d08302d2a42c..c05b4b19cf6c 100644 --- a/lib/find_next_bit.c +++ b/lib/find_next_bit.c @@ -10,6 +10,7 @@ */ #include +#include int find_next_bit(const unsigned long *addr, int size, int offset) { @@ -53,3 +54,5 @@ int find_next_bit(const unsigned long *addr, int size, int offset) return offset; } + +EXPORT_SYMBOL(find_next_bit); -- cgit v1.2.3 From 018b8d12bc85f8fb332239b11d919ea0724c49a4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:19 -0800 Subject: [PATCH] frv: support module exception tables Fix the exception table handling so that modules exceptions are dealt with. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/mm/extable.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/arch/frv/mm/extable.c b/arch/frv/mm/extable.c index 41be1128dc64..caacf030ac75 100644 --- a/arch/frv/mm/extable.c +++ b/arch/frv/mm/extable.c @@ -43,7 +43,7 @@ static inline unsigned long search_one_table(const struct exception_table_entry */ unsigned long search_exception_table(unsigned long pc) { - unsigned long ret = 0; + const struct exception_table_entry *extab; /* determine if the fault lay during a memcpy_user or a memset_user */ if (__frame->lr == (unsigned long) &__memset_user_error_lr && @@ -55,9 +55,10 @@ unsigned long search_exception_table(unsigned long pc) */ return (unsigned long) &__memset_user_error_handler; } - else if (__frame->lr == (unsigned long) &__memcpy_user_error_lr && - (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end - ) { + + if (__frame->lr == (unsigned long) &__memcpy_user_error_lr && + (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end + ) { /* the fault occurred in a protected memset * - we search for the return address (in LR) instead of the program counter * - it was probably during a copy_to/from_user() @@ -65,27 +66,10 @@ unsigned long search_exception_table(unsigned long pc) return (unsigned long) &__memcpy_user_error_handler; } -#ifndef CONFIG_MODULES - /* there is only the kernel to search. */ - ret = search_one_table(__start___ex_table, __stop___ex_table - 1, pc); - return ret; - -#else - /* the kernel is the last "module" -- no need to treat it special */ - unsigned long flags; - struct module *mp; + extab = search_exception_tables(pc); + if (extab) + return extab->fixup; - spin_lock_irqsave(&modlist_lock, flags); - - for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL || !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING))) - continue; - ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, pc); - if (ret) - break; - } + return 0; - spin_unlock_irqrestore(&modlist_lock, flags); - return ret; -#endif } /* end search_exception_table() */ -- cgit v1.2.3 From a90a72c85fb202d0b172da27d8df2579b6591783 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:20 -0800 Subject: [PATCH] frv: supply various missing I/O access primitives Supply various I/O access primitives that are missing for the FRV arch: (*) mmiowb() (*) read*_relaxed() (*) ioport_*map() (*) ioread*(), iowrite*(), ioread*_rep() and iowrite*_rep() (*) pci_io*map() (*) check_signature() The patch also makes __is_PCI_addr() more efficient. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-frv/io.h | 123 ++++++++++++++++++++++++++++++++++++++++++++++ include/asm-frv/mb-regs.h | 4 ++ 2 files changed, 127 insertions(+) diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h index 48829f727242..075369b1a34b 100644 --- a/include/asm-frv/io.h +++ b/include/asm-frv/io.h @@ -18,6 +18,7 @@ #ifdef __KERNEL__ #include +#include #include #include #include @@ -104,6 +105,8 @@ static inline void __insl(unsigned long addr, void *buf, int len, int swap) __insl_sw(addr, buf, len); } +#define mmiowb() mb() + /* * make the short names macros so specific devices * can override them as required @@ -209,6 +212,10 @@ static inline uint32_t readl(const volatile void __iomem *addr) return ret; } +#define readb_relaxed readb +#define readw_relaxed readw +#define readl_relaxed readl + static inline void writeb(uint8_t datum, volatile void __iomem *addr) { __builtin_write8((volatile uint8_t __force *) addr, datum); @@ -268,11 +275,106 @@ static inline void __iomem *ioremap_fullcache(unsigned long physaddr, unsigned l extern void iounmap(void __iomem *addr); +static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + return (void __iomem *) port; +} + +static inline void ioport_unmap(void __iomem *p) +{ +} + static inline void flush_write_buffers(void) { __asm__ __volatile__ ("membar" : : :"memory"); } +/* + * do appropriate I/O accesses for token type + */ +static inline unsigned int ioread8(void __iomem *p) +{ + return __builtin_read8(p); +} + +static inline unsigned int ioread16(void __iomem *p) +{ + uint16_t ret = __builtin_read16(p); + if (__is_PCI_addr(p)) + ret = _swapw(ret); + return ret; +} + +static inline unsigned int ioread32(void __iomem *p) +{ + uint32_t ret = __builtin_read32(p); + if (__is_PCI_addr(p)) + ret = _swapl(ret); + return ret; +} + +static inline void iowrite8(u8 val, void __iomem *p) +{ + __builtin_write8(p, val); + if (__is_PCI_MEM(p)) + __flush_PCI_writes(); +} + +static inline void iowrite16(u16 val, void __iomem *p) +{ + if (__is_PCI_addr(p)) + val = _swapw(val); + __builtin_write16(p, val); + if (__is_PCI_MEM(p)) + __flush_PCI_writes(); +} + +static inline void iowrite32(u32 val, void __iomem *p) +{ + if (__is_PCI_addr(p)) + val = _swapl(val); + __builtin_write32(p, val); + if (__is_PCI_MEM(p)) + __flush_PCI_writes(); +} + +static inline void ioread8_rep(void __iomem *p, void *dst, unsigned long count) +{ + io_insb((unsigned long) p, dst, count); +} + +static inline void ioread16_rep(void __iomem *p, void *dst, unsigned long count) +{ + io_insw((unsigned long) p, dst, count); +} + +static inline void ioread32_rep(void __iomem *p, void *dst, unsigned long count) +{ + __insl_ns((unsigned long) p, dst, count); +} + +static inline void iowrite8_rep(void __iomem *p, const void *src, unsigned long count) +{ + io_outsb((unsigned long) p, src, count); +} + +static inline void iowrite16_rep(void __iomem *p, const void *src, unsigned long count) +{ + io_outsw((unsigned long) p, src, count); +} + +static inline void iowrite32_rep(void __iomem *p, const void *src, unsigned long count) +{ + __outsl_ns((unsigned long) p, src, count); +} + +/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ +struct pci_dev; +extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); +static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p) +{ +} + /* * Convert a physical pointer to a virtual kernel pointer for /dev/mem @@ -285,6 +387,27 @@ static inline void flush_write_buffers(void) */ #define xlate_dev_kmem_ptr(p) p +/* + * Check BIOS signature + */ +static inline int check_signature(volatile void __iomem *io_addr, + const unsigned char *signature, int length) +{ + int retval = 0; + + do { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + + retval = 1; +out: + return retval; +} + #endif /* __KERNEL__ */ #endif /* _ASM_IO_H */ diff --git a/include/asm-frv/mb-regs.h b/include/asm-frv/mb-regs.h index c8f575fc42fa..93fa732fb0cd 100644 --- a/include/asm-frv/mb-regs.h +++ b/include/asm-frv/mb-regs.h @@ -68,6 +68,9 @@ do { \ #define __is_PCI_MEM(addr) \ ((unsigned long)(addr) - __region_PCI_MEM < 0x08000000UL) +#define __is_PCI_addr(addr) \ + ((unsigned long)(addr) - __region_PCI_IO < 0x0c000000UL) + #define __get_CLKSW() ({ *(volatile unsigned long *)(__region_CS2 + 0x0130000cUL) & 0xffUL; }) #define __get_CLKIN() (__get_CLKSW() * 125U * 100000U / 24U) @@ -149,6 +152,7 @@ do { \ #define __is_PCI_IO(addr) 0 /* no PCI */ #define __is_PCI_MEM(addr) 0 +#define __is_PCI_addr(addr) 0 #define __region_PCI_IO 0 #define __region_PCI_MEM 0 #define __flush_PCI_writes() do { } while(0) -- cgit v1.2.3 From 00d76710c253341b1e84795923e59ccdb099628f Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:21 -0800 Subject: [PATCH] frv: add module support stubs Add stubs for FRV module support. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/kernel/Makefile | 1 + arch/frv/kernel/module.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ include/asm-frv/module.h | 16 +++++++--- 3 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 arch/frv/kernel/module.c diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile index 422f30ede575..5a827b349b5e 100644 --- a/arch/frv/kernel/Makefile +++ b/arch/frv/kernel/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_PM) += pm.o cmode.o obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o obj-$(CONFIG_SYSCTL) += sysctl.o obj-$(CONFIG_FUTEX) += futex.o +obj-$(CONFIG_MODULES) += module.o diff --git a/arch/frv/kernel/module.c b/arch/frv/kernel/module.c new file mode 100644 index 000000000000..850d168f69fc --- /dev/null +++ b/arch/frv/kernel/module.c @@ -0,0 +1,80 @@ +/* module.c: FRV specific module loading bits + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * - Derived from arch/i386/kernel/module.c, Copyright (C) 2001 Rusty Russell. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + + return vmalloc_exec(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/include/asm-frv/module.h b/include/asm-frv/module.h index 3223cfaef743..3d5c6360289a 100644 --- a/include/asm-frv/module.h +++ b/include/asm-frv/module.h @@ -11,10 +11,18 @@ #ifndef _ASM_MODULE_H #define _ASM_MODULE_H -#define module_map(x) vmalloc(x) -#define module_unmap(x) vfree(x) -#define module_arch_init(x) (0) -#define arch_init_modules(x) do { } while (0) +struct mod_arch_specific +{ +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +/* + * Include the architecture version. + */ +#define MODULE_ARCH_VERMAGIC __stringify(PROCESSOR_MODEL_NAME) " " #endif /* _ASM_MODULE_H */ -- cgit v1.2.3 From a2a88f88782e8815cafa22f2b9e22234b9a61d0a Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:22 -0800 Subject: [PATCH] frv: add pci_iomap Implement pci_iomap() for FRV. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/mb93090-mb00/Makefile | 2 +- arch/frv/mb93090-mb00/pci-iomap.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 arch/frv/mb93090-mb00/pci-iomap.c diff --git a/arch/frv/mb93090-mb00/Makefile b/arch/frv/mb93090-mb00/Makefile index 3faf0f8cf9b5..76595e870733 100644 --- a/arch/frv/mb93090-mb00/Makefile +++ b/arch/frv/mb93090-mb00/Makefile @@ -3,7 +3,7 @@ # ifeq "$(CONFIG_PCI)" "y" -obj-y := pci-frv.o pci-irq.o pci-vdk.o +obj-y := pci-frv.o pci-irq.o pci-vdk.o pci-iomap.o ifeq "$(CONFIG_MMU)" "y" obj-y += pci-dma.o diff --git a/arch/frv/mb93090-mb00/pci-iomap.c b/arch/frv/mb93090-mb00/pci-iomap.c new file mode 100644 index 000000000000..068fa04bd527 --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-iomap.c @@ -0,0 +1,29 @@ +/* pci-iomap.c: description + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + + if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) + return (void __iomem *) start; + + return NULL; +} + +EXPORT_SYMBOL(pci_iomap); -- cgit v1.2.3 From 7a758313905f8b085b4591e8838626274e88b969 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:22 -0800 Subject: [PATCH] frv: fix PCMCIA configuration Fix PCMCIA configuration for FRV by including the stock PCMCIA configuration description file. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/Kconfig | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index ec85c0d6c6da..3516a3aee820 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -305,23 +305,7 @@ config RESERVE_DMA_COHERENT source "drivers/pci/Kconfig" -config PCMCIA - tristate "Use PCMCIA" - help - Say Y here if you want to attach PCMCIA- or PC-cards to your FR-V - board. These are credit-card size devices such as network cards, - modems or hard drives often used with laptops computers. There are - actually two varieties of these cards: the older 16 bit PCMCIA cards - and the newer 32 bit CardBus cards. If you want to use CardBus - cards, you need to say Y here and also to "CardBus support" below. - - To use your PC-cards, you will need supporting software from David - Hinds pcmcia-cs package (see the file - for location). Please also read the PCMCIA-HOWTO, available from - . - - To compile this driver as modules, choose M here: the - modules will be called pcmcia_core and ds. +source "drivers/pcmcia/Kconfig" #config MATH_EMULATION # bool "Math emulation support (EXPERIMENTAL)" -- cgit v1.2.3 From f8aec7573b87d2bc09cafab459476953353d2efa Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:23 -0800 Subject: [PATCH] frv: force serial driver inclusion Force the 8230 serial driver to be built in if the on-CPU UARTs are to be used. It can't be used as a module because the arch setup needs to call into it. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/Kconfig | 5 +++++ arch/frv/kernel/setup.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 3516a3aee820..61261b78ced7 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -274,6 +274,11 @@ config GPREL_DATA_NONE endchoice +config FRV_ONCPU_SERIAL + bool "Use on-CPU serial ports" + select SERIAL_8250 + default y + config PCI bool "Use PCI" depends on MB93090_MB00 diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index 767ebb55bd83..5908deae9607 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c @@ -787,6 +787,7 @@ void __init setup_arch(char **cmdline_p) #endif /* register those serial ports that are available */ +#ifdef CONFIG_FRV_ONCPU_SERIAL #ifndef CONFIG_GDBSTUB_UART0 __reg(UART0_BASE + UART_IER * 8) = 0; early_serial_setup(&__frv_uart0); @@ -795,6 +796,7 @@ void __init setup_arch(char **cmdline_p) __reg(UART1_BASE + UART_IER * 8) = 0; early_serial_setup(&__frv_uart1); #endif +#endif #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH) /* we need to initialize the Flashrom device here since we might -- cgit v1.2.3 From 5c15d41bab185431a9a28982b5aaac251dde4556 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:24 -0800 Subject: [PATCH] frv: make get_user macro cast pointers Make the get_user macro cast the source pointer to an appropriate type for the specified size. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-frv/uaccess.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h index 991b50fbba24..b6bcbe01f6ee 100644 --- a/include/asm-frv/uaccess.h +++ b/include/asm-frv/uaccess.h @@ -180,16 +180,16 @@ do { \ \ switch (sizeof(*(ptr))) { \ case 1: \ - __get_user_asm(__gu_err, __gu_val, ptr, "ub", "=r"); \ + __get_user_asm(__gu_err, *(u8*)&__gu_val, ptr, "ub", "=r"); \ break; \ case 2: \ - __get_user_asm(__gu_err, __gu_val, ptr, "uh", "=r"); \ + __get_user_asm(__gu_err, *(u16*)&__gu_val, ptr, "uh", "=r"); \ break; \ case 4: \ - __get_user_asm(__gu_err, __gu_val, ptr, "", "=r"); \ + __get_user_asm(__gu_err, *(u32*)&__gu_val, ptr, "", "=r"); \ break; \ case 8: \ - __get_user_asm(__gu_err, __gu_val, ptr, "d", "=e"); \ + __get_user_asm(__gu_err, *(u64*)&__gu_val, ptr, "d", "=e"); \ break; \ default: \ __gu_err = __get_user_bad(); \ -- cgit v1.2.3 From 41be6aef38c08f1f85ac1c4bd8191b0d1ec61b4c Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:25 -0800 Subject: [PATCH] frv: miscellaneous changes Fix a number of miscellanous items: (1) Declare lock sections in the linker script. (2) Recurse in the correct manner in the arch makefile. (3) asm/bug.h requires asm/linkage.h to be included first. One C file puts asm/bug.h first. (4) Add an empty RTC header file to avoid missing header file errors. (5) sg_dma_address() should use the dma_address member of a scatter list. (6) Add trivial pci_unmap support. (7) Add pgprot_noncached() (8) Discard u_quad_t. (9) Use ~0UL rather than ULONG_MAX in unistd.h in case the latter isn't declared. (10) Add an empty VGA header file to avoid missing header file errors. (11) Add an XOR header file to use the generic XOR stuff. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/frv/Makefile | 6 +++--- arch/frv/kernel/vmlinux.lds.S | 1 + include/asm-frv/bug.h | 1 + include/asm-frv/dma-mapping.h | 2 +- include/asm-frv/mc146818rtc.h | 16 ++++++++++++++++ include/asm-frv/pci.h | 8 ++++++++ include/asm-frv/pgtable.h | 5 +++++ include/asm-frv/types.h | 1 - include/asm-frv/unistd.h | 2 +- include/asm-frv/vga.h | 17 +++++++++++++++++ include/asm-frv/xor.h | 1 + 11 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 include/asm-frv/mc146818rtc.h create mode 100644 include/asm-frv/vga.h create mode 100644 include/asm-frv/xor.h diff --git a/arch/frv/Makefile b/arch/frv/Makefile index 54046d2386f5..90c0fb8d9dc3 100644 --- a/arch/frv/Makefile +++ b/arch/frv/Makefile @@ -109,10 +109,10 @@ bootstrap: $(Q)$(MAKEBOOT) bootstrap archmrproper: - $(Q)$(MAKE) -C arch/frv/boot mrproper + $(Q)$(MAKE) $(build)=arch/frv/boot mrproper archclean: - $(Q)$(MAKE) -C arch/frv/boot clean + $(Q)$(MAKE) $(build)=arch/frv/boot clean archdep: scripts/mkdep symlinks - $(Q)$(MAKE) -C arch/frv/boot dep + $(Q)$(MAKE) $(build)=arch/frv/boot dep diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index fceafd2cc202..f474534ba78a 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -112,6 +112,7 @@ SECTIONS #endif ) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) *(.exitcall.exit) diff --git a/include/asm-frv/bug.h b/include/asm-frv/bug.h index 074c0d5770eb..451712cc3060 100644 --- a/include/asm-frv/bug.h +++ b/include/asm-frv/bug.h @@ -12,6 +12,7 @@ #define _ASM_BUG_H #include +#include #ifdef CONFIG_BUG /* diff --git a/include/asm-frv/dma-mapping.h b/include/asm-frv/dma-mapping.h index 5003e017fd1e..e9fc1d47797e 100644 --- a/include/asm-frv/dma-mapping.h +++ b/include/asm-frv/dma-mapping.h @@ -23,7 +23,7 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t * returns, or alternatively stop on the first sg_dma_len(sg) which * is 0. */ -#define sg_dma_address(sg) ((unsigned long) (page_to_phys((sg)->page) + (sg)->offset)) +#define sg_dma_address(sg) ((sg)->dma_address) #define sg_dma_len(sg) ((sg)->length) /* diff --git a/include/asm-frv/mc146818rtc.h b/include/asm-frv/mc146818rtc.h new file mode 100644 index 000000000000..90dfb7a633d1 --- /dev/null +++ b/include/asm-frv/mc146818rtc.h @@ -0,0 +1,16 @@ +/* mc146818rtc.h: RTC defs + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_MC146818RTC_H +#define _ASM_MC146818RTC_H + + +#endif /* _ASM_MC146818RTC_H */ diff --git a/include/asm-frv/pci.h b/include/asm-frv/pci.h index 1168451c275f..598b0c6b695d 100644 --- a/include/asm-frv/pci.h +++ b/include/asm-frv/pci.h @@ -57,6 +57,14 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, */ #define PCI_DMA_BUS_IS_PHYS (1) +/* pci_unmap_{page,single} is a nop so... */ +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) +#define pci_unmap_addr(PTR, ADDR_NAME) (0) +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +#define pci_unmap_len(PTR, LEN_NAME) (0) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) + #ifdef CONFIG_PCI static inline void pci_dma_burst_advice(struct pci_dev *pdev, enum pci_dma_burst_strategy *strat, diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h index 844666377dcb..d1c3b182c691 100644 --- a/include/asm-frv/pgtable.h +++ b/include/asm-frv/pgtable.h @@ -420,6 +420,11 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, asm volatile("dcf %M0" :: "U"(*ptep)); } +/* + * Macro to mark a page protection value as "uncacheable" + */ +#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NOCACHE)) + /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. diff --git a/include/asm-frv/types.h b/include/asm-frv/types.h index 50605df6d8ac..2560f596a75d 100644 --- a/include/asm-frv/types.h +++ b/include/asm-frv/types.h @@ -59,7 +59,6 @@ typedef unsigned int u32; typedef signed long long s64; typedef unsigned long long u64; -typedef u64 u_quad_t; /* Dma addresses are 32-bits wide. */ diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index 5cf989b448d5..cde376a7a857 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -313,7 +313,7 @@ do { \ unsigned long __sr2 = (res); \ if (__builtin_expect(__sr2 >= (unsigned long)(-4095), 0)) { \ errno = (-__sr2); \ - __sr2 = ULONG_MAX; \ + __sr2 = ~0UL; \ } \ return (type) __sr2; \ } while (0) diff --git a/include/asm-frv/vga.h b/include/asm-frv/vga.h new file mode 100644 index 000000000000..a702c800a229 --- /dev/null +++ b/include/asm-frv/vga.h @@ -0,0 +1,17 @@ +/* vga.h: VGA register stuff + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ASM_VGA_H +#define _ASM_VGA_H + + + +#endif /* _ASM_VGA_H */ diff --git a/include/asm-frv/xor.h b/include/asm-frv/xor.h new file mode 100644 index 000000000000..c82eb12a5b18 --- /dev/null +++ b/include/asm-frv/xor.h @@ -0,0 +1 @@ +#include -- cgit v1.2.3 From 2087ff3ec56eba9bccd3b3a9d4d42670b1543f5d Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:25 -0800 Subject: [PATCH] frv: fix uninitialised variable in atm nicstar driver Fix an uninitialised variable warning in the atm nicstar driver. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/atm/nicstar.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index c57e20dcb0f8..074abc81ec3d 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -2126,8 +2126,7 @@ static void process_rsq(ns_dev *card) if (!ns_rsqe_valid(card->rsq.next)) return; - while (ns_rsqe_valid(card->rsq.next)) - { + do { dequeue_rx(card, card->rsq.next); ns_rsqe_init(card->rsq.next); previous = card->rsq.next; @@ -2135,7 +2134,7 @@ static void process_rsq(ns_dev *card) card->rsq.next = card->rsq.base; else card->rsq.next++; - } + } while (ns_rsqe_valid(card->rsq.next)); writel((((u32) previous) - ((u32) card->rsq.base)), card->membase + RSQH); } -- cgit v1.2.3 From 6d524aed1f50b2b1d5b4ad5a4e2fe3f38106d0a6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:01:26 -0800 Subject: [PATCH] frv: fix uninitialised variable in serverworks driver Fix an uninitialised variable warning in the serverworks driver. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/pci/serverworks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index ff2e217a8c84..0d3073f4eab4 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -69,7 +69,7 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list) static u8 svwks_ratemask (ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 mode; + u8 mode = 0; if (!svwks_revision) pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); -- cgit v1.2.3 From 22fc6eccbf4ce4eb6265e6ada7b50a7b9cc57d05 Mon Sep 17 00:00:00 2001 From: Ravikiran G Thirumalai Date: Sun, 8 Jan 2006 01:01:27 -0800 Subject: [PATCH] Change maxaligned_in_smp alignemnt macros to internodealigned_in_smp macros ____cacheline_maxaligned_in_smp is currently used to align critical structures and avoid false sharing. It uses per-arch L1_CACHE_SHIFT_MAX and people find L1_CACHE_SHIFT_MAX useless. However, we have been using ____cacheline_maxaligned_in_smp to align structures on the internode cacheline size. As per Andi's suggestion, following patch kills ____cacheline_maxaligned_in_smp and introduces INTERNODE_CACHE_SHIFT, which defaults to L1_CACHE_SHIFT for all arches. Arches needing L3/Internode cacheline alignment can define INTERNODE_CACHE_SHIFT in the arch asm/cache.h. Patch replaces ____cacheline_maxaligned_in_smp with ____cacheline_internodealigned_in_smp With this patch, L1_CACHE_SHIFT_MAX can be killed Signed-off-by: Ravikiran Thirumalai Signed-off-by: Shai Fultheim Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/init_task.c | 2 +- arch/i386/kernel/irq.c | 2 +- arch/x86_64/kernel/init_task.c | 2 +- include/linux/cache.h | 17 +++++++++++++---- include/linux/ide.h | 2 +- include/linux/mmzone.h | 4 ++-- include/linux/rcupdate.h | 2 +- kernel/rcupdate.c | 4 ++-- mm/sparse.c | 4 ++-- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c index 9caa8e8db80c..cff95d10a4d8 100644 --- a/arch/i386/kernel/init_task.c +++ b/arch/i386/kernel/init_task.c @@ -42,5 +42,5 @@ EXPORT_SYMBOL(init_task); * per-CPU TSS segments. Threads are completely 'soft' on Linux, * no more per-task TSS's. */ -DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 1a201a932865..f3a9c78c4a24 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -19,7 +19,7 @@ #include #include -DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp; +DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); #ifndef CONFIG_X86_LOCAL_APIC diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c index e0ba5c1043fd..ce31d904d601 100644 --- a/arch/x86_64/kernel/init_task.c +++ b/arch/x86_64/kernel/init_task.c @@ -44,6 +44,6 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS; #define ALIGN_TO_4K __attribute__((section(".data.init_task"))) diff --git a/include/linux/cache.h b/include/linux/cache.h index 0b7ecf3af78a..ffe52210fc4f 100644 --- a/include/linux/cache.h +++ b/include/linux/cache.h @@ -45,12 +45,21 @@ #endif /* CONFIG_SMP */ #endif -#if !defined(____cacheline_maxaligned_in_smp) +/* + * The maximum alignment needed for some critical structures + * These could be inter-node cacheline sizes/L3 cacheline + * size etc. Define this in asm/cache.h for your arch + */ +#ifndef INTERNODE_CACHE_SHIFT +#define INTERNODE_CACHE_SHIFT L1_CACHE_SHIFT +#endif + +#if !defined(____cacheline_internodealigned_in_smp) #if defined(CONFIG_SMP) -#define ____cacheline_maxaligned_in_smp \ - __attribute__((__aligned__(1 << (L1_CACHE_SHIFT_MAX)))) +#define ____cacheline_internodealigned_in_smp \ + __attribute__((__aligned__(1 << (INTERNODE_CACHE_SHIFT)))) #else -#define ____cacheline_maxaligned_in_smp +#define ____cacheline_internodealigned_in_smp #endif #endif diff --git a/include/linux/ide.h b/include/linux/ide.h index 7b6a6a58e465..4dd6694963c0 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -801,7 +801,7 @@ typedef struct hwif_s { unsigned dma; void (*led_act)(void *data, int rw); -} ____cacheline_maxaligned_in_smp ide_hwif_t; +} ____cacheline_internodealigned_in_smp ide_hwif_t; /* * internal ide interrupt handler type diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 2a89c132ba9c..7e4ae6ab1977 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -38,7 +38,7 @@ struct pglist_data; #if defined(CONFIG_SMP) struct zone_padding { char x[0]; -} ____cacheline_maxaligned_in_smp; +} ____cacheline_internodealigned_in_smp; #define ZONE_PADDING(name) struct zone_padding name; #else #define ZONE_PADDING(name) @@ -233,7 +233,7 @@ struct zone { * rarely used fields: */ char *name; -} ____cacheline_maxaligned_in_smp; +} ____cacheline_internodealigned_in_smp; /* diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a471f3bb713e..51747cd88d1a 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -65,7 +65,7 @@ struct rcu_ctrlblk { long cur; /* Current batch number. */ long completed; /* Number of the last completed batch */ int next_pending; /* Is the next batch already waiting? */ -} ____cacheline_maxaligned_in_smp; +} ____cacheline_internodealigned_in_smp; /* Is batch a before batch b ? */ static inline int rcu_batch_before(long a, long b) diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 48d3bce465b8..c9afc61240e4 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -61,9 +61,9 @@ struct rcu_state { /* for current batch to proceed. */ }; -static struct rcu_state rcu_state ____cacheline_maxaligned_in_smp = +static struct rcu_state rcu_state ____cacheline_internodealigned_in_smp = {.lock = SPIN_LOCK_UNLOCKED, .cpumask = CPU_MASK_NONE }; -static struct rcu_state rcu_bh_state ____cacheline_maxaligned_in_smp = +static struct rcu_state rcu_bh_state ____cacheline_internodealigned_in_smp = {.lock = SPIN_LOCK_UNLOCKED, .cpumask = CPU_MASK_NONE }; DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L }; diff --git a/mm/sparse.c b/mm/sparse.c index 72079b538e2d..0a51f36ba3a1 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -18,10 +18,10 @@ */ #ifdef CONFIG_SPARSEMEM_EXTREME struct mem_section *mem_section[NR_SECTION_ROOTS] - ____cacheline_maxaligned_in_smp; + ____cacheline_internodealigned_in_smp; #else struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT] - ____cacheline_maxaligned_in_smp; + ____cacheline_internodealigned_in_smp; #endif EXPORT_SYMBOL(mem_section); -- cgit v1.2.3 From 1fd73c6b6737b7e6eacac1b00dac16e7540c3cb1 Mon Sep 17 00:00:00 2001 From: Ravikiran G Thirumalai Date: Sun, 8 Jan 2006 01:01:28 -0800 Subject: [PATCH] Kill L1_CACHE_SHIFT_MAX Kill L1_CACHE_SHIFT from all arches. Since L1_CACHE_SHIFT_MAX is not used anymore with the introduction of INTERNODE_CACHE, kill L1_CACHE_SHIFT_MAX. Signed-off-by: Ravikiran Thirumalai Signed-off-by: Shai Fultheim Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-alpha/cache.h | 1 - include/asm-arm/cache.h | 5 ----- include/asm-cris/arch-v10/cache.h | 1 - include/asm-cris/arch-v32/cache.h | 1 - include/asm-cris/dma-mapping.h | 2 +- include/asm-generic/dma-mapping.h | 2 +- include/asm-i386/cache.h | 2 -- include/asm-i386/dma-mapping.h | 2 +- include/asm-ia64/cache.h | 2 -- include/asm-m32r/cache.h | 2 -- include/asm-m68k/cache.h | 2 -- include/asm-mips/cache.h | 1 - include/asm-parisc/cache.h | 1 - include/asm-powerpc/cache.h | 1 - include/asm-powerpc/dma-mapping.h | 2 +- include/asm-s390/cache.h | 1 - include/asm-sh/cache.h | 2 -- include/asm-sh64/cache.h | 2 -- include/asm-sparc/cache.h | 1 - include/asm-sparc64/cache.h | 1 - include/asm-um/cache.h | 3 --- include/asm-v850/cache.h | 2 -- include/asm-x86_64/cache.h | 1 - 23 files changed, 4 insertions(+), 36 deletions(-) diff --git a/include/asm-alpha/cache.h b/include/asm-alpha/cache.h index e69b29501a5f..e6d4d1695e25 100644 --- a/include/asm-alpha/cache.h +++ b/include/asm-alpha/cache.h @@ -20,6 +20,5 @@ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define L1_CACHE_SHIFT_MAX L1_CACHE_SHIFT #endif diff --git a/include/asm-arm/cache.h b/include/asm-arm/cache.h index 8d161f7c87ff..31332c8ac04e 100644 --- a/include/asm-arm/cache.h +++ b/include/asm-arm/cache.h @@ -7,9 +7,4 @@ #define L1_CACHE_SHIFT 5 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -/* - * largest L1 which this arch supports - */ -#define L1_CACHE_SHIFT_MAX 5 - #endif diff --git a/include/asm-cris/arch-v10/cache.h b/include/asm-cris/arch-v10/cache.h index 1d1d1ba65b1a..aea27184d2d2 100644 --- a/include/asm-cris/arch-v10/cache.h +++ b/include/asm-cris/arch-v10/cache.h @@ -4,6 +4,5 @@ /* Etrax 100LX have 32-byte cache-lines. */ #define L1_CACHE_BYTES 32 #define L1_CACHE_SHIFT 5 -#define L1_CACHE_SHIFT_MAX 5 #endif /* _ASM_ARCH_CACHE_H */ diff --git a/include/asm-cris/arch-v32/cache.h b/include/asm-cris/arch-v32/cache.h index 4fed8d62ccc8..80b236b15319 100644 --- a/include/asm-cris/arch-v32/cache.h +++ b/include/asm-cris/arch-v32/cache.h @@ -4,6 +4,5 @@ /* A cache-line is 32 bytes. */ #define L1_CACHE_BYTES 32 #define L1_CACHE_SHIFT 5 -#define L1_CACHE_SHIFT_MAX 5 #endif /* _ASM_CRIS_ARCH_CACHE_H */ diff --git a/include/asm-cris/dma-mapping.h b/include/asm-cris/dma-mapping.h index 8eff51349ae7..cbf1a98f0129 100644 --- a/include/asm-cris/dma-mapping.h +++ b/include/asm-cris/dma-mapping.h @@ -153,7 +153,7 @@ dma_set_mask(struct device *dev, u64 mask) static inline int dma_get_cache_alignment(void) { - return (1 << L1_CACHE_SHIFT_MAX); + return (1 << INTERNODE_CACHE_SHIFT); } #define dma_is_consistent(d) (1) diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h index 747d790295f3..1b356207712c 100644 --- a/include/asm-generic/dma-mapping.h +++ b/include/asm-generic/dma-mapping.h @@ -274,7 +274,7 @@ dma_get_cache_alignment(void) { /* no easy way to get cache size on all processors, so return * the maximum possible, to be safe */ - return (1 << L1_CACHE_SHIFT_MAX); + return (1 << INTERNODE_CACHE_SHIFT); } static inline void diff --git a/include/asm-i386/cache.h b/include/asm-i386/cache.h index 849788710feb..615911e5bd24 100644 --- a/include/asm-i386/cache.h +++ b/include/asm-i386/cache.h @@ -10,6 +10,4 @@ #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ - #endif diff --git a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h index e56c335f8ef9..6c37a9ab8d60 100644 --- a/include/asm-i386/dma-mapping.h +++ b/include/asm-i386/dma-mapping.h @@ -150,7 +150,7 @@ dma_get_cache_alignment(void) { /* no easy way to get cache size on all x86, so return the * maximum possible, to be safe */ - return (1 << L1_CACHE_SHIFT_MAX); + return (1 << INTERNODE_CACHE_SHIFT); } #define dma_is_consistent(d) (1) diff --git a/include/asm-ia64/cache.h b/include/asm-ia64/cache.h index 666d8f175cb3..40dd25195d65 100644 --- a/include/asm-ia64/cache.h +++ b/include/asm-ia64/cache.h @@ -12,8 +12,6 @@ #define L1_CACHE_SHIFT CONFIG_IA64_L1_CACHE_SHIFT #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ - #ifdef CONFIG_SMP # define SMP_CACHE_SHIFT L1_CACHE_SHIFT # define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/include/asm-m32r/cache.h b/include/asm-m32r/cache.h index 724820596980..9c2b2d9998bc 100644 --- a/include/asm-m32r/cache.h +++ b/include/asm-m32r/cache.h @@ -7,6 +7,4 @@ #define L1_CACHE_SHIFT 4 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define L1_CACHE_SHIFT_MAX 4 - #endif /* _ASM_M32R_CACHE_H */ diff --git a/include/asm-m68k/cache.h b/include/asm-m68k/cache.h index 6161fd3d8600..fed3fd30de7e 100644 --- a/include/asm-m68k/cache.h +++ b/include/asm-m68k/cache.h @@ -8,6 +8,4 @@ #define L1_CACHE_SHIFT 4 #define L1_CACHE_BYTES (1<< L1_CACHE_SHIFT) -#define L1_CACHE_SHIFT_MAX 4 /* largest L1 which this arch supports */ - #endif diff --git a/include/asm-mips/cache.h b/include/asm-mips/cache.h index 1a5d1a669db3..55e19f2ff0e0 100644 --- a/include/asm-mips/cache.h +++ b/include/asm-mips/cache.h @@ -15,7 +15,6 @@ #define L1_CACHE_SHIFT CONFIG_MIPS_L1_CACHE_SHIFT #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define L1_CACHE_SHIFT_MAX 6 #define SMP_CACHE_SHIFT L1_CACHE_SHIFT #define SMP_CACHE_BYTES L1_CACHE_BYTES diff --git a/include/asm-parisc/cache.h b/include/asm-parisc/cache.h index 5da72e38bdde..38d201b5652d 100644 --- a/include/asm-parisc/cache.h +++ b/include/asm-parisc/cache.h @@ -28,7 +28,6 @@ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ extern void flush_data_cache_local(void); /* flushes local data-cache only */ extern void flush_instruction_cache_local(void); /* flushes local code-cache only */ diff --git a/include/asm-powerpc/cache.h b/include/asm-powerpc/cache.h index 26ce502e76e8..6379c2df5c40 100644 --- a/include/asm-powerpc/cache.h +++ b/include/asm-powerpc/cache.h @@ -19,7 +19,6 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ #if defined(__powerpc64__) && !defined(__ASSEMBLY__) struct ppc64_caches { diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h index 59a80163f75f..a96e5742ca32 100644 --- a/include/asm-powerpc/dma-mapping.h +++ b/include/asm-powerpc/dma-mapping.h @@ -229,7 +229,7 @@ static inline int dma_get_cache_alignment(void) #ifdef CONFIG_PPC64 /* no easy way to get cache size on all processors, so return * the maximum possible, to be safe */ - return (1 << L1_CACHE_SHIFT_MAX); + return (1 << INTERNODE_CACHE_SHIFT); #else /* * Each processor family will define its own L1_CACHE_SHIFT, diff --git a/include/asm-s390/cache.h b/include/asm-s390/cache.h index 29845378b206..e20cdd9074db 100644 --- a/include/asm-s390/cache.h +++ b/include/asm-s390/cache.h @@ -13,7 +13,6 @@ #define L1_CACHE_BYTES 256 #define L1_CACHE_SHIFT 8 -#define L1_CACHE_SHIFT_MAX 8 /* largest L1 which this arch supports */ #define ARCH_KMALLOC_MINALIGN 8 diff --git a/include/asm-sh/cache.h b/include/asm-sh/cache.h index 9b4dd6d8212e..656fdfe9e8b4 100644 --- a/include/asm-sh/cache.h +++ b/include/asm-sh/cache.h @@ -22,8 +22,6 @@ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) -#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ - struct cache_info { unsigned int ways; unsigned int sets; diff --git a/include/asm-sh64/cache.h b/include/asm-sh64/cache.h index f54e85e8a470..a4f36f0036e1 100644 --- a/include/asm-sh64/cache.h +++ b/include/asm-sh64/cache.h @@ -20,8 +20,6 @@ #define L1_CACHE_ALIGN_MASK (~(L1_CACHE_BYTES - 1)) #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES - 1)) & L1_CACHE_ALIGN_MASK) #define L1_CACHE_SIZE_BYTES (L1_CACHE_BYTES << 10) -/* Largest L1 which this arch supports */ -#define L1_CACHE_SHIFT_MAX 5 #ifdef MODULE #define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) diff --git a/include/asm-sparc/cache.h b/include/asm-sparc/cache.h index a10522cb21b7..cb971e88aea4 100644 --- a/include/asm-sparc/cache.h +++ b/include/asm-sparc/cache.h @@ -13,7 +13,6 @@ #define L1_CACHE_SHIFT 5 #define L1_CACHE_BYTES 32 #define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))) -#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ #define SMP_CACHE_BYTES 32 diff --git a/include/asm-sparc64/cache.h b/include/asm-sparc64/cache.h index ade5ec3bfd5a..f7d35a2ae9b8 100644 --- a/include/asm-sparc64/cache.h +++ b/include/asm-sparc64/cache.h @@ -9,7 +9,6 @@ #define L1_CACHE_BYTES 32 /* Two 16-byte sub-blocks per line. */ #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) -#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ #define SMP_CACHE_BYTES_SHIFT 6 #define SMP_CACHE_BYTES (1 << SMP_CACHE_BYTES_SHIFT) /* L2 cache line size. */ diff --git a/include/asm-um/cache.h b/include/asm-um/cache.h index a10602a5b2d6..3d0587075521 100644 --- a/include/asm-um/cache.h +++ b/include/asm-um/cache.h @@ -13,9 +13,6 @@ # define L1_CACHE_SHIFT 5 #endif -/* XXX: this is valid for x86 and x86_64. */ -#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ - #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #endif diff --git a/include/asm-v850/cache.h b/include/asm-v850/cache.h index cbf9096e8517..8832c7ea3242 100644 --- a/include/asm-v850/cache.h +++ b/include/asm-v850/cache.h @@ -23,6 +23,4 @@ #define L1_CACHE_SHIFT 4 #endif -#define L1_CACHE_SHIFT_MAX L1_CACHE_SHIFT - #endif /* __V850_CACHE_H__ */ diff --git a/include/asm-x86_64/cache.h b/include/asm-x86_64/cache.h index 33e53424128b..b4a2401de77b 100644 --- a/include/asm-x86_64/cache.h +++ b/include/asm-x86_64/cache.h @@ -9,6 +9,5 @@ /* L1 cache line size */ #define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT) #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */ #endif -- cgit v1.2.3 From b2de464f7f0006bec162559a8db161869d32ee93 Mon Sep 17 00:00:00 2001 From: Woody Suwalski Date: Sun, 8 Jan 2006 01:01:29 -0800 Subject: [PATCH] ARM: Netwinder ds1620 driver needs an export to be built as module ds1620 module is using gpio_read symbol, so works only if "built-in" symbol needs to be exported from the kernel image Signed-off-by: Woody Suwalski Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/mach-footbridge/netwinder-hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c index 775f85fc8513..9e563de465b5 100644 --- a/arch/arm/mach-footbridge/netwinder-hw.c +++ b/arch/arm/mach-footbridge/netwinder-hw.c @@ -601,6 +601,7 @@ EXPORT_SYMBOL(gpio_lock); EXPORT_SYMBOL(gpio_modify_op); EXPORT_SYMBOL(gpio_modify_io); EXPORT_SYMBOL(cpld_modify); +EXPORT_SYMBOL(gpio_read); /* * Initialise any other hardware after we've got the PCI bus -- cgit v1.2.3 From 0805d89c151b4800eade4c2f50d39c5253d7d054 Mon Sep 17 00:00:00 2001 From: Gennady Sharapov Date: Sun, 8 Jan 2006 01:01:29 -0800 Subject: [PATCH] uml: move libc-dependent code from signal_user.c The serial UML OS-abstraction layer patch (um/kernel dir). This moves all systemcalls from signal_user.c file under os-Linux dir Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/kern_util.h | 2 - arch/um/include/os.h | 10 +++ arch/um/include/signal_user.h | 28 ------- arch/um/kernel/Makefile | 2 +- arch/um/kernel/irq_user.c | 1 - arch/um/kernel/process_kern.c | 1 - arch/um/kernel/signal_kern.c | 1 - arch/um/kernel/signal_user.c | 157 ------------------------------------ arch/um/kernel/skas/include/skas.h | 1 - arch/um/kernel/skas/process.c | 11 --- arch/um/kernel/skas/process_kern.c | 1 - arch/um/kernel/skas/trap_user.c | 2 +- arch/um/kernel/time.c | 2 +- arch/um/kernel/trap_user.c | 1 - arch/um/kernel/tt/exec_kern.c | 1 - arch/um/kernel/tt/process_kern.c | 1 - arch/um/kernel/tt/tracer.c | 1 - arch/um/kernel/tt/trap_user.c | 2 +- arch/um/os-Linux/main.c | 1 - arch/um/os-Linux/process.c | 1 - arch/um/os-Linux/signal.c | 158 ++++++++++++++++++++++++++++++++++--- arch/um/os-Linux/start_up.c | 1 - arch/um/os-Linux/tt.c | 1 - arch/um/sys-i386/signal.c | 1 - 24 files changed, 162 insertions(+), 226 deletions(-) delete mode 100644 arch/um/include/signal_user.h delete mode 100644 arch/um/kernel/signal_user.c diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index e5fec5570199..58c0b10fcf2d 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -51,8 +51,6 @@ extern void timer_handler(int sig, union uml_pt_regs *regs); extern int set_signals(int enable); extern void force_sigbus(void); extern int pid_to_processor_id(int pid); -extern void block_signals(void); -extern void unblock_signals(void); extern void deliver_signals(void *t); extern int next_syscall_index(int max); extern int next_trap_index(int max); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index c279ee6d89e4..cfc806e4610b 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -219,4 +219,14 @@ extern int umid_file_name(char *name, char *buf, int len); extern int set_umid(char *name); extern char *get_umid(void); +/* signal.c */ +extern void set_sigstack(void *sig_stack, int size); +extern void remove_sigstack(void); +extern void set_handler(int sig, void (*handler)(int), int flags, ...); +extern int change_sig(int signal, int on); +extern void block_signals(void); +extern void unblock_signals(void); +extern int get_signals(void); +extern int set_signals(int enable); + #endif diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h deleted file mode 100644 index b075e543d864..000000000000 --- a/arch/um/include/signal_user.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SIGNAL_USER_H__ -#define __SIGNAL_USER_H__ - -extern int signal_stack_size; - -extern int change_sig(int signal, int on); -extern void set_sigstack(void *stack, int size); -extern void set_handler(int sig, void (*handler)(int), int flags, ...); -extern int set_signals(int enable); -extern int get_signals(void); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 6f7700593a6f..9ce6c57747a8 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -9,7 +9,7 @@ clean-files := obj-y = config.o exec_kern.o exitcode.o \ init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ - signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \ + signal_kern.o smp.o syscall_kern.o sysrq.o time.o \ time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o umid.o \ user_util.o diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 50a2aa35cda9..0e32f5f4a887 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -15,7 +15,6 @@ #include "kern_util.h" #include "user.h" #include "process.h" -#include "signal_user.h" #include "sigio.h" #include "irq_user.h" #include "os.h" diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 651abf255bc5..d2d3f256778c 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -36,7 +36,6 @@ #include "kern_util.h" #include "kern.h" #include "signal_kern.h" -#include "signal_user.h" #include "init.h" #include "irq_user.h" #include "mem_user.h" diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 03618bd13d55..7b0e0e81c161 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -22,7 +22,6 @@ #include "asm/ucontext.h" #include "kern_util.h" #include "signal_kern.h" -#include "signal_user.h" #include "kern.h" #include "frame_kern.h" #include "sigcontext.h" diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c deleted file mode 100644 index 62f457835fb1..000000000000 --- a/arch/um/kernel/signal_user.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "signal_user.h" -#include "signal_kern.h" -#include "sysdep/sigcontext.h" -#include "sigcontext.h" - -void set_sigstack(void *sig_stack, int size) -{ - stack_t stack = ((stack_t) { .ss_flags = 0, - .ss_sp = (__ptr_t) sig_stack, - .ss_size = size - sizeof(void *) }); - - if(sigaltstack(&stack, NULL) != 0) - panic("enabling signal stack failed, errno = %d\n", errno); -} - -void set_handler(int sig, void (*handler)(int), int flags, ...) -{ - struct sigaction action; - va_list ap; - int mask; - - va_start(ap, flags); - action.sa_handler = handler; - sigemptyset(&action.sa_mask); - while((mask = va_arg(ap, int)) != -1){ - sigaddset(&action.sa_mask, mask); - } - va_end(ap); - action.sa_flags = flags; - action.sa_restorer = NULL; - if(sigaction(sig, &action, NULL) < 0) - panic("sigaction failed"); -} - -int change_sig(int signal, int on) -{ - sigset_t sigset, old; - - sigemptyset(&sigset); - sigaddset(&sigset, signal); - sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); - return(!sigismember(&old, signal)); -} - -/* Both here and in set/get_signal we don't touch SIGPROF, because we must not - * disable profiling; it's safe because the profiling code does not interact - * with the kernel code at all.*/ - -static void change_signals(int type) -{ - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - sigaddset(&mask, SIGIO); - if(sigprocmask(type, &mask, NULL) < 0) - panic("Failed to change signal mask - errno = %d", errno); -} - -void block_signals(void) -{ - change_signals(SIG_BLOCK); -} - -void unblock_signals(void) -{ - change_signals(SIG_UNBLOCK); -} - -/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled - * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to - * be able to profile all of UML, not just the non-critical sections. If - * profiling is not thread-safe, then that is not my problem. We can disable - * profiling when SMP is enabled in that case. - */ -#define SIGIO_BIT 0 -#define SIGVTALRM_BIT 1 - -static int enable_mask(sigset_t *mask) -{ - int sigs; - - sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; - sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; - sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; - return(sigs); -} - -int get_signals(void) -{ - sigset_t mask; - - if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) - panic("Failed to get signal mask"); - return(enable_mask(&mask)); -} - -int set_signals(int enable) -{ - sigset_t mask; - int ret; - - sigemptyset(&mask); - if(enable & (1 << SIGIO_BIT)) - sigaddset(&mask, SIGIO); - if(enable & (1 << SIGVTALRM_BIT)){ - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - } - - /* This is safe - sigprocmask is guaranteed to copy locally the - * value of new_set, do his work and then, at the end, write to - * old_set. - */ - if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) - panic("Failed to enable signals"); - ret = enable_mask(&mask); - sigemptyset(&mask); - if((enable & (1 << SIGIO_BIT)) == 0) - sigaddset(&mask, SIGIO); - if((enable & (1 << SIGVTALRM_BIT)) == 0){ - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - } - if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) - panic("Failed to block signals"); - - return(ret); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index daa2f85b684c..01d489de3986 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -22,7 +22,6 @@ extern int start_idle_thread(void *stack, void *switch_buf_ptr, extern int user_thread(unsigned long stack, int flags); extern void userspace(union uml_pt_regs *regs); extern void new_thread_proc(void *stack, void (*handler)(int sig)); -extern void remove_sigstack(void); extern void new_thread_handler(int sig); extern void handle_syscall(union uml_pt_regs *regs); extern int map(struct mm_id * mm_idp, unsigned long virt, diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 599d679bd4fc..9264d4021dfe 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -31,7 +31,6 @@ #include "proc_mm.h" #include "skas_ptrace.h" #include "chan_user.h" -#include "signal_user.h" #include "registers.h" #include "mem.h" #include "uml-config.h" @@ -514,16 +513,6 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) siglongjmp(**switch_buf, 1); } -void remove_sigstack(void) -{ - stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, - .ss_sp = NULL, - .ss_size = 0 }); - - if(sigaltstack(&stack, NULL) != 0) - panic("disabling signal stack failed, errno = %d\n", errno); -} - void initial_thread_cb_skas(void (*proc)(void *), void *arg) { sigjmp_buf here; diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 9c990253966c..09790ccb161c 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -14,7 +14,6 @@ #include "asm/atomic.h" #include "kern_util.h" #include "time_user.h" -#include "signal_user.h" #include "skas.h" #include "os.h" #include "user_util.h" diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 9950a6716fe5..28403d2cafe6 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -5,7 +5,6 @@ #include #include -#include "signal_user.h" #include "user_util.h" #include "kern_util.h" #include "task.h" @@ -14,6 +13,7 @@ #include "ptrace_user.h" #include "sysdep/ptrace.h" #include "sysdep/ptrace_user.h" +#include "os.h" void sig_handler_common_skas(int sig, void *sc_ptr) { diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index c40b611e3d93..11f518a7e156 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -14,9 +14,9 @@ #include "kern_util.h" #include "user.h" #include "process.h" -#include "signal_user.h" #include "time_user.h" #include "kern_constants.h" +#include "os.h" /* XXX This really needs to be declared and initialized in a kernel file since * it's in diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index e9ccd6b8d3c7..e55110725124 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -17,7 +17,6 @@ #include "sigcontext.h" #include "sysdep/sigcontext.h" #include "irq_user.h" -#include "signal_user.h" #include "time_user.h" #include "task.h" #include "mode.h" diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index 065b504a653b..136e54c47d37 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -14,7 +14,6 @@ #include "kern_util.h" #include "irq_user.h" #include "time_user.h" -#include "signal_user.h" #include "mem_user.h" #include "os.h" #include "tlb.h" diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index cfaa373a6e77..14d4622a5fb8 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -13,7 +13,6 @@ #include "asm/ptrace.h" #include "asm/tlbflush.h" #include "irq_user.h" -#include "signal_user.h" #include "kern_util.h" #include "user_util.h" #include "os.h" diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index d11e7399d7a1..71daae24e48a 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -19,7 +19,6 @@ #include "sigcontext.h" #include "sysdep/sigcontext.h" #include "os.h" -#include "signal_user.h" #include "user_util.h" #include "mem_user.h" #include "process.h" diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index fc108615beaf..7501900f8941 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c @@ -8,11 +8,11 @@ #include #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" -#include "signal_user.h" #include "user_util.h" #include "kern_util.h" #include "task.h" #include "tt.h" +#include "os.h" void sig_handler_common_tt(int sig, void *sc_ptr) { diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 23da27d22569..172c8474453c 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -16,7 +16,6 @@ #include "user_util.h" #include "kern_util.h" #include "mem_user.h" -#include "signal_user.h" #include "time_user.h" #include "irq_user.h" #include "user.h" diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d9c52387c4a1..39815c6b5e45 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -15,7 +15,6 @@ #include "os.h" #include "user.h" #include "user_util.h" -#include "signal_user.h" #include "process.h" #include "irq_user.h" #include "kern_util.h" diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index c7bfd5ee3925..c1f46a0fef13 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -4,9 +4,22 @@ */ #include +#include +#include +#include +#include +#include +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "signal_kern.h" +#include "sysdep/sigcontext.h" +#include "sysdep/signal.h" +#include "sigcontext.h" #include "time_user.h" #include "mode.h" -#include "sysdep/signal.h" void sig_handler(ARCH_SIGHDLR_PARAM) { @@ -36,13 +49,138 @@ void alarm_handler(ARCH_SIGHDLR_PARAM) switch_timers(1); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: +void set_sigstack(void *sig_stack, int size) +{ + stack_t stack = ((stack_t) { .ss_flags = 0, + .ss_sp = (__ptr_t) sig_stack, + .ss_size = size - sizeof(void *) }); + + if(sigaltstack(&stack, NULL) != 0) + panic("enabling signal stack failed, errno = %d\n", errno); +} + +void remove_sigstack(void) +{ + stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, + .ss_sp = NULL, + .ss_size = 0 }); + + if(sigaltstack(&stack, NULL) != 0) + panic("disabling signal stack failed, errno = %d\n", errno); +} + +void set_handler(int sig, void (*handler)(int), int flags, ...) +{ + struct sigaction action; + va_list ap; + int mask; + + va_start(ap, flags); + action.sa_handler = handler; + sigemptyset(&action.sa_mask); + while((mask = va_arg(ap, int)) != -1){ + sigaddset(&action.sa_mask, mask); + } + va_end(ap); + action.sa_flags = flags; + action.sa_restorer = NULL; + if(sigaction(sig, &action, NULL) < 0) + panic("sigaction failed"); +} + +int change_sig(int signal, int on) +{ + sigset_t sigset, old; + + sigemptyset(&sigset); + sigaddset(&sigset, signal); + sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); + return(!sigismember(&old, signal)); +} + +/* Both here and in set/get_signal we don't touch SIGPROF, because we must not + * disable profiling; it's safe because the profiling code does not interact + * with the kernel code at all.*/ + +static void change_signals(int type) +{ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + sigaddset(&mask, SIGIO); + if(sigprocmask(type, &mask, NULL) < 0) + panic("Failed to change signal mask - errno = %d", errno); +} + +void block_signals(void) +{ + change_signals(SIG_BLOCK); +} + +void unblock_signals(void) +{ + change_signals(SIG_UNBLOCK); +} + +/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled + * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to + * be able to profile all of UML, not just the non-critical sections. If + * profiling is not thread-safe, then that is not my problem. We can disable + * profiling when SMP is enabled in that case. */ +#define SIGIO_BIT 0 +#define SIGVTALRM_BIT 1 + +static int enable_mask(sigset_t *mask) +{ + int sigs; + + sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; + sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; + sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; + return(sigs); +} + +int get_signals(void) +{ + sigset_t mask; + + if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) + panic("Failed to get signal mask"); + return(enable_mask(&mask)); +} + +int set_signals(int enable) +{ + sigset_t mask; + int ret; + + sigemptyset(&mask); + if(enable & (1 << SIGIO_BIT)) + sigaddset(&mask, SIGIO); + if(enable & (1 << SIGVTALRM_BIT)){ + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + } + + /* This is safe - sigprocmask is guaranteed to copy locally the + * value of new_set, do his work and then, at the end, write to + * old_set. + */ + if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) + panic("Failed to enable signals"); + ret = enable_mask(&mask); + sigemptyset(&mask); + if((enable & (1 << SIGIO_BIT)) == 0) + sigaddset(&mask, SIGIO); + if((enable & (1 << SIGVTALRM_BIT)) == 0){ + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + } + if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) + panic("Failed to block signals"); + + return(ret); +} diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 29a9e3f43763..b47e5e71d1a5 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -24,7 +24,6 @@ #include "kern_util.h" #include "user.h" #include "signal_kern.h" -#include "signal_user.h" #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" #include "irq_user.h" diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index a6db8877931a..37828e5b3526 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c @@ -23,7 +23,6 @@ #include "kern_util.h" #include "user.h" #include "signal_kern.h" -#include "signal_user.h" #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" #include "irq_user.h" diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 16bc19928b3c..7cd1a82dc8c2 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -10,7 +10,6 @@ #include "asm/uaccess.h" #include "asm/unistd.h" #include "frame_kern.h" -#include "signal_user.h" #include "sigcontext.h" #include "registers.h" #include "mode.h" -- cgit v1.2.3 From ea2ba7dc3dd3f85034e6da6abacc813d723a2ad5 Mon Sep 17 00:00:00 2001 From: Gennady Sharapov Date: Sun, 8 Jan 2006 01:01:31 -0800 Subject: [PATCH] uml: move libc-dependent code from trap_user.c The serial UML OS-abstraction layer patch (um/kernel dir). This moves all systemcalls from trap_user.c file under os-Linux dir Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/kern_util.h | 17 ++++++++- arch/um/include/os.h | 6 ++++ arch/um/include/user_util.h | 10 ++---- arch/um/kernel/skas/Makefile | 2 +- arch/um/kernel/skas/trap_user.c | 78 ----------------------------------------- arch/um/kernel/trap_kern.c | 11 +++++- arch/um/kernel/trap_user.c | 65 +++++++--------------------------- arch/um/kernel/tt/trap_user.c | 14 +++++--- arch/um/kernel/um_arch.c | 7 +++- arch/um/os-Linux/Makefile | 8 +++-- arch/um/os-Linux/skas/Makefile | 10 ++++++ arch/um/os-Linux/skas/trap.c | 73 ++++++++++++++++++++++++++++++++++++++ arch/um/os-Linux/trap.c | 17 +++++++++ arch/um/os-Linux/tt.c | 14 ++++++++ 14 files changed, 182 insertions(+), 150 deletions(-) delete mode 100644 arch/um/kernel/skas/trap_user.c create mode 100644 arch/um/os-Linux/skas/Makefile create mode 100644 arch/um/os-Linux/skas/trap.c create mode 100644 arch/um/os-Linux/trap.c diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 58c0b10fcf2d..8f4e46d677ab 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -10,6 +10,19 @@ #include "sysdep/ptrace.h" #include "sysdep/faultinfo.h" +typedef void (*kern_hndl)(int, union uml_pt_regs *); + +struct kern_handlers { + kern_hndl relay_signal; + kern_hndl winch; + kern_hndl bus_handler; + kern_hndl page_fault; + kern_hndl sigio_handler; + kern_hndl timer_handler; +}; + +extern struct kern_handlers handlinfo_kern; + extern int ncpus; extern char *linux_prog; extern char *gdb_init; @@ -109,6 +122,8 @@ extern void arch_switch(void); extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); extern int cpu(void); +extern void segv_handler(int sig, union uml_pt_regs *regs); +extern void sigio_handler(int sig, union uml_pt_regs *regs); #endif diff --git a/arch/um/include/os.h b/arch/um/include/os.h index cfc806e4610b..dd72d66cf0ed 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -9,6 +9,8 @@ #include "uml-config.h" #include "asm/types.h" #include "../os/include/file.h" +#include "sysdep/ptrace.h" +#include "kern_util.h" #define OS_TYPE_FILE 1 #define OS_TYPE_DIR 2 @@ -229,4 +231,8 @@ extern void unblock_signals(void); extern int get_signals(void); extern int set_signals(int enable); +/* trap.c */ +extern void os_fill_handlinfo(struct kern_handlers h); +extern void do_longjmp(void *p, int val); + #endif diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index b9984003e603..c1dbd77b073f 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -23,12 +23,7 @@ struct cpu_task { extern struct cpu_task cpu_tasks[]; -struct signal_info { - void (*handler)(int, union uml_pt_regs *); - int is_irq; -}; - -extern struct signal_info sig_info[]; +extern void (*sig_info[])(int, union uml_pt_regs *); extern unsigned long low_physmem; extern unsigned long high_physmem; @@ -64,7 +59,6 @@ extern void setup_machinename(char *machine_out); extern void setup_hostinfo(void); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); -extern void do_longjmp(void *p, int val); extern int detach(int pid, int sig); extern int attach(int pid); extern void kill_child_dead(int pid); diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 8de471b59c1c..7a9fc16d71d4 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -4,7 +4,7 @@ # obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ - syscall.o tlb.o trap_user.o uaccess.o + syscall.o tlb.o uaccess.o USER_OBJS := process.o clone.o diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c deleted file mode 100644 index 28403d2cafe6..000000000000 --- a/arch/um/kernel/skas/trap_user.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) - * Licensed under the GPL - */ - -#include -#include -#include "user_util.h" -#include "kern_util.h" -#include "task.h" -#include "sigcontext.h" -#include "skas.h" -#include "ptrace_user.h" -#include "sysdep/ptrace.h" -#include "sysdep/ptrace_user.h" -#include "os.h" - -void sig_handler_common_skas(int sig, void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - struct skas_regs *r; - struct signal_info *info; - int save_errno = errno; - int save_user; - - /* This is done because to allow SIGSEGV to be delivered inside a SEGV - * handler. This can happen in copy_user, and if SEGV is disabled, - * the process will die. - * XXX Figure out why this is better than SA_NODEFER - */ - if(sig == SIGSEGV) - change_sig(SIGSEGV, 1); - - r = &TASK_REGS(get_current())->skas; - save_user = r->is_user; - r->is_user = 0; - if ( sig == SIGFPE || sig == SIGSEGV || - sig == SIGBUS || sig == SIGILL || - sig == SIGTRAP ) { - GET_FAULTINFO_FROM_SC(r->faultinfo, sc); - } - - change_sig(SIGUSR1, 1); - info = &sig_info[sig]; - if(!info->is_irq) unblock_signals(); - - (*info->handler)(sig, (union uml_pt_regs *) r); - - errno = save_errno; - r->is_user = save_user; -} - -extern int ptrace_faultinfo; - -void user_signal(int sig, union uml_pt_regs *regs, int pid) -{ - struct signal_info *info; - int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || - (sig == SIGILL) || (sig == SIGTRAP)); - - if (segv) - get_skas_faultinfo(pid, ®s->skas.faultinfo); - info = &sig_info[sig]; - (*info->handler)(sig, regs); - - unblock_signals(); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 0d4c10a73607..b79f805bdc00 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -29,6 +29,7 @@ #ifdef CONFIG_MODE_SKAS #include "skas.h" #endif +#include "os.h" /* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */ int handle_page_fault(unsigned long address, unsigned long ip, @@ -125,6 +126,14 @@ out_of_memory: goto out; } +struct kern_handlers handlinfo_kern = { + .relay_signal = relay_signal, + .winch = winch, + .bus_handler = relay_signal, + .page_fault = segv_handler, + .sigio_handler = sigio_handler, + .timer_handler = timer_handler +}; /* * We give a *copy* of the faultinfo in the regs to segv. * This must be done, since nesting SEGVs could overwrite diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index e55110725124..5590b5739db9 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -25,20 +25,6 @@ #include "user_util.h" #include "os.h" -void kill_child_dead(int pid) -{ - kill(pid, SIGKILL); - kill(pid, SIGCONT); - do { - int n; - CATCH_EINTR(n = waitpid(pid, NULL, 0)); - if (n > 0) - kill(pid, SIGCONT); - else - break; - } while(1); -} - void segv_handler(int sig, union uml_pt_regs *regs) { struct faultinfo * fi = UPT_FAULTINFO(regs); @@ -55,43 +41,18 @@ void usr2_handler(int sig, union uml_pt_regs *regs) CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); } -struct signal_info sig_info[] = { - [ SIGTRAP ] { .handler = relay_signal, - .is_irq = 0 }, - [ SIGFPE ] { .handler = relay_signal, - .is_irq = 0 }, - [ SIGILL ] { .handler = relay_signal, - .is_irq = 0 }, - [ SIGWINCH ] { .handler = winch, - .is_irq = 1 }, - [ SIGBUS ] { .handler = bus_handler, - .is_irq = 0 }, - [ SIGSEGV] { .handler = segv_handler, - .is_irq = 0 }, - [ SIGIO ] { .handler = sigio_handler, - .is_irq = 1 }, - [ SIGVTALRM ] { .handler = timer_handler, - .is_irq = 1 }, - [ SIGALRM ] { .handler = timer_handler, - .is_irq = 1 }, - [ SIGUSR2 ] { .handler = usr2_handler, - .is_irq = 0 }, -}; +void (*sig_info[NSIG])(int, union uml_pt_regs *); -void do_longjmp(void *b, int val) +void os_fill_handlinfo(struct kern_handlers h) { - sigjmp_buf *buf = b; - - siglongjmp(*buf, val); + sig_info[SIGTRAP] = h.relay_signal; + sig_info[SIGFPE] = h.relay_signal; + sig_info[SIGILL] = h.relay_signal; + sig_info[SIGWINCH] = h.winch; + sig_info[SIGBUS] = h.bus_handler; + sig_info[SIGSEGV] = h.page_fault; + sig_info[SIGIO] = h.sigio_handler; + sig_info[SIGVTALRM] = h.timer_handler; + sig_info[SIGALRM] = h.timer_handler; + sig_info[SIGUSR2] = usr2_handler; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index 7501900f8941..a414c529fbcd 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -18,8 +18,8 @@ void sig_handler_common_tt(int sig, void *sc_ptr) { struct sigcontext *sc = sc_ptr; struct tt_regs save_regs, *r; - struct signal_info *info; int save_errno = errno, is_user; + void (*handler)(int, union uml_pt_regs *); /* This is done because to allow SIGSEGV to be delivered inside a SEGV * handler. This can happen in copy_user, and if SEGV is disabled, @@ -40,10 +40,14 @@ void sig_handler_common_tt(int sig, void *sc_ptr) if(sig != SIGUSR2) r->syscall = -1; - info = &sig_info[sig]; - if(!info->is_irq) unblock_signals(); + handler = sig_info[sig]; + + /* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */ + if (sig != SIGIO && sig != SIGWINCH && + sig != SIGVTALRM && sig != SIGALRM) + unblock_signals(); - (*info->handler)(sig, (union uml_pt_regs *) r); + handler(sig, (union uml_pt_regs *) r); if(is_user){ interrupt_end(); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 26626b2b9172..73747ac19774 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -363,6 +363,11 @@ int linux_main(int argc, char **argv) uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, &host_task_size, &task_size); + /* + * Setting up handlers to 'sig_info' struct + */ + os_fill_handlinfo(handlinfo_kern); + brk_start = (unsigned long) sbrk(0); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); /* Increase physical memory size for exec-shield users diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 11e30b13e318..40c7d6b1df68 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -4,11 +4,13 @@ # obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ - start_up.o time.o tt.o tty.o uaccess.o umid.o user_syms.o drivers/ \ - sys-$(SUBARCH)/ + start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ + drivers/ sys-$(SUBARCH)/ + +obj-$(CONFIG_MODE_SKAS) += skas/ USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ - start_up.o time.o tt.o tty.o uaccess.o umid.o + start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o elf_aux.o: $(ARCH_DIR)/kernel-offsets.h CFLAGS_elf_aux.o += -I$(objtree)/arch/um diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile new file mode 100644 index 000000000000..eab5386d60a7 --- /dev/null +++ b/arch/um/os-Linux/skas/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) +# Licensed under the GPL +# + +obj-y := trap.o + +USER_OBJS := trap.o + +include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c new file mode 100644 index 000000000000..818f30e9004f --- /dev/null +++ b/arch/um/os-Linux/skas/trap.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include +#include +#include "user_util.h" +#include "kern_util.h" +#include "task.h" +#include "sigcontext.h" +#include "skas.h" +#include "ptrace_user.h" +#include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" +#include "os.h" + +void sig_handler_common_skas(int sig, void *sc_ptr) +{ + struct sigcontext *sc = sc_ptr; + struct skas_regs *r; + void (*handler)(int, union uml_pt_regs *); + int save_errno = errno; + int save_user; + + /* This is done because to allow SIGSEGV to be delivered inside a SEGV + * handler. This can happen in copy_user, and if SEGV is disabled, + * the process will die. + * XXX Figure out why this is better than SA_NODEFER + */ + if(sig == SIGSEGV) + change_sig(SIGSEGV, 1); + + r = &TASK_REGS(get_current())->skas; + save_user = r->is_user; + r->is_user = 0; + if ( sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGILL || + sig == SIGTRAP ) { + GET_FAULTINFO_FROM_SC(r->faultinfo, sc); + } + + change_sig(SIGUSR1, 1); + + handler = sig_info[sig]; + + /* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */ + if (sig != SIGIO && sig != SIGWINCH && + sig != SIGVTALRM && sig != SIGALRM) + unblock_signals(); + + handler(sig, (union uml_pt_regs *) r); + + errno = save_errno; + r->is_user = save_user; +} + +extern int ptrace_faultinfo; + +void user_signal(int sig, union uml_pt_regs *regs, int pid) +{ + void (*handler)(int, union uml_pt_regs *); + int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || + (sig == SIGILL) || (sig == SIGTRAP)); + + if (segv) + get_skas_faultinfo(pid, ®s->skas.faultinfo); + + handler = sig_info[sig]; + handler(sig, (union uml_pt_regs *) regs); + + unblock_signals(); +} diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c new file mode 100644 index 000000000000..6e7841c23d26 --- /dev/null +++ b/arch/um/os-Linux/trap.c @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include "kern_util.h" +#include "user_util.h" +#include "os.h" + +void do_longjmp(void *b, int val) +{ + sigjmp_buf *buf = b; + + siglongjmp(*buf, val); +} diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index 37828e5b3526..cb2648b79d0f 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c @@ -49,6 +49,20 @@ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, return(0); } +void kill_child_dead(int pid) +{ + kill(pid, SIGKILL); + kill(pid, SIGCONT); + do { + int n; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + if (n > 0) + kill(pid, SIGCONT); + else + break; + } while(1); +} + /* *------------------------- * only for tt mode (will be deleted in future...) -- cgit v1.2.3 From c66fdd5e324392584c6f11de65cfe24b0e2d9303 Mon Sep 17 00:00:00 2001 From: Gennady Sharapov Date: Sun, 8 Jan 2006 01:01:32 -0800 Subject: [PATCH] uml: merge trap_user.c and trap_kern.c The serial UML OS-abstraction layer patch (um/kernel dir). This joins trap_user.c and trap_kernel.c files. Signed-off-by: Gennady Sharapov Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/Makefile | 2 +- arch/um/kernel/trap_kern.c | 14 +++++++++++ arch/um/kernel/trap_user.c | 58 ---------------------------------------------- arch/um/os-Linux/trap.c | 25 +++++++++++++++++++- 4 files changed, 39 insertions(+), 60 deletions(-) delete mode 100644 arch/um/kernel/trap_user.c diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 9ce6c57747a8..193cc2b7448d 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -10,7 +10,7 @@ obj-y = config.o exec_kern.o exitcode.o \ init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ signal_kern.o smp.o syscall_kern.o sysrq.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o umid.o \ + time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o \ user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index b79f805bdc00..d56046c2aba2 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -26,6 +26,9 @@ #include "mconsole_kern.h" #include "mem.h" #include "mem_kern.h" +#include "sysdep/sigcontext.h" +#include "sysdep/ptrace.h" +#include "os.h" #ifdef CONFIG_MODE_SKAS #include "skas.h" #endif @@ -126,6 +129,17 @@ out_of_memory: goto out; } +void segv_handler(int sig, union uml_pt_regs *regs) +{ + struct faultinfo * fi = UPT_FAULTINFO(regs); + + if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ + bad_segv(*fi, UPT_IP(regs)); + return; + } + segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); +} + struct kern_handlers handlinfo_kern = { .relay_signal = relay_signal, .winch = winch, diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c deleted file mode 100644 index 5590b5739db9..000000000000 --- a/arch/um/kernel/trap_user.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "sysdep/ptrace.h" -#include "sigcontext.h" -#include "sysdep/sigcontext.h" -#include "irq_user.h" -#include "time_user.h" -#include "task.h" -#include "mode.h" -#include "choose-mode.h" -#include "kern_util.h" -#include "user_util.h" -#include "os.h" - -void segv_handler(int sig, union uml_pt_regs *regs) -{ - struct faultinfo * fi = UPT_FAULTINFO(regs); - - if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ - bad_segv(*fi, UPT_IP(regs)); - return; - } - segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); -} - -void usr2_handler(int sig, union uml_pt_regs *regs) -{ - CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); -} - -void (*sig_info[NSIG])(int, union uml_pt_regs *); - -void os_fill_handlinfo(struct kern_handlers h) -{ - sig_info[SIGTRAP] = h.relay_signal; - sig_info[SIGFPE] = h.relay_signal; - sig_info[SIGILL] = h.relay_signal; - sig_info[SIGWINCH] = h.winch; - sig_info[SIGBUS] = h.bus_handler; - sig_info[SIGSEGV] = h.page_fault; - sig_info[SIGIO] = h.sigio_handler; - sig_info[SIGVTALRM] = h.timer_handler; - sig_info[SIGALRM] = h.timer_handler; - sig_info[SIGUSR2] = usr2_handler; -} diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c index 6e7841c23d26..321e1c8e227d 100644 --- a/arch/um/os-Linux/trap.c +++ b/arch/um/os-Linux/trap.c @@ -3,11 +3,34 @@ * Licensed under the GPL */ -#include +#include #include +#include #include "kern_util.h" #include "user_util.h" #include "os.h" +#include "mode.h" + +void usr2_handler(int sig, union uml_pt_regs *regs) +{ + CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); +} + +void (*sig_info[NSIG])(int, union uml_pt_regs *); + +void os_fill_handlinfo(struct kern_handlers h) +{ + sig_info[SIGTRAP] = h.relay_signal; + sig_info[SIGFPE] = h.relay_signal; + sig_info[SIGILL] = h.relay_signal; + sig_info[SIGWINCH] = h.winch; + sig_info[SIGBUS] = h.bus_handler; + sig_info[SIGSEGV] = h.page_fault; + sig_info[SIGIO] = h.sigio_handler; + sig_info[SIGVTALRM] = h.timer_handler; + sig_info[SIGALRM] = h.timer_handler; + sig_info[SIGUSR2] = usr2_handler; +} void do_longjmp(void *b, int val) { -- cgit v1.2.3 From f8aaeacec159f2d9003872781fa4d49659e347fb Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 8 Jan 2006 01:01:32 -0800 Subject: [PATCH] consolidate asm/futex.h Most of the architectures have the same asm/futex.h. This consolidates them into asm-generic, with the arches including it from their own asm/futex.h. In the case of UML, this reverts the old broken futex.h and goes back to using the same one as almost everyone else. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-alpha/futex.h | 49 +-------------------------------------- include/asm-arm/futex.h | 49 +-------------------------------------- include/asm-arm26/futex.h | 49 +-------------------------------------- include/asm-cris/futex.h | 49 +-------------------------------------- include/asm-generic/futex.h | 53 +++++++++++++++++++++++++++++++++++++++++++ include/asm-h8300/futex.h | 49 +-------------------------------------- include/asm-ia64/futex.h | 49 +-------------------------------------- include/asm-m32r/futex.h | 49 +-------------------------------------- include/asm-m68k/futex.h | 49 +-------------------------------------- include/asm-m68knommu/futex.h | 49 +-------------------------------------- include/asm-parisc/futex.h | 49 +-------------------------------------- include/asm-s390/futex.h | 49 +-------------------------------------- include/asm-sh/futex.h | 49 +-------------------------------------- include/asm-sh64/futex.h | 49 +-------------------------------------- include/asm-sparc/futex.h | 49 +-------------------------------------- include/asm-sparc64/futex.h | 49 +-------------------------------------- include/asm-um/futex.h | 12 +++------- include/asm-v850/futex.h | 49 +-------------------------------------- 18 files changed, 72 insertions(+), 777 deletions(-) create mode 100644 include/asm-generic/futex.h diff --git a/include/asm-alpha/futex.h b/include/asm-alpha/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-alpha/futex.h +++ b/include/asm-alpha/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-arm/futex.h b/include/asm-arm/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-arm/futex.h +++ b/include/asm-arm/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-arm26/futex.h b/include/asm-arm26/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-arm26/futex.h +++ b/include/asm-arm26/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-cris/futex.h b/include/asm-cris/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-cris/futex.h +++ b/include/asm-cris/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h new file mode 100644 index 000000000000..3ae2c7347549 --- /dev/null +++ b/include/asm-generic/futex.h @@ -0,0 +1,53 @@ +#ifndef _ASM_GENERIC_FUTEX_H +#define _ASM_GENERIC_FUTEX_H + +#ifdef __KERNEL__ + +#include +#include +#include + +static inline int +futex_atomic_op_inuser (int encoded_op, int __user *uaddr) +{ + int op = (encoded_op >> 28) & 7; + int cmp = (encoded_op >> 24) & 15; + int oparg = (encoded_op << 8) >> 20; + int cmparg = (encoded_op << 20) >> 20; + int oldval = 0, ret; + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) + oparg = 1 << oparg; + + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + inc_preempt_count(); + + switch (op) { + case FUTEX_OP_SET: + case FUTEX_OP_ADD: + case FUTEX_OP_OR: + case FUTEX_OP_ANDN: + case FUTEX_OP_XOR: + default: + ret = -ENOSYS; + } + + dec_preempt_count(); + + if (!ret) { + switch (cmp) { + case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; + case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; + case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; + case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; + case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; + case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; + default: ret = -ENOSYS; + } + } + return ret; +} + +#endif +#endif diff --git a/include/asm-h8300/futex.h b/include/asm-h8300/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-h8300/futex.h +++ b/include/asm-h8300/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-ia64/futex.h +++ b/include/asm-ia64/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-m32r/futex.h b/include/asm-m32r/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-m32r/futex.h +++ b/include/asm-m32r/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-m68k/futex.h b/include/asm-m68k/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-m68k/futex.h +++ b/include/asm-m68k/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-m68knommu/futex.h b/include/asm-m68knommu/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-m68knommu/futex.h +++ b/include/asm-m68knommu/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-parisc/futex.h +++ b/include/asm-parisc/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-s390/futex.h b/include/asm-s390/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-s390/futex.h +++ b/include/asm-s390/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-sh/futex.h b/include/asm-sh/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-sh/futex.h +++ b/include/asm-sh/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-sh64/futex.h b/include/asm-sh64/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-sh64/futex.h +++ b/include/asm-sh64/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-sparc/futex.h b/include/asm-sparc/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-sparc/futex.h +++ b/include/asm-sparc/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-sparc64/futex.h +++ b/include/asm-sparc64/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-um/futex.h b/include/asm-um/futex.h index 142ee2d8e0fd..6a332a9f099c 100644 --- a/include/asm-um/futex.h +++ b/include/asm-um/futex.h @@ -1,12 +1,6 @@ -#ifndef __UM_FUTEX_H -#define __UM_FUTEX_H +#ifndef _ASM_FUTEX_H +#define _ASM_FUTEX_H -#include -#include -#include -#include -#include - -#include "asm/arch/futex.h" +#include #endif diff --git a/include/asm-v850/futex.h b/include/asm-v850/futex.h index 9feff4ce1424..6a332a9f099c 100644 --- a/include/asm-v850/futex.h +++ b/include/asm-v850/futex.h @@ -1,53 +1,6 @@ #ifndef _ASM_FUTEX_H #define _ASM_FUTEX_H -#ifdef __KERNEL__ +#include -#include -#include -#include - -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } - - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif -- cgit v1.2.3 From c0a689d05d8dc1580aeb87b2959e3de8c57f5f77 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sun, 8 Jan 2006 01:01:33 -0800 Subject: [PATCH] uml: whitespace cleanup This fixes some mangled whitespace added by the earlier trap_user.c patch. Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/skas/trap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c index 818f30e9004f..9ad5fbec4593 100644 --- a/arch/um/os-Linux/skas/trap.c +++ b/arch/um/os-Linux/skas/trap.c @@ -34,11 +34,11 @@ void sig_handler_common_skas(int sig, void *sc_ptr) r = &TASK_REGS(get_current())->skas; save_user = r->is_user; r->is_user = 0; - if ( sig == SIGFPE || sig == SIGSEGV || - sig == SIGBUS || sig == SIGILL || - sig == SIGTRAP ) { - GET_FAULTINFO_FROM_SC(r->faultinfo, sc); - } + if ( sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGILL || + sig == SIGTRAP ) { + GET_FAULTINFO_FROM_SC(r->faultinfo, sc); + } change_sig(SIGUSR1, 1); @@ -60,8 +60,8 @@ extern int ptrace_faultinfo; void user_signal(int sig, union uml_pt_regs *regs, int pid) { void (*handler)(int, union uml_pt_regs *); - int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || - (sig == SIGILL) || (sig == SIGTRAP)); + int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || + (sig == SIGILL) || (sig == SIGTRAP)); if (segv) get_skas_faultinfo(pid, ®s->skas.faultinfo); -- cgit v1.2.3 From eafbaa94691f6a1fa67c3b076caa3ce4e2920100 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:01:34 -0800 Subject: [PATCH] uml: prevent MODE_SKAS=n and MODE_TT=n If MODE_TT=n, MODE_SKAS must be y. Signed-off-by: Adrian Bunk Acked-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 1eb21de9d1b5..cdaa2ab19258 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -83,7 +83,7 @@ config KERNEL_HALF_GIGS of physical memory. config MODE_SKAS - bool "Separate Kernel Address Space support" + bool "Separate Kernel Address Space support" if MODE_TT default y help This option controls whether skas (separate kernel address space) -- cgit v1.2.3 From 4369ef3c3e9d3bd9b879580678778f558d481e90 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 8 Jan 2006 01:01:35 -0800 Subject: [PATCH] Make RCU task_struct safe for oprofile Applying RCU to the task structure broke oprofile, because free_task_notify() can now be called from softirq. This means that the task_mortuary lock must be acquired with irq disabled in order to avoid intermittent self-deadlock. Since irq is now disabled, the critical section within process_task_mortuary() has been restructured to be O(1) in order to maximize scalability and minimize realtime latency degradation. Kudos to Wu Fengguang for finding this problem! CC: Wu Fengguang Cc: Philippe Elie Cc: John Levon Signed-off-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/oprofile/buffer_sync.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 531b07313141..b2e8e49c8659 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -43,13 +43,16 @@ static void process_task_mortuary(void); * list for processing. Only after two full buffer syncs * does the task eventually get freed, because by then * we are sure we will not reference it again. + * Can be invoked from softirq via RCU callback due to + * call_rcu() of the task struct, hence the _irqsave. */ static int task_free_notify(struct notifier_block * self, unsigned long val, void * data) { + unsigned long flags; struct task_struct * task = data; - spin_lock(&task_mortuary); + spin_lock_irqsave(&task_mortuary, flags); list_add(&task->tasks, &dying_tasks); - spin_unlock(&task_mortuary); + spin_unlock_irqrestore(&task_mortuary, flags); return NOTIFY_OK; } @@ -431,25 +434,22 @@ static void increment_tail(struct oprofile_cpu_buffer * b) */ static void process_task_mortuary(void) { - struct list_head * pos; - struct list_head * pos2; + unsigned long flags; + LIST_HEAD(local_dead_tasks); struct task_struct * task; + struct task_struct * ttask; - spin_lock(&task_mortuary); + spin_lock_irqsave(&task_mortuary, flags); - list_for_each_safe(pos, pos2, &dead_tasks) { - task = list_entry(pos, struct task_struct, tasks); - list_del(&task->tasks); - free_task(task); - } + list_splice_init(&dead_tasks, &local_dead_tasks); + list_splice_init(&dying_tasks, &dead_tasks); - list_for_each_safe(pos, pos2, &dying_tasks) { - task = list_entry(pos, struct task_struct, tasks); + spin_unlock_irqrestore(&task_mortuary, flags); + + list_for_each_entry_safe(task, ttask, &local_dead_tasks, tasks) { list_del(&task->tasks); - list_add_tail(&task->tasks, &dead_tasks); + free_task(task); } - - spin_unlock(&task_mortuary); } -- cgit v1.2.3 From e56d090310d7625ecb43a1eeebd479f04affb48b Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 8 Jan 2006 01:01:37 -0800 Subject: [PATCH] RCU signal handling RCU tasklist_lock and RCU signal handling: send signals RCU-read-locked instead of tasklist_lock read-locked. This is a scalability improvement on SMP and a preemption-latency improvement under PREEMPT_RCU. Signed-off-by: Paul E. McKenney Signed-off-by: Ingo Molnar Acked-by: William Irwin Cc: Roland McGrath Cc: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 4 +-- include/linux/sched.h | 32 +++++++++++++++-- kernel/exit.c | 1 - kernel/fork.c | 10 +++++- kernel/pid.c | 22 ++++++------ kernel/rcupdate.c | 1 + kernel/sched.c | 7 ++++ kernel/signal.c | 97 +++++++++++++++++++++++++++++++++++++++++++-------- 8 files changed, 143 insertions(+), 31 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index e75a9548da8e..e9650cd22a3b 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -760,7 +760,7 @@ no_thread_group: spin_lock(&oldsighand->siglock); spin_lock(&newsighand->siglock); - current->sighand = newsighand; + rcu_assign_pointer(current->sighand, newsighand); recalc_sigpending(); spin_unlock(&newsighand->siglock); @@ -768,7 +768,7 @@ no_thread_group: write_unlock_irq(&tasklist_lock); if (atomic_dec_and_test(&oldsighand->count)) - kmem_cache_free(sighand_cachep, oldsighand); + sighand_free(oldsighand); } BUG_ON(!thread_group_leader(current)); diff --git a/include/linux/sched.h b/include/linux/sched.h index a74662077d60..a6af77e9b4cf 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -34,6 +34,7 @@ #include #include #include +#include #include /* For AT_VECTOR_SIZE */ @@ -350,8 +351,16 @@ struct sighand_struct { atomic_t count; struct k_sigaction action[_NSIG]; spinlock_t siglock; + struct rcu_head rcu; }; +extern void sighand_free_cb(struct rcu_head *rhp); + +static inline void sighand_free(struct sighand_struct *sp) +{ + call_rcu(&sp->rcu, sighand_free_cb); +} + /* * NOTE! "signal_struct" does not have it's own * locking, because a shared signal_struct always @@ -844,6 +853,7 @@ struct task_struct { int cpuset_mems_generation; #endif atomic_t fs_excl; /* holding fs exclusive resources */ + struct rcu_head rcu; }; static inline pid_t process_group(struct task_struct *tsk) @@ -867,8 +877,26 @@ static inline int pid_alive(struct task_struct *p) extern void free_task(struct task_struct *tsk); extern void __put_task_struct(struct task_struct *tsk); #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) -#define put_task_struct(tsk) \ -do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) + +static inline int get_task_struct_rcu(struct task_struct *t) +{ + int oldusage; + + do { + oldusage = atomic_read(&t->usage); + if (oldusage == 0) + return 0; + } while (cmpxchg(&t->usage.counter, oldusage, oldusage+1) != oldusage); + return 1; +} + +extern void __put_task_struct_cb(struct rcu_head *rhp); + +static inline void put_task_struct(struct task_struct *t) +{ + if (atomic_dec_and_test(&t->usage)) + call_rcu(&t->rcu, __put_task_struct_cb); +} /* * Per process flags diff --git a/kernel/exit.c b/kernel/exit.c index ee515683b92d..c73a7eb26de3 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -72,7 +72,6 @@ repeat: __ptrace_unlink(p); BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); __exit_signal(p); - __exit_sighand(p); /* * Note that the fastpath in sys_times depends on __exit_signal having * updated the counters before a task is removed from the tasklist of diff --git a/kernel/fork.c b/kernel/fork.c index fb8572a42297..7fe3adfa65cb 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -743,6 +743,14 @@ int unshare_files(void) EXPORT_SYMBOL(unshare_files); +void sighand_free_cb(struct rcu_head *rhp) +{ + struct sighand_struct *sp; + + sp = container_of(rhp, struct sighand_struct, rcu); + kmem_cache_free(sighand_cachep, sp); +} + static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk) { struct sighand_struct *sig; @@ -752,7 +760,7 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * t return 0; } sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); - tsk->sighand = sig; + rcu_assign_pointer(tsk->sighand, sig); if (!sig) return -ENOMEM; spin_lock_init(&sig->siglock); diff --git a/kernel/pid.c b/kernel/pid.c index edba31c681ac..1acc07246991 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -136,7 +136,7 @@ struct pid * fastcall find_pid(enum pid_type type, int nr) struct hlist_node *elem; struct pid *pid; - hlist_for_each_entry(pid, elem, + hlist_for_each_entry_rcu(pid, elem, &pid_hash[type][pid_hashfn(nr)], pid_chain) { if (pid->nr == nr) return pid; @@ -150,15 +150,15 @@ int fastcall attach_pid(task_t *task, enum pid_type type, int nr) task_pid = &task->pids[type]; pid = find_pid(type, nr); + task_pid->nr = nr; if (pid == NULL) { - hlist_add_head(&task_pid->pid_chain, - &pid_hash[type][pid_hashfn(nr)]); INIT_LIST_HEAD(&task_pid->pid_list); + hlist_add_head_rcu(&task_pid->pid_chain, + &pid_hash[type][pid_hashfn(nr)]); } else { INIT_HLIST_NODE(&task_pid->pid_chain); - list_add_tail(&task_pid->pid_list, &pid->pid_list); + list_add_tail_rcu(&task_pid->pid_list, &pid->pid_list); } - task_pid->nr = nr; return 0; } @@ -170,20 +170,20 @@ static fastcall int __detach_pid(task_t *task, enum pid_type type) pid = &task->pids[type]; if (!hlist_unhashed(&pid->pid_chain)) { - hlist_del(&pid->pid_chain); - if (list_empty(&pid->pid_list)) + if (list_empty(&pid->pid_list)) { nr = pid->nr; - else { + hlist_del_rcu(&pid->pid_chain); + } else { pid_next = list_entry(pid->pid_list.next, struct pid, pid_list); /* insert next pid from pid_list to hash */ - hlist_add_head(&pid_next->pid_chain, - &pid_hash[type][pid_hashfn(pid_next->nr)]); + hlist_replace_rcu(&pid->pid_chain, + &pid_next->pid_chain); } } - list_del(&pid->pid_list); + list_del_rcu(&pid->pid_list); pid->nr = 0; return nr; diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index c9afc61240e4..0a669bd2f6d1 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/kernel/sched.c b/kernel/sched.c index 6f46c94cc29e..92733091154c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -176,6 +176,13 @@ static unsigned int task_timeslice(task_t *p) #define task_hot(p, now, sd) ((long long) ((now) - (p)->last_ran) \ < (long long) (sd)->cache_hot_time) +void __put_task_struct_cb(struct rcu_head *rhp) +{ + __put_task_struct(container_of(rhp, struct task_struct, rcu)); +} + +EXPORT_SYMBOL_GPL(__put_task_struct_cb); + /* * These are the runqueue data structures: */ diff --git a/kernel/signal.c b/kernel/signal.c index d7611f189ef7..64737c72dadd 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -329,13 +329,20 @@ void __exit_sighand(struct task_struct *tsk) /* Ok, we're done with the signal handlers */ tsk->sighand = NULL; if (atomic_dec_and_test(&sighand->count)) - kmem_cache_free(sighand_cachep, sighand); + sighand_free(sighand); } void exit_sighand(struct task_struct *tsk) { write_lock_irq(&tasklist_lock); - __exit_sighand(tsk); + rcu_read_lock(); + if (tsk->sighand != NULL) { + struct sighand_struct *sighand = rcu_dereference(tsk->sighand); + spin_lock(&sighand->siglock); + __exit_sighand(tsk); + spin_unlock(&sighand->siglock); + } + rcu_read_unlock(); write_unlock_irq(&tasklist_lock); } @@ -345,12 +352,14 @@ void exit_sighand(struct task_struct *tsk) void __exit_signal(struct task_struct *tsk) { struct signal_struct * sig = tsk->signal; - struct sighand_struct * sighand = tsk->sighand; + struct sighand_struct * sighand; if (!sig) BUG(); if (!atomic_read(&sig->count)) BUG(); + rcu_read_lock(); + sighand = rcu_dereference(tsk->sighand); spin_lock(&sighand->siglock); posix_cpu_timers_exit(tsk); if (atomic_dec_and_test(&sig->count)) { @@ -358,6 +367,7 @@ void __exit_signal(struct task_struct *tsk) if (tsk == sig->curr_target) sig->curr_target = next_thread(tsk); tsk->signal = NULL; + __exit_sighand(tsk); spin_unlock(&sighand->siglock); flush_sigqueue(&sig->shared_pending); } else { @@ -389,9 +399,11 @@ void __exit_signal(struct task_struct *tsk) sig->nvcsw += tsk->nvcsw; sig->nivcsw += tsk->nivcsw; sig->sched_time += tsk->sched_time; + __exit_sighand(tsk); spin_unlock(&sighand->siglock); sig = NULL; /* Marker for below. */ } + rcu_read_unlock(); clear_tsk_thread_flag(tsk,TIF_SIGPENDING); flush_sigqueue(&tsk->pending); if (sig) { @@ -1080,18 +1092,28 @@ void zap_other_threads(struct task_struct *p) } /* - * Must be called with the tasklist_lock held for reading! + * Must be called under rcu_read_lock() or with tasklist_lock read-held. */ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) { unsigned long flags; + struct sighand_struct *sp; int ret; +retry: ret = check_kill_permission(sig, info, p); - if (!ret && sig && p->sighand) { - spin_lock_irqsave(&p->sighand->siglock, flags); + if (!ret && sig && (sp = p->sighand)) { + if (!get_task_struct_rcu(p)) + return -ESRCH; + spin_lock_irqsave(&sp->siglock, flags); + if (p->sighand != sp) { + spin_unlock_irqrestore(&sp->siglock, flags); + put_task_struct(p); + goto retry; + } ret = __group_send_sig_info(sig, info, p); - spin_unlock_irqrestore(&p->sighand->siglock, flags); + spin_unlock_irqrestore(&sp->siglock, flags); + put_task_struct(p); } return ret; @@ -1136,14 +1158,21 @@ int kill_proc_info(int sig, struct siginfo *info, pid_t pid) { int error; + int acquired_tasklist_lock = 0; struct task_struct *p; - read_lock(&tasklist_lock); + rcu_read_lock(); + if (unlikely(sig_kernel_stop(sig) || sig == SIGCONT)) { + read_lock(&tasklist_lock); + acquired_tasklist_lock = 1; + } p = find_task_by_pid(pid); error = -ESRCH; if (p) error = group_send_sig_info(sig, info, p); - read_unlock(&tasklist_lock); + if (unlikely(acquired_tasklist_lock)) + read_unlock(&tasklist_lock); + rcu_read_unlock(); return error; } @@ -1355,16 +1384,54 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) { unsigned long flags; int ret = 0; + struct sighand_struct *sh; BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); - read_lock(&tasklist_lock); + + /* + * The rcu based delayed sighand destroy makes it possible to + * run this without tasklist lock held. The task struct itself + * cannot go away as create_timer did get_task_struct(). + * + * We return -1, when the task is marked exiting, so + * posix_timer_event can redirect it to the group leader + */ + rcu_read_lock(); if (unlikely(p->flags & PF_EXITING)) { ret = -1; goto out_err; } - spin_lock_irqsave(&p->sighand->siglock, flags); +retry: + sh = rcu_dereference(p->sighand); + + spin_lock_irqsave(&sh->siglock, flags); + if (p->sighand != sh) { + /* We raced with exec() in a multithreaded process... */ + spin_unlock_irqrestore(&sh->siglock, flags); + goto retry; + } + + /* + * We do the check here again to handle the following scenario: + * + * CPU 0 CPU 1 + * send_sigqueue + * check PF_EXITING + * interrupt exit code running + * __exit_signal + * lock sighand->siglock + * unlock sighand->siglock + * lock sh->siglock + * add(tsk->pending) flush_sigqueue(tsk->pending) + * + */ + + if (unlikely(p->flags & PF_EXITING)) { + ret = -1; + goto out; + } if (unlikely(!list_empty(&q->list))) { /* @@ -1388,9 +1455,9 @@ send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) signal_wake_up(p, sig == SIGKILL); out: - spin_unlock_irqrestore(&p->sighand->siglock, flags); + spin_unlock_irqrestore(&sh->siglock, flags); out_err: - read_unlock(&tasklist_lock); + rcu_read_unlock(); return ret; } @@ -1402,7 +1469,9 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) int ret = 0; BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); + read_lock(&tasklist_lock); + /* Since it_lock is held, p->sighand cannot be NULL. */ spin_lock_irqsave(&p->sighand->siglock, flags); handle_stop_signal(sig, p); @@ -1436,7 +1505,7 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) out: spin_unlock_irqrestore(&p->sighand->siglock, flags); read_unlock(&tasklist_lock); - return(ret); + return ret; } /* -- cgit v1.2.3 From 2d89c929078588aa9b9c674ef03ee9aa816b59b8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 8 Jan 2006 01:01:38 -0800 Subject: [PATCH] Simpler signal-exit concurrency handling Some simplification in checking signal delivery against concurrent exit. Instead of using get_task_struct_rcu(), which increments the task_struct reference count, check the reference count after acquiring sighand lock. Signed-off-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/signal.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 64737c72dadd..9b6fda5e87f1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1102,18 +1102,19 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) retry: ret = check_kill_permission(sig, info, p); - if (!ret && sig && (sp = p->sighand)) { - if (!get_task_struct_rcu(p)) - return -ESRCH; + if (!ret && sig && (sp = rcu_dereference(p->sighand))) { spin_lock_irqsave(&sp->siglock, flags); if (p->sighand != sp) { spin_unlock_irqrestore(&sp->siglock, flags); - put_task_struct(p); goto retry; } + if ((atomic_read(&sp->count) == 0) || + (atomic_read(&p->usage) == 0)) { + spin_unlock_irqrestore(&sp->siglock, flags); + return -ESRCH; + } ret = __group_send_sig_info(sig, info, p); spin_unlock_irqrestore(&sp->siglock, flags); - put_task_struct(p); } return ret; -- cgit v1.2.3 From d4829cd5b4bd1ea58ba1bebad44d562f4027c290 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 8 Jan 2006 01:01:39 -0800 Subject: [PATCH] remove get_task_struct_rcu() The latest set of signal-RCU patches does not use get_task_struct_rcu(). Attached is a patch that removes it. Signed-off-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index a6af77e9b4cf..20bd70749104 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -878,18 +878,6 @@ extern void free_task(struct task_struct *tsk); extern void __put_task_struct(struct task_struct *tsk); #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) -static inline int get_task_struct_rcu(struct task_struct *t) -{ - int oldusage; - - do { - oldusage = atomic_read(&t->usage); - if (oldusage == 0) - return 0; - } while (cmpxchg(&t->usage.counter, oldusage, oldusage+1) != oldusage); - return 1; -} - extern void __put_task_struct_cb(struct rcu_head *rhp); static inline void put_task_struct(struct task_struct *t) -- cgit v1.2.3 From 6e954b9e90c3a7157c0c1457dd3919e2a1345d23 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:01:40 -0800 Subject: [PATCH] radix tree: code consolidation Introduce helper any_tag_set() rather than repeat the same code sequence 4 times. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/radix-tree.c | 57 ++++++++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 88511c3805ad..1403e2c8bb3e 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -151,6 +151,20 @@ static inline int tag_get(struct radix_tree_node *node, int tag, int offset) return test_bit(offset, &node->tags[tag][0]); } +/* + * Returns 1 if any slot in the node has this tag set. + * Otherwise returns 0. + */ +static inline int any_tag_set(struct radix_tree_node *node, int tag) +{ + int idx; + for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { + if (node->tags[tag][idx]) + return 1; + } + return 0; +} + /* * Return the maximum key which can be store into a * radix tree with height HEIGHT. @@ -185,15 +199,9 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) * into the newly-pushed top-level node(s) */ for (tag = 0; tag < RADIX_TREE_TAGS; tag++) { - int idx; - tags[tag] = 0; - for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { - if (root->rnode->tags[tag][idx]) { - tags[tag] = 1; - break; - } - } + if (any_tag_set(root->rnode, tag)) + tags[tag] = 1; } do { @@ -427,13 +435,9 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, goto out; do { - int idx; - tag_clear(pathp->node, tag, pathp->offset); - for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { - if (pathp->node->tags[tag][idx]) - goto out; - } + if (any_tag_set(pathp->node, tag)) + goto out; pathp--; } while (pathp->node); out: @@ -729,19 +733,14 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) nr_cleared_tags = RADIX_TREE_TAGS; for (tag = 0; tag < RADIX_TREE_TAGS; tag++) { - int idx; - if (tags[tag]) continue; tag_clear(pathp->node, tag, pathp->offset); - for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { - if (pathp->node->tags[tag][idx]) { - tags[tag] = 1; - nr_cleared_tags--; - break; - } + if (any_tag_set(pathp->node, tag)) { + tags[tag] = 1; + nr_cleared_tags--; } } pathp--; @@ -770,15 +769,11 @@ EXPORT_SYMBOL(radix_tree_delete); */ int radix_tree_tagged(struct radix_tree_root *root, int tag) { - int idx; - - if (!root->rnode) - return 0; - for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { - if (root->rnode->tags[tag][idx]) - return 1; - } - return 0; + struct radix_tree_node *rnode; + rnode = root->rnode; + if (!rnode) + return 0; + return any_tag_set(rnode, tag); } EXPORT_SYMBOL(radix_tree_tagged); -- cgit v1.2.3 From d5274261ea46f0aae93820fe36628249120d2f75 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:01:41 -0800 Subject: [PATCH] radix tree: early termination of tag clearing Correctly determine the tags to be cleared in radix_tree_delete() so we don't keep moving up the tree clearing tags that we don't need to. For example, if a tag is simply not set in the deleted item, nor anywhere up the tree, radix_tree_delete() would attempt to clear it up the entire height of the tree. Also, tag_set() was made conditional so as not to dirty too many cachelines high up in the radix tree. Instead, put this logic into radix_tree_tag_set(). Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/radix-tree.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 1403e2c8bb3e..336852f23592 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -137,18 +137,17 @@ out: static inline void tag_set(struct radix_tree_node *node, int tag, int offset) { - if (!test_bit(offset, &node->tags[tag][0])) - __set_bit(offset, &node->tags[tag][0]); + __set_bit(offset, node->tags[tag]); } static inline void tag_clear(struct radix_tree_node *node, int tag, int offset) { - __clear_bit(offset, &node->tags[tag][0]); + __clear_bit(offset, node->tags[tag]); } static inline int tag_get(struct radix_tree_node *node, int tag, int offset) { - return test_bit(offset, &node->tags[tag][0]); + return test_bit(offset, node->tags[tag]); } /* @@ -375,7 +374,8 @@ void *radix_tree_tag_set(struct radix_tree_root *root, int offset; offset = (index >> shift) & RADIX_TREE_MAP_MASK; - tag_set(slot, tag, offset); + if (!tag_get(slot, tag, offset)) + tag_set(slot, tag, offset); slot = slot->slots[offset]; BUG_ON(slot == NULL); shift -= RADIX_TREE_MAP_SHIFT; @@ -435,6 +435,8 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, goto out; do { + if (!tag_get(pathp->node, tag, pathp->offset)) + goto out; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) goto out; @@ -695,6 +697,8 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) void *ret = NULL; char tags[RADIX_TREE_TAGS]; int nr_cleared_tags; + int tag; + int offset; height = root->height; if (index > radix_tree_maxindex(height)) @@ -705,16 +709,14 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) slot = root->rnode; for ( ; height > 0; height--) { - int offset; - if (slot == NULL) goto out; + pathp++; offset = (index >> shift) & RADIX_TREE_MAP_MASK; - pathp[1].offset = offset; - pathp[1].node = slot; + pathp->offset = offset; + pathp->node = slot; slot = slot->slots[offset]; - pathp++; shift -= RADIX_TREE_MAP_SHIFT; } @@ -727,24 +729,28 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) /* * Clear all tags associated with the just-deleted item */ - memset(tags, 0, sizeof(tags)); - do { - int tag; + nr_cleared_tags = 0; + for (tag = 0; tag < RADIX_TREE_TAGS; tag++) { + if (tag_get(pathp->node, tag, pathp->offset)) { + tag_clear(pathp->node, tag, pathp->offset); + tags[tag] = 0; + nr_cleared_tags++; + } else + tags[tag] = 1; + } - nr_cleared_tags = RADIX_TREE_TAGS; + for (pathp--; nr_cleared_tags && pathp->node; pathp--) { for (tag = 0; tag < RADIX_TREE_TAGS; tag++) { if (tags[tag]) continue; tag_clear(pathp->node, tag, pathp->offset); - if (any_tag_set(pathp->node, tag)) { tags[tag] = 1; nr_cleared_tags--; } } - pathp--; - } while (pathp->node && nr_cleared_tags); + } /* Now free the nodes we do not need anymore */ for (pathp = orig_pathp; pathp->node; pathp--) { -- cgit v1.2.3 From a5f51c966720fa519c6ce69b169107dbc5769cdf Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:01:41 -0800 Subject: [PATCH] radix-tree: reduce tree height upon partial truncation Shrink the height of a radix tree when it is partially truncated - we only do shrinkage of full truncation at present. Signed-off-by: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/radix-tree.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 336852f23592..c0bd4a914803 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -253,7 +253,7 @@ int radix_tree_insert(struct radix_tree_root *root, shift = (height-1) * RADIX_TREE_MAP_SHIFT; offset = 0; /* uninitialised var warning */ - while (height > 0) { + do { if (slot == NULL) { /* Have to add a child node. */ if (!(slot = radix_tree_node_alloc(root))) @@ -271,18 +271,16 @@ int radix_tree_insert(struct radix_tree_root *root, slot = node->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; - } + } while (height > 0); if (slot != NULL) return -EEXIST; - if (node) { - node->count++; - node->slots[offset] = item; - BUG_ON(tag_get(node, 0, offset)); - BUG_ON(tag_get(node, 1, offset)); - } else - root->rnode = item; + BUG_ON(!node); + node->count++; + node->slots[offset] = item; + BUG_ON(tag_get(node, 0, offset)); + BUG_ON(tag_get(node, 1, offset)); return 0; } @@ -679,6 +677,29 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, } EXPORT_SYMBOL(radix_tree_gang_lookup_tag); +/** + * radix_tree_shrink - shrink height of a radix tree to minimal + * @root radix tree root + */ +static inline void radix_tree_shrink(struct radix_tree_root *root) +{ + /* try to shrink tree height */ + while (root->height > 1 && + root->rnode->count == 1 && + root->rnode->slots[0]) { + struct radix_tree_node *to_free = root->rnode; + + root->rnode = to_free->slots[0]; + root->height--; + /* must only free zeroed nodes into the slab */ + tag_clear(to_free, 0, 0); + tag_clear(to_free, 1, 0); + to_free->slots[0] = NULL; + to_free->count = 0; + radix_tree_node_free(to_free); + } +} + /** * radix_tree_delete - delete an item from a radix tree * @root: radix tree root @@ -755,8 +776,13 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) /* Now free the nodes we do not need anymore */ for (pathp = orig_pathp; pathp->node; pathp--) { pathp->node->slots[pathp->offset] = NULL; - if (--pathp->node->count) + pathp->node->count--; + + if (pathp->node->count) { + if (pathp->node == root->rnode) + radix_tree_shrink(root); goto out; + } /* Node with zero slots in use so free it */ radix_tree_node_free(pathp->node); -- cgit v1.2.3 From 50dd26ba0947aa653f0e42897aad7a4adce4e620 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 8 Jan 2006 01:01:42 -0800 Subject: [PATCH] DEBUG_SLAB depends on SLAB Make DEBUG_SLAB depend on SLAB. Signed-off-by: Ingo Molnar Cc: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 80598cfd728c..c48260fb8fd9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -79,7 +79,7 @@ config SCHEDSTATS config DEBUG_SLAB bool "Debug memory allocations" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && SLAB help Say Y here to have the kernel do limited verification on memory allocation as well as poisoning memory on free to catch use of freed -- cgit v1.2.3 From 30992c97ae9d01b17374fbfab76a869fb4bba500 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:01:43 -0800 Subject: [PATCH] slob: introduce mm/util.c for shared functions Add mm/util.c for functions common between SLAB and SLOB. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/Makefile | 2 +- mm/slab.c | 37 ------------------------------------- mm/util.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 38 deletions(-) create mode 100644 mm/util.c diff --git a/mm/Makefile b/mm/Makefile index 2fa6d2ca9f28..74c85ddc9176 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -10,7 +10,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ page_alloc.o page-writeback.o pdflush.o \ readahead.o slab.o swap.o truncate.o vmscan.o \ - prio_tree.o $(mmu-y) + prio_tree.o util.o $(mmu-y) obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o diff --git a/mm/slab.c b/mm/slab.c index 76b092bd0bf7..1c46c6383552 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3052,20 +3052,6 @@ void kmem_cache_free(kmem_cache_t *cachep, void *objp) } EXPORT_SYMBOL(kmem_cache_free); -/** - * kzalloc - allocate memory. The memory is set to zero. - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - */ -void *kzalloc(size_t size, gfp_t flags) -{ - void *ret = kmalloc(size, flags); - if (ret) - memset(ret, 0, size); - return ret; -} -EXPORT_SYMBOL(kzalloc); - /** * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. @@ -3659,26 +3645,3 @@ unsigned int ksize(const void *objp) return obj_reallen(page_get_cache(virt_to_page(objp))); } - - -/* - * kstrdup - allocate space for and copy an existing string - * - * @s: the string to duplicate - * @gfp: the GFP mask used in the kmalloc() call when allocating memory - */ -char *kstrdup(const char *s, gfp_t gfp) -{ - size_t len; - char *buf; - - if (!s) - return NULL; - - len = strlen(s) + 1; - buf = kmalloc(len, gfp); - if (buf) - memcpy(buf, s, len); - return buf; -} -EXPORT_SYMBOL(kstrdup); diff --git a/mm/util.c b/mm/util.c new file mode 100644 index 000000000000..5f4bb59da63c --- /dev/null +++ b/mm/util.c @@ -0,0 +1,39 @@ +#include +#include +#include + +/** + * kzalloc - allocate memory. The memory is set to zero. + * @size: how many bytes of memory are required. + * @flags: the type of memory to allocate. + */ +void *kzalloc(size_t size, gfp_t flags) +{ + void *ret = kmalloc(size, flags); + if (ret) + memset(ret, 0, size); + return ret; +} +EXPORT_SYMBOL(kzalloc); + +/* + * kstrdup - allocate space for and copy an existing string + * + * @s: the string to duplicate + * @gfp: the GFP mask used in the kmalloc() call when allocating memory + */ +char *kstrdup(const char *s, gfp_t gfp) +{ + size_t len; + char *buf; + + if (!s) + return NULL; + + len = strlen(s) + 1; + buf = kmalloc(len, gfp); + if (buf) + memcpy(buf, s, len); + return buf; +} +EXPORT_SYMBOL(kstrdup); -- cgit v1.2.3 From 10cef6029502915bdb3cf0821d425cf9dc30c817 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:01:45 -0800 Subject: [PATCH] slob: introduce the SLOB allocator configurable replacement for slab allocator This adds a CONFIG_SLAB option under CONFIG_EMBEDDED. When CONFIG_SLAB is disabled, the kernel falls back to using the 'SLOB' allocator. SLOB is a traditional K&R/UNIX allocator with a SLAB emulation layer, similar to the original Linux kmalloc allocator that SLAB replaced. It's signicantly smaller code and is more memory efficient. But like all similar allocators, it scales poorly and suffers from fragmentation more than SLAB, so it's only appropriate for small systems. It's been tested extensively in the Linux-tiny tree. I've also stress-tested it with make -j 8 compiles on a 3G SMP+PREEMPT box (not recommended). Here's a comparison for otherwise identical builds, showing SLOB saving nearly half a megabyte of RAM: $ size vmlinux* text data bss dec hex filename 3336372 529360 190812 4056544 3de5e0 vmlinux-slab 3323208 527948 190684 4041840 3dac70 vmlinux-slob $ size mm/{slab,slob}.o text data bss dec hex filename 13221 752 48 14021 36c5 mm/slab.o 1896 52 8 1956 7a4 mm/slob.o /proc/meminfo: SLAB SLOB delta MemTotal: 27964 kB 27980 kB +16 kB MemFree: 24596 kB 25092 kB +496 kB Buffers: 36 kB 36 kB 0 kB Cached: 1188 kB 1188 kB 0 kB SwapCached: 0 kB 0 kB 0 kB Active: 608 kB 600 kB -8 kB Inactive: 808 kB 812 kB +4 kB HighTotal: 0 kB 0 kB 0 kB HighFree: 0 kB 0 kB 0 kB LowTotal: 27964 kB 27980 kB +16 kB LowFree: 24596 kB 25092 kB +496 kB SwapTotal: 0 kB 0 kB 0 kB SwapFree: 0 kB 0 kB 0 kB Dirty: 4 kB 12 kB +8 kB Writeback: 0 kB 0 kB 0 kB Mapped: 560 kB 556 kB -4 kB Slab: 1756 kB 0 kB -1756 kB CommitLimit: 13980 kB 13988 kB +8 kB Committed_AS: 4208 kB 4208 kB 0 kB PageTables: 28 kB 28 kB 0 kB VmallocTotal: 1007312 kB 1007312 kB 0 kB VmallocUsed: 48 kB 48 kB 0 kB VmallocChunk: 1007264 kB 1007264 kB 0 kB (this work has been sponsored in part by CELF) From: Ingo Molnar Fix 32-bitness bugs in mm/slob.c. Signed-off-by: Matt Mackall Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/proc_misc.c | 4 + include/linux/slab.h | 35 +++++ init/Kconfig | 13 ++ mm/Makefile | 4 +- mm/slob.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 mm/slob.c diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 5b6b0b6038a7..63bf6c00fa0c 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -323,6 +323,7 @@ static struct file_operations proc_modules_operations = { }; #endif +#ifdef CONFIG_SLAB extern struct seq_operations slabinfo_op; extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *); static int slabinfo_open(struct inode *inode, struct file *file) @@ -336,6 +337,7 @@ static struct file_operations proc_slabinfo_operations = { .llseek = seq_lseek, .release = seq_release, }; +#endif static int show_stat(struct seq_file *p, void *v) { @@ -600,7 +602,9 @@ void __init proc_misc_init(void) create_seq_entry("partitions", 0, &proc_partitions_operations); create_seq_entry("stat", 0, &proc_stat_operations); create_seq_entry("interrupts", 0, &proc_interrupts_operations); +#ifdef CONFIG_SLAB create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); +#endif create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations); diff --git a/include/linux/slab.h b/include/linux/slab.h index d1ea4051b996..1fb77a9cc148 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -53,6 +53,8 @@ typedef struct kmem_cache kmem_cache_t; #define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */ #define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */ +#ifndef CONFIG_SLOB + /* prototypes */ extern void __init kmem_cache_init(void); @@ -134,6 +136,39 @@ static inline void *kmalloc_node(size_t size, gfp_t flags, int node) extern int FASTCALL(kmem_cache_reap(int)); extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)); +#else /* CONFIG_SLOB */ + +/* SLOB allocator routines */ + +void kmem_cache_init(void); +struct kmem_cache *kmem_find_general_cachep(size_t, gfp_t gfpflags); +struct kmem_cache *kmem_cache_create(const char *c, size_t, size_t, + unsigned long, + void (*)(void *, struct kmem_cache *, unsigned long), + void (*)(void *, struct kmem_cache *, unsigned long)); +int kmem_cache_destroy(struct kmem_cache *c); +void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags); +void kmem_cache_free(struct kmem_cache *c, void *b); +const char *kmem_cache_name(struct kmem_cache *); +void *kmalloc(size_t size, gfp_t flags); +void *kzalloc(size_t size, gfp_t flags); +void kfree(const void *m); +unsigned int ksize(const void *m); +unsigned int kmem_cache_size(struct kmem_cache *c); + +static inline void *kcalloc(size_t n, size_t size, gfp_t flags) +{ + return kzalloc(n * size, flags); +} + +#define kmem_cache_shrink(d) (0) +#define kmem_cache_reap(a) +#define kmem_ptr_validate(a, b) (0) +#define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f) +#define kmalloc_node(s, f, n) kmalloc(s, f) + +#endif /* CONFIG_SLOB */ + /* System wide caches */ extern kmem_cache_t *vm_area_cachep; extern kmem_cache_t *names_cachep; diff --git a/init/Kconfig b/init/Kconfig index ba42f3793a84..0c9932f9f06b 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -380,6 +380,15 @@ config CC_ALIGN_JUMPS no dummy operations need be executed. Zero means use compiler's default. +config SLAB + default y + bool "Use full SLAB allocator" if EMBEDDED + help + Disabling this replaces the advanced SLAB allocator and + kmalloc support with the drastically simpler SLOB allocator. + SLOB is more space efficient but does not scale well and is + more susceptible to fragmentation. + endmenu # General setup config TINY_SHMEM @@ -391,6 +400,10 @@ config BASE_SMALL default 0 if BASE_FULL default 1 if !BASE_FULL +config SLOB + default !SLAB + bool + menu "Loadable module support" config MODULES diff --git a/mm/Makefile b/mm/Makefile index 74c85ddc9176..9aa03fa1dcc3 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -9,7 +9,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ page_alloc.o page-writeback.o pdflush.o \ - readahead.o slab.o swap.o truncate.o vmscan.o \ + readahead.o swap.o truncate.o vmscan.o \ prio_tree.o util.o $(mmu-y) obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o @@ -18,5 +18,7 @@ obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SPARSEMEM) += sparse.o obj-$(CONFIG_SHMEM) += shmem.o obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o +obj-$(CONFIG_SLOB) += slob.o +obj-$(CONFIG_SLAB) += slab.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o obj-$(CONFIG_FS_XIP) += filemap_xip.o diff --git a/mm/slob.c b/mm/slob.c new file mode 100644 index 000000000000..1c240c4b71d9 --- /dev/null +++ b/mm/slob.c @@ -0,0 +1,385 @@ +/* + * SLOB Allocator: Simple List Of Blocks + * + * Matt Mackall 12/30/03 + * + * How SLOB works: + * + * The core of SLOB is a traditional K&R style heap allocator, with + * support for returning aligned objects. The granularity of this + * allocator is 8 bytes on x86, though it's perhaps possible to reduce + * this to 4 if it's deemed worth the effort. The slob heap is a + * singly-linked list of pages from __get_free_page, grown on demand + * and allocation from the heap is currently first-fit. + * + * Above this is an implementation of kmalloc/kfree. Blocks returned + * from kmalloc are 8-byte aligned and prepended with a 8-byte header. + * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls + * __get_free_pages directly so that it can return page-aligned blocks + * and keeps a linked list of such pages and their orders. These + * objects are detected in kfree() by their page alignment. + * + * SLAB is emulated on top of SLOB by simply calling constructors and + * destructors for every SLAB allocation. Objects are returned with + * the 8-byte alignment unless the SLAB_MUST_HWCACHE_ALIGN flag is + * set, in which case the low-level allocator will fragment blocks to + * create the proper alignment. Again, objects of page-size or greater + * are allocated by calling __get_free_pages. As SLAB objects know + * their size, no separate size bookkeeping is necessary and there is + * essentially no allocation space overhead. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct slob_block { + int units; + struct slob_block *next; +}; +typedef struct slob_block slob_t; + +#define SLOB_UNIT sizeof(slob_t) +#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT) +#define SLOB_ALIGN L1_CACHE_BYTES + +struct bigblock { + int order; + void *pages; + struct bigblock *next; +}; +typedef struct bigblock bigblock_t; + +static slob_t arena = { .next = &arena, .units = 1 }; +static slob_t *slobfree = &arena; +static bigblock_t *bigblocks; +static DEFINE_SPINLOCK(slob_lock); +static DEFINE_SPINLOCK(block_lock); + +static void slob_free(void *b, int size); + +static void *slob_alloc(size_t size, gfp_t gfp, int align) +{ + slob_t *prev, *cur, *aligned = 0; + int delta = 0, units = SLOB_UNITS(size); + unsigned long flags; + + spin_lock_irqsave(&slob_lock, flags); + prev = slobfree; + for (cur = prev->next; ; prev = cur, cur = cur->next) { + if (align) { + aligned = (slob_t *)ALIGN((unsigned long)cur, align); + delta = aligned - cur; + } + if (cur->units >= units + delta) { /* room enough? */ + if (delta) { /* need to fragment head to align? */ + aligned->units = cur->units - delta; + aligned->next = cur->next; + cur->next = aligned; + cur->units = delta; + prev = cur; + cur = aligned; + } + + if (cur->units == units) /* exact fit? */ + prev->next = cur->next; /* unlink */ + else { /* fragment */ + prev->next = cur + units; + prev->next->units = cur->units - units; + prev->next->next = cur->next; + cur->units = units; + } + + slobfree = prev; + spin_unlock_irqrestore(&slob_lock, flags); + return cur; + } + if (cur == slobfree) { + spin_unlock_irqrestore(&slob_lock, flags); + + if (size == PAGE_SIZE) /* trying to shrink arena? */ + return 0; + + cur = (slob_t *)__get_free_page(gfp); + if (!cur) + return 0; + + slob_free(cur, PAGE_SIZE); + spin_lock_irqsave(&slob_lock, flags); + cur = slobfree; + } + } +} + +static void slob_free(void *block, int size) +{ + slob_t *cur, *b = (slob_t *)block; + unsigned long flags; + + if (!block) + return; + + if (size) + b->units = SLOB_UNITS(size); + + /* Find reinsertion point */ + spin_lock_irqsave(&slob_lock, flags); + for (cur = slobfree; !(b > cur && b < cur->next); cur = cur->next) + if (cur >= cur->next && (b > cur || b < cur->next)) + break; + + if (b + b->units == cur->next) { + b->units += cur->next->units; + b->next = cur->next->next; + } else + b->next = cur->next; + + if (cur + cur->units == b) { + cur->units += b->units; + cur->next = b->next; + } else + cur->next = b; + + slobfree = cur; + + spin_unlock_irqrestore(&slob_lock, flags); +} + +static int FASTCALL(find_order(int size)); +static int fastcall find_order(int size) +{ + int order = 0; + for ( ; size > 4096 ; size >>=1) + order++; + return order; +} + +void *kmalloc(size_t size, gfp_t gfp) +{ + slob_t *m; + bigblock_t *bb; + unsigned long flags; + + if (size < PAGE_SIZE - SLOB_UNIT) { + m = slob_alloc(size + SLOB_UNIT, gfp, 0); + return m ? (void *)(m + 1) : 0; + } + + bb = slob_alloc(sizeof(bigblock_t), gfp, 0); + if (!bb) + return 0; + + bb->order = find_order(size); + bb->pages = (void *)__get_free_pages(gfp, bb->order); + + if (bb->pages) { + spin_lock_irqsave(&block_lock, flags); + bb->next = bigblocks; + bigblocks = bb; + spin_unlock_irqrestore(&block_lock, flags); + return bb->pages; + } + + slob_free(bb, sizeof(bigblock_t)); + return 0; +} + +EXPORT_SYMBOL(kmalloc); + +void kfree(const void *block) +{ + bigblock_t *bb, **last = &bigblocks; + unsigned long flags; + + if (!block) + return; + + if (!((unsigned long)block & (PAGE_SIZE-1))) { + /* might be on the big block list */ + spin_lock_irqsave(&block_lock, flags); + for (bb = bigblocks; bb; last = &bb->next, bb = bb->next) { + if (bb->pages == block) { + *last = bb->next; + spin_unlock_irqrestore(&block_lock, flags); + free_pages((unsigned long)block, bb->order); + slob_free(bb, sizeof(bigblock_t)); + return; + } + } + spin_unlock_irqrestore(&block_lock, flags); + } + + slob_free((slob_t *)block - 1, 0); + return; +} + +EXPORT_SYMBOL(kfree); + +unsigned int ksize(const void *block) +{ + bigblock_t *bb; + unsigned long flags; + + if (!block) + return 0; + + if (!((unsigned long)block & (PAGE_SIZE-1))) { + spin_lock_irqsave(&block_lock, flags); + for (bb = bigblocks; bb; bb = bb->next) + if (bb->pages == block) { + spin_unlock_irqrestore(&slob_lock, flags); + return PAGE_SIZE << bb->order; + } + spin_unlock_irqrestore(&block_lock, flags); + } + + return ((slob_t *)block - 1)->units * SLOB_UNIT; +} + +struct kmem_cache { + unsigned int size, align; + const char *name; + void (*ctor)(void *, struct kmem_cache *, unsigned long); + void (*dtor)(void *, struct kmem_cache *, unsigned long); +}; + +struct kmem_cache *kmem_cache_create(const char *name, size_t size, + size_t align, unsigned long flags, + void (*ctor)(void*, struct kmem_cache *, unsigned long), + void (*dtor)(void*, struct kmem_cache *, unsigned long)) +{ + struct kmem_cache *c; + + c = slob_alloc(sizeof(struct kmem_cache), flags, 0); + + if (c) { + c->name = name; + c->size = size; + c->ctor = ctor; + c->dtor = dtor; + /* ignore alignment unless it's forced */ + c->align = (flags & SLAB_MUST_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; + if (c->align < align) + c->align = align; + } + + return c; +} +EXPORT_SYMBOL(kmem_cache_create); + +int kmem_cache_destroy(struct kmem_cache *c) +{ + slob_free(c, sizeof(struct kmem_cache)); + return 0; +} +EXPORT_SYMBOL(kmem_cache_destroy); + +void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags) +{ + void *b; + + if (c->size < PAGE_SIZE) + b = slob_alloc(c->size, flags, c->align); + else + b = (void *)__get_free_pages(flags, find_order(c->size)); + + if (c->ctor) + c->ctor(b, c, SLAB_CTOR_CONSTRUCTOR); + + return b; +} +EXPORT_SYMBOL(kmem_cache_alloc); + +void kmem_cache_free(struct kmem_cache *c, void *b) +{ + if (c->dtor) + c->dtor(b, c, 0); + + if (c->size < PAGE_SIZE) + slob_free(b, c->size); + else + free_pages((unsigned long)b, find_order(c->size)); +} +EXPORT_SYMBOL(kmem_cache_free); + +unsigned int kmem_cache_size(struct kmem_cache *c) +{ + return c->size; +} +EXPORT_SYMBOL(kmem_cache_size); + +const char *kmem_cache_name(struct kmem_cache *c) +{ + return c->name; +} +EXPORT_SYMBOL(kmem_cache_name); + +static struct timer_list slob_timer = TIMER_INITIALIZER( + (void (*)(unsigned long))kmem_cache_init, 0, 0); + +void kmem_cache_init(void) +{ + void *p = slob_alloc(PAGE_SIZE, 0, PAGE_SIZE-1); + + if (p) + free_page((unsigned long)p); + + mod_timer(&slob_timer, jiffies + HZ); +} + +atomic_t slab_reclaim_pages = ATOMIC_INIT(0); +EXPORT_SYMBOL(slab_reclaim_pages); + +#ifdef CONFIG_SMP + +void *__alloc_percpu(size_t size, size_t align) +{ + int i; + struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL); + + if (!pdata) + return NULL; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; + pdata->ptrs[i] = kmalloc(size, GFP_KERNEL); + if (!pdata->ptrs[i]) + goto unwind_oom; + memset(pdata->ptrs[i], 0, size); + } + + /* Catch derefs w/o wrappers */ + return (void *) (~(unsigned long) pdata); + +unwind_oom: + while (--i >= 0) { + if (!cpu_possible(i)) + continue; + kfree(pdata->ptrs[i]); + } + kfree(pdata); + return NULL; +} +EXPORT_SYMBOL(__alloc_percpu); + +void +free_percpu(const void *objp) +{ + int i; + struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp); + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; + kfree(p->ptrs[i]); + } + kfree(p); +} +EXPORT_SYMBOL(free_percpu); + +#endif -- cgit v1.2.3 From 96b7f34143c2c823a6a750fcb758fc66c44945d2 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:46 -0800 Subject: [PATCH] cpuset: better bitmap remap defaults Fix the default behaviour for the remap operators in bitmap, cpumask and nodemask. As previously submitted, the pair of masks defined a map of the positions of the set bits in A to the corresponding bits in B. This is still true. The issue is how to map the other positions, corresponding to the unset (0) bits in A. As previously submitted, they were all mapped to the first set bit position in B, a constant map. When I tried to code per-vma mempolicy rebinding using these remap operators, I realized this was wrong. This patch changes the default to map all the unset bit positions in A to the same positions in B, the identity map. For example, if A has bits 4-7 set, and B has bits 9-12 set, then the map defined by the pair maps each bit position in the first 32 bits as follows: 0 ==> 0 ... 3 ==> 3 4 ==> 9 ... 7 ==> 12 8 ==> 8 9 ==> 9 ... 31 ==> 31 This now corresponds to the typical behaviour desired when migrating pages and policies from one cpuset to another. The pages on nodes within the original cpuset, and the references in memory policies to nodes within the original cpuset, are migrated to the corresponding cpuset-relative nodes in the destination cpuset. Other pages and node references are left untouched. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/bitmap.c | 89 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/lib/bitmap.c b/lib/bitmap.c index 23d3b1147fe9..48e708381d44 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -519,7 +519,7 @@ EXPORT_SYMBOL(bitmap_parselist); * * Map the bit at position @pos in @buf (of length @bits) to the * ordinal of which set bit it is. If it is not set or if @pos - * is not a valid bit position, map to zero (0). + * is not a valid bit position, map to -1. * * If for example, just bits 4 through 7 are set in @buf, then @pos * values 4 through 7 will get mapped to 0 through 3, respectively, @@ -531,18 +531,19 @@ EXPORT_SYMBOL(bitmap_parselist); */ static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits) { - int ord = 0; + int i, ord; - if (pos >= 0 && pos < bits) { - int i; + if (pos < 0 || pos >= bits || !test_bit(pos, buf)) + return -1; - for (i = find_first_bit(buf, bits); - i < pos; - i = find_next_bit(buf, bits, i + 1)) - ord++; - if (i > pos) - ord = 0; + i = find_first_bit(buf, bits); + ord = 0; + while (i < pos) { + i = find_next_bit(buf, bits, i + 1); + ord++; } + BUG_ON(i != pos); + return ord; } @@ -553,11 +554,12 @@ static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits) * @bits: number of valid bit positions in @buf * * Map the ordinal offset of bit @ord in @buf to its position in @buf. - * If @ord is not the ordinal offset of a set bit in @buf, map to zero (0). + * Value of @ord should be in range 0 <= @ord < weight(buf), else + * results are undefined. * * If for example, just bits 4 through 7 are set in @buf, then @ord * values 0 through 3 will get mapped to 4 through 7, respectively, - * and all other @ord valuds will get mapped to 0. When @ord value 3 + * and all other @ord values return undefined values. When @ord value 3 * gets mapped to (returns) @pos value 7 in this example, that means * that the 3rd set bit (starting with 0th) is at position 7 in @buf. * @@ -583,8 +585,8 @@ static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits) /** * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap - * @src: subset to be remapped * @dst: remapped result + * @src: subset to be remapped * @old: defines domain of map * @new: defines range of map * @bits: number of bits in each of these bitmaps @@ -596,49 +598,42 @@ static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits) * weight of @old, map the position of the n-th set bit in @old to * the position of the m-th set bit in @new, where m == n % w. * - * If either of the @old and @new bitmaps are empty, or if@src and @dst - * point to the same location, then this routine does nothing. + * If either of the @old and @new bitmaps are empty, or if @src and + * @dst point to the same location, then this routine copies @src + * to @dst. * - * The positions of unset bits in @old are mapped to the position of - * the first set bit in @new. + * The positions of unset bits in @old are mapped to themselves + * (the identify map). * * Apply the above specified mapping to @src, placing the result in * @dst, clearing any bits previously set in @dst. * - * The resulting value of @dst will have either the same weight as - * @src, or less weight in the general case that the mapping wasn't - * injective due to the weight of @new being less than that of @old. - * The resulting value of @dst will never have greater weight than - * that of @src, except perhaps in the case that one of the above - * conditions was not met and this routine just returned. - * * For example, lets say that @old has bits 4 through 7 set, and * @new has bits 12 through 15 set. This defines the mapping of bit * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other - * bit positions to 12 (the first set bit in @new. So if say @src - * comes into this routine with bits 1, 5 and 7 set, then @dst should - * leave with bits 12, 13 and 15 set. + * bit positions unchanged. So if say @src comes into this routine + * with bits 1, 5 and 7 set, then @dst should leave with bits 1, + * 13 and 15 set. */ void bitmap_remap(unsigned long *dst, const unsigned long *src, const unsigned long *old, const unsigned long *new, int bits) { - int s; + int oldbit, w; - if (bitmap_weight(old, bits) == 0) - return; - if (bitmap_weight(new, bits) == 0) - return; if (dst == src) /* following doesn't handle inplace remaps */ return; - bitmap_zero(dst, bits); - for (s = find_first_bit(src, bits); - s < bits; - s = find_next_bit(src, bits, s + 1)) { - int x = bitmap_pos_to_ord(old, s, bits); - int y = bitmap_ord_to_pos(new, x, bits); - set_bit(y, dst); + + w = bitmap_weight(new, bits); + for (oldbit = find_first_bit(src, bits); + oldbit < bits; + oldbit = find_next_bit(src, bits, oldbit + 1)) { + int n = bitmap_pos_to_ord(old, oldbit, bits); + if (n < 0 || w == 0) + set_bit(oldbit, dst); /* identity map */ + else + set_bit(bitmap_ord_to_pos(new, n % w, bits), dst); } } EXPORT_SYMBOL(bitmap_remap); @@ -657,8 +652,8 @@ EXPORT_SYMBOL(bitmap_remap); * weight of @old, map the position of the n-th set bit in @old to * the position of the m-th set bit in @new, where m == n % w. * - * The positions of unset bits in @old are mapped to the position of - * the first set bit in @new. + * The positions of unset bits in @old are mapped to themselves + * (the identify map). * * Apply the above specified mapping to bit position @oldbit, returning * the new bit position. @@ -666,14 +661,18 @@ EXPORT_SYMBOL(bitmap_remap); * For example, lets say that @old has bits 4 through 7 set, and * @new has bits 12 through 15 set. This defines the mapping of bit * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other - * bit positions to 12 (the first set bit in @new. So if say @oldbit - * is 5, then this routine returns 13. + * bit positions unchanged. So if say @oldbit is 5, then this routine + * returns 13. */ int bitmap_bitremap(int oldbit, const unsigned long *old, const unsigned long *new, int bits) { - int x = bitmap_pos_to_ord(old, oldbit, bits); - return bitmap_ord_to_pos(new, x, bits); + int w = bitmap_weight(new, bits); + int n = bitmap_pos_to_ord(old, oldbit, bits); + if (n < 0 || w == 0) + return oldbit; + else + return bitmap_ord_to_pos(new, n % w, bits); } EXPORT_SYMBOL(bitmap_bitremap); -- cgit v1.2.3 From 5966514db662fb24c9bb43226a80106bcffd51f8 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:47 -0800 Subject: [PATCH] cpuset: mempolicy one more nodemask conversion Finish converting mm/mempolicy.c from bitmaps to nodemasks. The previous conversion had left one routine using bitmaps, since it involved a corresponding change to kernel/cpuset.c Fix that interface by replacing with a simple macro that calls nodes_subset(), or if !CONFIG_CPUSET, returns (1). Signed-off-by: Paul Jackson Cc: Christoph Lameter Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 5 +++-- kernel/cpuset.c | 10 ---------- mm/mempolicy.c | 5 ++--- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 6e2deef96b34..8b21786490ee 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -21,7 +21,8 @@ extern void cpuset_exit(struct task_struct *p); extern cpumask_t cpuset_cpus_allowed(const struct task_struct *p); void cpuset_init_current_mems_allowed(void); void cpuset_update_current_mems_allowed(void); -void cpuset_restrict_to_mems_allowed(unsigned long *nodes); +#define cpuset_nodes_subset_current_mems_allowed(nodes) \ + nodes_subset((nodes), current->mems_allowed) int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl); extern int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask); extern int cpuset_excl_nodes_overlap(const struct task_struct *p); @@ -42,7 +43,7 @@ static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p) static inline void cpuset_init_current_mems_allowed(void) {} static inline void cpuset_update_current_mems_allowed(void) {} -static inline void cpuset_restrict_to_mems_allowed(unsigned long *nodes) {} +#define cpuset_nodes_subset_current_mems_allowed(nodes) (1) static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl) { diff --git a/kernel/cpuset.c b/kernel/cpuset.c index f63383e01ec7..6503c6da4c4f 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1749,16 +1749,6 @@ done: refresh_mems(); } -/** - * cpuset_restrict_to_mems_allowed - limit nodes to current mems_allowed - * @nodes: pointer to a node bitmap that is and-ed with mems_allowed - */ -void cpuset_restrict_to_mems_allowed(unsigned long *nodes) -{ - bitmap_and(nodes, nodes, nodes_addr(current->mems_allowed), - MAX_NUMNODES); -} - /** * cpuset_zonelist_valid_mems_allowed - check zonelist vs. curremt mems_allowed * @zl: the zonelist to be checked diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 7051fe450e96..9dea2b8a7d48 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -387,10 +387,9 @@ static int contextualize_policy(int mode, nodemask_t *nodes) if (!nodes) return 0; - /* Update current mems_allowed */ cpuset_update_current_mems_allowed(); - /* Ignore nodes not set in current->mems_allowed */ - cpuset_restrict_to_mems_allowed(nodes->bits); + if (!cpuset_nodes_subset_current_mems_allowed(*nodes)) + return -EINVAL; return mpol_check_policy(mode, nodes); } -- cgit v1.2.3 From 3e0d98b9f1eb757fc98efc84e74e54a08308aa73 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:49 -0800 Subject: [PATCH] cpuset: memory pressure meter Provide a simple per-cpuset metric of memory pressure, tracking the -rate- that the tasks in a cpuset call try_to_free_pages(), the synchronous (direct) memory reclaim code. This enables batch managers monitoring jobs running in dedicated cpusets to efficiently detect what level of memory pressure that job is causing. This is useful both on tightly managed systems running a wide mix of submitted jobs, which may choose to terminate or reprioritize jobs that are trying to use more memory than allowed on the nodes assigned them, and with tightly coupled, long running, massively parallel scientific computing jobs that will dramatically fail to meet required performance goals if they start to use more memory than allowed to them. This patch just provides a very economical way for the batch manager to monitor a cpuset for signs of memory pressure. It's up to the batch manager or other user code to decide what to do about it and take action. ==> Unless this feature is enabled by writing "1" to the special file /dev/cpuset/memory_pressure_enabled, the hook in the rebalance code of __alloc_pages() for this metric reduces to simply noticing that the cpuset_memory_pressure_enabled flag is zero. So only systems that enable this feature will compute the metric. Why a per-cpuset, running average: Because this meter is per-cpuset, rather than per-task or mm, the system load imposed by a batch scheduler monitoring this metric is sharply reduced on large systems, because a scan of the tasklist can be avoided on each set of queries. Because this meter is a running average, instead of an accumulating counter, a batch scheduler can detect memory pressure with a single read, instead of having to read and accumulate results for a period of time. Because this meter is per-cpuset rather than per-task or mm, the batch scheduler can obtain the key information, memory pressure in a cpuset, with a single read, rather than having to query and accumulate results over all the (dynamically changing) set of tasks in the cpuset. A per-cpuset simple digital filter (requires a spinlock and 3 words of data per-cpuset) is kept, and updated by any task attached to that cpuset, if it enters the synchronous (direct) page reclaim code. A per-cpuset file provides an integer number representing the recent (half-life of 10 seconds) rate of direct page reclaims caused by the tasks in the cpuset, in units of reclaims attempted per second, times 1000. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 11 +++ kernel/cpuset.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++- mm/page_alloc.c | 1 + 3 files changed, 203 insertions(+), 2 deletions(-) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 8b21786490ee..736d73801cb6 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -26,6 +26,15 @@ void cpuset_update_current_mems_allowed(void); int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl); extern int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask); extern int cpuset_excl_nodes_overlap(const struct task_struct *p); + +#define cpuset_memory_pressure_bump() \ + do { \ + if (cpuset_memory_pressure_enabled) \ + __cpuset_memory_pressure_bump(); \ + } while (0) +extern int cpuset_memory_pressure_enabled; +extern void __cpuset_memory_pressure_bump(void); + extern struct file_operations proc_cpuset_operations; extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer); @@ -60,6 +69,8 @@ static inline int cpuset_excl_nodes_overlap(const struct task_struct *p) return 1; } +static inline void cpuset_memory_pressure_bump(void) {} + static inline char *cpuset_task_status_allowed(struct task_struct *task, char *buffer) { diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 6503c6da4c4f..5a06fef669f8 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -56,6 +56,15 @@ #define CPUSET_SUPER_MAGIC 0x27e0eb +/* See "Frequency meter" comments, below. */ + +struct fmeter { + int cnt; /* unprocessed events count */ + int val; /* most recent output value */ + time_t time; /* clock (secs) when val computed */ + spinlock_t lock; /* guards read or write of above */ +}; + struct cpuset { unsigned long flags; /* "unsigned long" so bitops work */ cpumask_t cpus_allowed; /* CPUs allowed to tasks in cpuset */ @@ -80,7 +89,9 @@ struct cpuset { * Copy of global cpuset_mems_generation as of the most * recent time this cpuset changed its mems_allowed. */ - int mems_generation; + int mems_generation; + + struct fmeter fmeter; /* memory_pressure filter */ }; /* bits in struct cpuset flags field */ @@ -149,7 +160,7 @@ static struct cpuset top_cpuset = { }; static struct vfsmount *cpuset_mount; -static struct super_block *cpuset_sb = NULL; +static struct super_block *cpuset_sb; /* * We have two global cpuset semaphores below. They can nest. @@ -806,6 +817,19 @@ static int update_nodemask(struct cpuset *cs, char *buf) return retval; } +/* + * Call with manage_sem held. + */ + +static int update_memory_pressure_enabled(struct cpuset *cs, char *buf) +{ + if (simple_strtoul(buf, NULL, 10) != 0) + cpuset_memory_pressure_enabled = 1; + else + cpuset_memory_pressure_enabled = 0; + return 0; +} + /* * update_flag - read a 0 or a 1 in a file and update associated flag * bit: the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, @@ -847,6 +871,104 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) return 0; } +/* + * Frequency meter - How fast is some event occuring? + * + * These routines manage a digitally filtered, constant time based, + * event frequency meter. There are four routines: + * fmeter_init() - initialize a frequency meter. + * fmeter_markevent() - called each time the event happens. + * fmeter_getrate() - returns the recent rate of such events. + * fmeter_update() - internal routine used to update fmeter. + * + * A common data structure is passed to each of these routines, + * which is used to keep track of the state required to manage the + * frequency meter and its digital filter. + * + * The filter works on the number of events marked per unit time. + * The filter is single-pole low-pass recursive (IIR). The time unit + * is 1 second. Arithmetic is done using 32-bit integers scaled to + * simulate 3 decimal digits of precision (multiplied by 1000). + * + * With an FM_COEF of 933, and a time base of 1 second, the filter + * has a half-life of 10 seconds, meaning that if the events quit + * happening, then the rate returned from the fmeter_getrate() + * will be cut in half each 10 seconds, until it converges to zero. + * + * It is not worth doing a real infinitely recursive filter. If more + * than FM_MAXTICKS ticks have elapsed since the last filter event, + * just compute FM_MAXTICKS ticks worth, by which point the level + * will be stable. + * + * Limit the count of unprocessed events to FM_MAXCNT, so as to avoid + * arithmetic overflow in the fmeter_update() routine. + * + * Given the simple 32 bit integer arithmetic used, this meter works + * best for reporting rates between one per millisecond (msec) and + * one per 32 (approx) seconds. At constant rates faster than one + * per msec it maxes out at values just under 1,000,000. At constant + * rates between one per msec, and one per second it will stabilize + * to a value N*1000, where N is the rate of events per second. + * At constant rates between one per second and one per 32 seconds, + * it will be choppy, moving up on the seconds that have an event, + * and then decaying until the next event. At rates slower than + * about one in 32 seconds, it decays all the way back to zero between + * each event. + */ + +#define FM_COEF 933 /* coefficient for half-life of 10 secs */ +#define FM_MAXTICKS ((time_t)99) /* useless computing more ticks than this */ +#define FM_MAXCNT 1000000 /* limit cnt to avoid overflow */ +#define FM_SCALE 1000 /* faux fixed point scale */ + +/* Initialize a frequency meter */ +static void fmeter_init(struct fmeter *fmp) +{ + fmp->cnt = 0; + fmp->val = 0; + fmp->time = 0; + spin_lock_init(&fmp->lock); +} + +/* Internal meter update - process cnt events and update value */ +static void fmeter_update(struct fmeter *fmp) +{ + time_t now = get_seconds(); + time_t ticks = now - fmp->time; + + if (ticks == 0) + return; + + ticks = min(FM_MAXTICKS, ticks); + while (ticks-- > 0) + fmp->val = (FM_COEF * fmp->val) / FM_SCALE; + fmp->time = now; + + fmp->val += ((FM_SCALE - FM_COEF) * fmp->cnt) / FM_SCALE; + fmp->cnt = 0; +} + +/* Process any previous ticks, then bump cnt by one (times scale). */ +static void fmeter_markevent(struct fmeter *fmp) +{ + spin_lock(&fmp->lock); + fmeter_update(fmp); + fmp->cnt = min(FM_MAXCNT, fmp->cnt + FM_SCALE); + spin_unlock(&fmp->lock); +} + +/* Process any previous ticks, then return current value. */ +static int fmeter_getrate(struct fmeter *fmp) +{ + int val; + + spin_lock(&fmp->lock); + fmeter_update(fmp); + val = fmp->val; + spin_unlock(&fmp->lock); + return val; +} + /* * Attack task specified by pid in 'pidbuf' to cpuset 'cs', possibly * writing the path of the old cpuset in 'ppathbuf' if it needs to be @@ -931,6 +1053,8 @@ typedef enum { FILE_CPU_EXCLUSIVE, FILE_MEM_EXCLUSIVE, FILE_NOTIFY_ON_RELEASE, + FILE_MEMORY_PRESSURE_ENABLED, + FILE_MEMORY_PRESSURE, FILE_TASKLIST, } cpuset_filetype_t; @@ -984,6 +1108,12 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us case FILE_MEMORY_MIGRATE: retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer); break; + case FILE_MEMORY_PRESSURE_ENABLED: + retval = update_memory_pressure_enabled(cs, buffer); + break; + case FILE_MEMORY_PRESSURE: + retval = -EACCES; + break; case FILE_TASKLIST: retval = attach_task(cs, buffer, &pathbuf); break; @@ -1087,6 +1217,12 @@ static ssize_t cpuset_common_file_read(struct file *file, char __user *buf, case FILE_MEMORY_MIGRATE: *s++ = is_memory_migrate(cs) ? '1' : '0'; break; + case FILE_MEMORY_PRESSURE_ENABLED: + *s++ = cpuset_memory_pressure_enabled ? '1' : '0'; + break; + case FILE_MEMORY_PRESSURE: + s += sprintf(s, "%d", fmeter_getrate(&cs->fmeter)); + break; default: retval = -EINVAL; goto out; @@ -1440,6 +1576,16 @@ static struct cftype cft_memory_migrate = { .private = FILE_MEMORY_MIGRATE, }; +static struct cftype cft_memory_pressure_enabled = { + .name = "memory_pressure_enabled", + .private = FILE_MEMORY_PRESSURE_ENABLED, +}; + +static struct cftype cft_memory_pressure = { + .name = "memory_pressure", + .private = FILE_MEMORY_PRESSURE, +}; + static int cpuset_populate_dir(struct dentry *cs_dentry) { int err; @@ -1456,6 +1602,8 @@ static int cpuset_populate_dir(struct dentry *cs_dentry) return err; if ((err = cpuset_add_file(cs_dentry, &cft_memory_migrate)) < 0) return err; + if ((err = cpuset_add_file(cs_dentry, &cft_memory_pressure)) < 0) + return err; if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0) return err; return 0; @@ -1491,6 +1639,7 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode) INIT_LIST_HEAD(&cs->children); atomic_inc(&cpuset_mems_generation); cs->mems_generation = atomic_read(&cpuset_mems_generation); + fmeter_init(&cs->fmeter); cs->parent = parent; @@ -1580,6 +1729,7 @@ int __init cpuset_init(void) top_cpuset.cpus_allowed = CPU_MASK_ALL; top_cpuset.mems_allowed = NODE_MASK_ALL; + fmeter_init(&top_cpuset.fmeter); atomic_inc(&cpuset_mems_generation); top_cpuset.mems_generation = atomic_read(&cpuset_mems_generation); @@ -1601,6 +1751,9 @@ int __init cpuset_init(void) top_cpuset.dentry = root; root->d_inode->i_op = &cpuset_dir_inode_operations; err = cpuset_populate_dir(root); + /* memory_pressure_enabled is in root cpuset only */ + if (err == 0) + err = cpuset_add_file(root, &cft_memory_pressure_enabled); out: return err; } @@ -1890,6 +2043,42 @@ done: return overlap; } +/* + * Collection of memory_pressure is suppressed unless + * this flag is enabled by writing "1" to the special + * cpuset file 'memory_pressure_enabled' in the root cpuset. + */ + +int cpuset_memory_pressure_enabled; + +/** + * cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims. + * + * Keep a running average of the rate of synchronous (direct) + * page reclaim efforts initiated by tasks in each cpuset. + * + * This represents the rate at which some task in the cpuset + * ran low on memory on all nodes it was allowed to use, and + * had to enter the kernels page reclaim code in an effort to + * create more free memory by tossing clean pages or swapping + * or writing dirty pages. + * + * Display to user space in the per-cpuset read-only file + * "memory_pressure". Value displayed is an integer + * representing the recent rate of entry into the synchronous + * (direct) page reclaim by any task attached to the cpuset. + **/ + +void __cpuset_memory_pressure_bump(void) +{ + struct cpuset *cs; + + task_lock(current); + cs = current->cpuset; + fmeter_markevent(&cs->fmeter); + task_unlock(current); +} + /* * proc_cpuset_show() * - Print tasks cpuset path into seq_file. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ad3d0202cdef..e0e84924171b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -976,6 +976,7 @@ rebalance: cond_resched(); /* We now go into synchronous reclaim */ + cpuset_memory_pressure_bump(); p->flags |= PF_MEMALLOC; reclaim_state.reclaimed_slab = 0; p->reclaim_state = &reclaim_state; -- cgit v1.2.3 From bd5e09cf7054878a3db6a8c8bab1c2fabcd4f072 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:50 -0800 Subject: [PATCH] cpuset: document additional features Document the additional cpuset features: notify_on_release marker_pid memory_pressure memory_pressure_enabled Rearrange and improve formatting of existing documentation for cpu_exclusive and mem_exclusive features. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpusets.txt | 178 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 153 insertions(+), 25 deletions(-) diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index e2d9afc30d2d..ef83b2dd0cb3 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -14,7 +14,11 @@ CONTENTS: 1.1 What are cpusets ? 1.2 Why are cpusets needed ? 1.3 How are cpusets implemented ? - 1.4 How do I use cpusets ? + 1.4 What are exclusive cpusets ? + 1.5 What does notify_on_release do ? + 1.6 What is a marker_pid ? + 1.7 What is memory_pressure ? + 1.8 How do I use cpusets ? 2. Usage Examples and Syntax 2.1 Basic Usage 2.2 Adding/removing cpus @@ -49,29 +53,6 @@ its cpus_allowed vector, and the kernel page allocator will not allocate a page on a node that is not allowed in the requesting tasks mems_allowed vector. -If a cpuset is cpu or mem exclusive, no other cpuset, other than a direct -ancestor or descendent, may share any of the same CPUs or Memory Nodes. -A cpuset that is cpu exclusive has a sched domain associated with it. -The sched domain consists of all cpus in the current cpuset that are not -part of any exclusive child cpusets. -This ensures that the scheduler load balacing code only balances -against the cpus that are in the sched domain as defined above and not -all of the cpus in the system. This removes any overhead due to -load balancing code trying to pull tasks outside of the cpu exclusive -cpuset only to be prevented by the tasks' cpus_allowed mask. - -A cpuset that is mem_exclusive restricts kernel allocations for -page, buffer and other data commonly shared by the kernel across -multiple users. All cpusets, whether mem_exclusive or not, restrict -allocations of memory for user space. This enables configuring a -system so that several independent jobs can share common kernel -data, such as file system pages, while isolating each jobs user -allocation in its own cpuset. To do this, construct a large -mem_exclusive cpuset to hold all the jobs, and construct child, -non-mem_exclusive cpusets for each individual job. Only a small -amount of typical kernel memory, such as requests from interrupt -handlers, is allowed to be taken outside even a mem_exclusive cpuset. - User level code may create and destroy cpusets by name in the cpuset virtual file system, manage the attributes and permissions of these cpusets and which CPUs and Memory Nodes are assigned to each cpuset, @@ -196,6 +177,12 @@ containing the following files describing that cpuset: - cpu_exclusive flag: is cpu placement exclusive? - mem_exclusive flag: is memory placement exclusive? - tasks: list of tasks (by pid) attached to that cpuset + - notify_on_release flag: run /sbin/cpuset_release_agent on exit? + - marker_pid: pid of user task in co-ordinated operation sequence + - memory_pressure: measure of how much paging pressure in cpuset + +In addition, the root cpuset only has the following file: + - memory_pressure_enabled flag: compute memory_pressure? New cpusets are created using the mkdir system call or shell command. The properties of a cpuset, such as its flags, allowed @@ -229,7 +216,148 @@ exclusive cpuset. Also, the use of a Linux virtual file system (vfs) to represent the cpuset hierarchy provides for a familiar permission and name space for cpusets, with a minimum of additional kernel code. -1.4 How do I use cpusets ? + +1.4 What are exclusive cpusets ? +-------------------------------- + +If a cpuset is cpu or mem exclusive, no other cpuset, other than +a direct ancestor or descendent, may share any of the same CPUs or +Memory Nodes. + +A cpuset that is cpu_exclusive has a scheduler (sched) domain +associated with it. The sched domain consists of all CPUs in the +current cpuset that are not part of any exclusive child cpusets. +This ensures that the scheduler load balancing code only balances +against the CPUs that are in the sched domain as defined above and +not all of the CPUs in the system. This removes any overhead due to +load balancing code trying to pull tasks outside of the cpu_exclusive +cpuset only to be prevented by the tasks' cpus_allowed mask. + +A cpuset that is mem_exclusive restricts kernel allocations for +page, buffer and other data commonly shared by the kernel across +multiple users. All cpusets, whether mem_exclusive or not, restrict +allocations of memory for user space. This enables configuring a +system so that several independent jobs can share common kernel data, +such as file system pages, while isolating each jobs user allocation in +its own cpuset. To do this, construct a large mem_exclusive cpuset to +hold all the jobs, and construct child, non-mem_exclusive cpusets for +each individual job. Only a small amount of typical kernel memory, +such as requests from interrupt handlers, is allowed to be taken +outside even a mem_exclusive cpuset. + + +1.5 What does notify_on_release do ? +------------------------------------ + +If the notify_on_release flag is enabled (1) in a cpuset, then whenever +the last task in the cpuset leaves (exits or attaches to some other +cpuset) and the last child cpuset of that cpuset is removed, then +the kernel runs the command /sbin/cpuset_release_agent, supplying the +pathname (relative to the mount point of the cpuset file system) of the +abandoned cpuset. This enables automatic removal of abandoned cpusets. +The default value of notify_on_release in the root cpuset at system +boot is disabled (0). The default value of other cpusets at creation +is the current value of their parents notify_on_release setting. + + +1.6 What is a marker_pid ? +-------------------------- + +The marker_pid helps manage cpuset changes safely from user space. + +The interface presented to user space for cpusets uses system wide +numbering of CPUs and Memory Nodes. It is the responsibility of +user level code, presumably in a library, to present cpuset-relative +numbering to applications when that would be more useful to them. + +However if a task is moved to a different cpuset, or if the 'cpus' or +'mems' of a cpuset are changed, then we need a way for such library +code to detect that its cpuset-relative numbering has changed, when +expressed using system wide numbering. + +The kernel cannot safely allow user code to lock kernel resources. +The kernel could deliver out-of-band notice of cpuset changes by +such mechanisms as signals or usermodehelper callbacks, however +this can't be synchronously delivered to library code linked in +applications without intruding on the IPC mechanisms available to +the app. The kernel could require user level code to do all the work, +tracking the cpuset state before and during changes, to verify no +unexpected change occurred, but this becomes an onerous task. + +The "marker_pid" cpuset field provides a simple way to make this task +less onerous on user library code. A task writes its pid to a cpusets +"marker_pid" at the start of a sequence of queries and updates, +and check as it goes that the cpusets marker_pid doesn't change. +The pread(2) system call does a seek and read in a single call. +If the marker_pid changes, the user code should retry the required +sequence of operations. + +Anytime that a task modifies the "cpus" or "mems" of a cpuset, +unless it's pid is in the cpusets marker_pid field, the kernel zeros +this field. + +The above was inspired by the load linked and store conditional +(ll/sc) instructions in the MIPS II instruction set. + + +1.7 What is memory_pressure ? +----------------------------- +The memory_pressure of a cpuset provides a simple per-cpuset metric +of the rate that the tasks in a cpuset are attempting to free up in +use memory on the nodes of the cpuset to satisfy additional memory +requests. + +This enables batch managers monitoring jobs running in dedicated +cpusets to efficiently detect what level of memory pressure that job +is causing. + +This is useful both on tightly managed systems running a wide mix of +submitted jobs, which may choose to terminate or re-prioritize jobs that +are trying to use more memory than allowed on the nodes assigned them, +and with tightly coupled, long running, massively parallel scientific +computing jobs that will dramatically fail to meet required performance +goals if they start to use more memory than allowed to them. + +This mechanism provides a very economical way for the batch manager +to monitor a cpuset for signs of memory pressure. It's up to the +batch manager or other user code to decide what to do about it and +take action. + +==> Unless this feature is enabled by writing "1" to the special file + /dev/cpuset/memory_pressure_enabled, the hook in the rebalance + code of __alloc_pages() for this metric reduces to simply noticing + that the cpuset_memory_pressure_enabled flag is zero. So only + systems that enable this feature will compute the metric. + +Why a per-cpuset, running average: + + Because this meter is per-cpuset, rather than per-task or mm, + the system load imposed by a batch scheduler monitoring this + metric is sharply reduced on large systems, because a scan of + the tasklist can be avoided on each set of queries. + + Because this meter is a running average, instead of an accumulating + counter, a batch scheduler can detect memory pressure with a + single read, instead of having to read and accumulate results + for a period of time. + + Because this meter is per-cpuset rather than per-task or mm, + the batch scheduler can obtain the key information, memory + pressure in a cpuset, with a single read, rather than having to + query and accumulate results over all the (dynamically changing) + set of tasks in the cpuset. + +A per-cpuset simple digital filter (requires a spinlock and 3 words +of data per-cpuset) is kept, and updated by any task attached to that +cpuset, if it enters the synchronous (direct) page reclaim code. + +A per-cpuset file provides an integer number representing the recent +(half-life of 10 seconds) rate of direct page reclaims caused by +the tasks in the cpuset, in units of reclaims attempted per second, +times 1000. + + +1.8 How do I use cpusets ? -------------------------- In order to minimize the impact of cpusets on critical kernel -- cgit v1.2.3 From 90c9cc4043fd8454d11886379f841f70e176698e Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:51 -0800 Subject: [PATCH] cpuset: remove marker_pid documentation Remove documentation for the cpuset 'marker_pid' feature, that was in the patch "cpuset: change marker for relative numbering" That patch was previously pulled from *-mm at my (pj) request. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpusets.txt | 50 ++++------------------------------------------- 1 file changed, 4 insertions(+), 46 deletions(-) diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index ef83b2dd0cb3..9e49b1c35729 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -16,9 +16,8 @@ CONTENTS: 1.3 How are cpusets implemented ? 1.4 What are exclusive cpusets ? 1.5 What does notify_on_release do ? - 1.6 What is a marker_pid ? - 1.7 What is memory_pressure ? - 1.8 How do I use cpusets ? + 1.6 What is memory_pressure ? + 1.7 How do I use cpusets ? 2. Usage Examples and Syntax 2.1 Basic Usage 2.2 Adding/removing cpus @@ -178,7 +177,6 @@ containing the following files describing that cpuset: - mem_exclusive flag: is memory placement exclusive? - tasks: list of tasks (by pid) attached to that cpuset - notify_on_release flag: run /sbin/cpuset_release_agent on exit? - - marker_pid: pid of user task in co-ordinated operation sequence - memory_pressure: measure of how much paging pressure in cpuset In addition, the root cpuset only has the following file: @@ -260,47 +258,7 @@ boot is disabled (0). The default value of other cpusets at creation is the current value of their parents notify_on_release setting. -1.6 What is a marker_pid ? --------------------------- - -The marker_pid helps manage cpuset changes safely from user space. - -The interface presented to user space for cpusets uses system wide -numbering of CPUs and Memory Nodes. It is the responsibility of -user level code, presumably in a library, to present cpuset-relative -numbering to applications when that would be more useful to them. - -However if a task is moved to a different cpuset, or if the 'cpus' or -'mems' of a cpuset are changed, then we need a way for such library -code to detect that its cpuset-relative numbering has changed, when -expressed using system wide numbering. - -The kernel cannot safely allow user code to lock kernel resources. -The kernel could deliver out-of-band notice of cpuset changes by -such mechanisms as signals or usermodehelper callbacks, however -this can't be synchronously delivered to library code linked in -applications without intruding on the IPC mechanisms available to -the app. The kernel could require user level code to do all the work, -tracking the cpuset state before and during changes, to verify no -unexpected change occurred, but this becomes an onerous task. - -The "marker_pid" cpuset field provides a simple way to make this task -less onerous on user library code. A task writes its pid to a cpusets -"marker_pid" at the start of a sequence of queries and updates, -and check as it goes that the cpusets marker_pid doesn't change. -The pread(2) system call does a seek and read in a single call. -If the marker_pid changes, the user code should retry the required -sequence of operations. - -Anytime that a task modifies the "cpus" or "mems" of a cpuset, -unless it's pid is in the cpusets marker_pid field, the kernel zeros -this field. - -The above was inspired by the load linked and store conditional -(ll/sc) instructions in the MIPS II instruction set. - - -1.7 What is memory_pressure ? +1.6 What is memory_pressure ? ----------------------------- The memory_pressure of a cpuset provides a simple per-cpuset metric of the rate that the tasks in a cpuset are attempting to free up in @@ -357,7 +315,7 @@ the tasks in the cpuset, in units of reclaims attempted per second, times 1000. -1.8 How do I use cpusets ? +1.7 How do I use cpusets ? -------------------------- In order to minimize the impact of cpusets on critical kernel -- cgit v1.2.3 From c5b2aff89635495064592dc90da595f8a880ee87 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:51 -0800 Subject: [PATCH] cpuset: minor spacing initializer fixes Four trivial cpuset fixes: remove extra spaces, remove useless initializers, mark one __read_mostly. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 5a06fef669f8..f513dd937eee 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -54,7 +54,7 @@ #include #include -#define CPUSET_SUPER_MAGIC 0x27e0eb +#define CPUSET_SUPER_MAGIC 0x27e0eb /* See "Frequency meter" comments, below. */ @@ -154,9 +154,6 @@ static struct cpuset top_cpuset = { .count = ATOMIC_INIT(0), .sibling = LIST_HEAD_INIT(top_cpuset.sibling), .children = LIST_HEAD_INIT(top_cpuset.children), - .parent = NULL, - .dentry = NULL, - .mems_generation = 0, }; static struct vfsmount *cpuset_mount; @@ -1341,7 +1338,7 @@ static int cpuset_create_file(struct dentry *dentry, int mode) /* * cpuset_create_dir - create a directory for an object. - * cs: the cpuset we create the directory for. + * cs: the cpuset we create the directory for. * It must have a valid ->parent field * And we are going to fill its ->dentry field. * name: The name to give to the cpuset directory. Will be copied. @@ -2049,7 +2046,7 @@ done: * cpuset file 'memory_pressure_enabled' in the root cpuset. */ -int cpuset_memory_pressure_enabled; +int cpuset_memory_pressure_enabled __read_mostly; /** * cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims. -- cgit v1.2.3 From 59dac16fb95f09253b8086134443abeb439703cd Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:52 -0800 Subject: [PATCH] cpuset: update_nodemask code reformat Restructure code layout of the kernel/cpuset.c update_nodemask() routine, removing embedded returns and nested if's in favor of goto completion labels. This is being done in anticipation of adding more logic to this routine, which will favor the goto style structure. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index f513dd937eee..3ea63da11d71 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -799,18 +799,23 @@ static int update_nodemask(struct cpuset *cs, char *buf) trialcs = *cs; retval = nodelist_parse(buf, trialcs.mems_allowed); if (retval < 0) - return retval; + goto done; nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map); - if (nodes_empty(trialcs.mems_allowed)) - return -ENOSPC; - retval = validate_change(cs, &trialcs); - if (retval == 0) { - down(&callback_sem); - cs->mems_allowed = trialcs.mems_allowed; - atomic_inc(&cpuset_mems_generation); - cs->mems_generation = atomic_read(&cpuset_mems_generation); - up(&callback_sem); + if (nodes_empty(trialcs.mems_allowed)) { + retval = -ENOSPC; + goto done; } + retval = validate_change(cs, &trialcs); + if (retval < 0) + goto done; + + down(&callback_sem); + cs->mems_allowed = trialcs.mems_allowed; + atomic_inc(&cpuset_mems_generation); + cs->mems_generation = atomic_read(&cpuset_mems_generation); + up(&callback_sem); + +done: return retval; } -- cgit v1.2.3 From b4b2641843db124637fa3d2cb2101982035dcc82 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:53 -0800 Subject: [PATCH] cpuset: fork hook fix Fix obscure, never seen in real life, cpuset fork race. The cpuset_fork() call in fork.c was setting up the correct task->cpuset pointer after the tasklist_lock was dropped, which briefly exposed the newly forked process with an unsafe (copied from parent without locks or usage counter increment) cpuset pointer. In theory, that exposed cpuset pointer could have been pointing at a cpuset that was already freed and removed, and in theory another task that had been sitting on the tasklist_lock waiting to scan the task list could have raced down the entire tasklist, found our new child at the far end, and dereferenced that bogus cpuset pointer. To fix, setup up the correct cpuset pointer in the new child by calling cpuset_fork() before the new task is linked into the tasklist, and with that, add a fork failure case, to dereference that cpuset, if the fork fails along the way, after cpuset_fork() was called. Had to remove a BUG_ON() from cpuset_exit(), because it was no longer valid - the call to cpuset_exit() from a failed fork would not have PF_EXITING set. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 4 +--- kernel/fork.c | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 3ea63da11d71..d9349cc48b95 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1821,15 +1821,13 @@ void cpuset_fork(struct task_struct *child) * * We don't need to task_lock() this reference to tsk->cpuset, * because tsk is already marked PF_EXITING, so attach_task() won't - * mess with it. + * mess with it, or task is a failed fork, never visible to attach_task. **/ void cpuset_exit(struct task_struct *tsk) { struct cpuset *cs; - BUG_ON(!(tsk->flags & PF_EXITING)); - cs = tsk->cpuset; tsk->cpuset = NULL; diff --git a/kernel/fork.c b/kernel/fork.c index 7fe3adfa65cb..7992ee759d89 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -972,12 +972,13 @@ static task_t *copy_process(unsigned long clone_flags, p->io_context = NULL; p->io_wait = NULL; p->audit_context = NULL; + cpuset_fork(p); #ifdef CONFIG_NUMA p->mempolicy = mpol_copy(p->mempolicy); if (IS_ERR(p->mempolicy)) { retval = PTR_ERR(p->mempolicy); p->mempolicy = NULL; - goto bad_fork_cleanup; + goto bad_fork_cleanup_cpuset; } #endif @@ -1148,7 +1149,6 @@ static task_t *copy_process(unsigned long clone_flags, total_forks++; write_unlock_irq(&tasklist_lock); proc_fork_connector(p); - cpuset_fork(p); retval = 0; fork_out: @@ -1180,7 +1180,9 @@ bad_fork_cleanup_security: bad_fork_cleanup_policy: #ifdef CONFIG_NUMA mpol_free(p->mempolicy); +bad_fork_cleanup_cpuset: #endif + cpuset_exit(p); bad_fork_cleanup: if (p->binfmt) module_put(p->binfmt->module); -- cgit v1.2.3 From cf2a473c4089aa41c26f653200673f5a4cc25047 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:54 -0800 Subject: [PATCH] cpuset: combine refresh_mems and update_mems The important code paths through alloc_pages_current() and alloc_page_vma(), by which most kernel page allocations go, both called cpuset_update_current_mems_allowed(), which in turn called refresh_mems(). -Both- of these latter two routines did a tasklock, got the tasks cpuset pointer, and checked for out of date cpuset->mems_generation. That was a silly duplication of code and waste of CPU cycles on an important code path. Consolidated those two routines into a single routine, called cpuset_update_task_memory_state(), since it updates more than just mems_allowed. Changed all callers of either routine to call the new consolidated routine. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 4 +-- kernel/cpuset.c | 95 ++++++++++++++++++++++---------------------------- mm/mempolicy.c | 10 +++--- 3 files changed, 48 insertions(+), 61 deletions(-) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 736d73801cb6..1feebf16ab08 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -20,7 +20,7 @@ extern void cpuset_fork(struct task_struct *p); extern void cpuset_exit(struct task_struct *p); extern cpumask_t cpuset_cpus_allowed(const struct task_struct *p); void cpuset_init_current_mems_allowed(void); -void cpuset_update_current_mems_allowed(void); +void cpuset_update_task_memory_state(void); #define cpuset_nodes_subset_current_mems_allowed(nodes) \ nodes_subset((nodes), current->mems_allowed) int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl); @@ -51,7 +51,7 @@ static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p) } static inline void cpuset_init_current_mems_allowed(void) {} -static inline void cpuset_update_current_mems_allowed(void) {} +static inline void cpuset_update_task_memory_state(void) {} #define cpuset_nodes_subset_current_mems_allowed(nodes) (1) static inline int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index d9349cc48b95..e9917d71628a 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -584,13 +584,26 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask) BUG_ON(!nodes_intersects(*pmask, node_online_map)); } -/* - * Refresh current tasks mems_allowed and mems_generation from current - * tasks cpuset. +/** + * cpuset_update_task_memory_state - update task memory placement * - * Call without callback_sem or task_lock() held. May be called with - * or without manage_sem held. Will acquire task_lock() and might - * acquire callback_sem during call. + * If the current tasks cpusets mems_allowed changed behind our + * backs, update current->mems_allowed, mems_generation and task NUMA + * mempolicy to the new value. + * + * Task mempolicy is updated by rebinding it relative to the + * current->cpuset if a task has its memory placement changed. + * Do not call this routine if in_interrupt(). + * + * Call without callback_sem or task_lock() held. May be called + * with or without manage_sem held. Except in early boot or + * an exiting task, when tsk->cpuset is NULL, this routine will + * acquire task_lock(). We don't need to use task_lock to guard + * against another task changing a non-NULL cpuset pointer to NULL, + * as that is only done by a task on itself, and if the current task + * is here, it is not simultaneously in the exit code NULL'ing its + * cpuset pointer. This routine also might acquire callback_sem and + * current->mm->mmap_sem during call. * * The task_lock() is required to dereference current->cpuset safely. * Without it, we could pick up the pointer value of current->cpuset @@ -605,32 +618,36 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask) * task has been modifying its cpuset. */ -static void refresh_mems(void) +void cpuset_update_task_memory_state() { int my_cpusets_mem_gen; + struct task_struct *tsk = current; + struct cpuset *cs = tsk->cpuset; - task_lock(current); - my_cpusets_mem_gen = current->cpuset->mems_generation; - task_unlock(current); + if (unlikely(!cs)) + return; + + task_lock(tsk); + my_cpusets_mem_gen = cs->mems_generation; + task_unlock(tsk); - if (current->cpuset_mems_generation != my_cpusets_mem_gen) { - struct cpuset *cs; - nodemask_t oldmem = current->mems_allowed; + if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) { + nodemask_t oldmem = tsk->mems_allowed; int migrate; down(&callback_sem); - task_lock(current); - cs = current->cpuset; + task_lock(tsk); + cs = tsk->cpuset; /* Maybe changed when task not locked */ migrate = is_memory_migrate(cs); - guarantee_online_mems(cs, ¤t->mems_allowed); - current->cpuset_mems_generation = cs->mems_generation; - task_unlock(current); + guarantee_online_mems(cs, &tsk->mems_allowed); + tsk->cpuset_mems_generation = cs->mems_generation; + task_unlock(tsk); up(&callback_sem); - if (!nodes_equal(oldmem, current->mems_allowed)) { - numa_policy_rebind(&oldmem, ¤t->mems_allowed); + numa_policy_rebind(&oldmem, &tsk->mems_allowed); + if (!nodes_equal(oldmem, tsk->mems_allowed)) { if (migrate) { - do_migrate_pages(current->mm, &oldmem, - ¤t->mems_allowed, + do_migrate_pages(tsk->mm, &oldmem, + &tsk->mems_allowed, MPOL_MF_MOVE_ALL); } } @@ -1630,7 +1647,7 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode) return -ENOMEM; down(&manage_sem); - refresh_mems(); + cpuset_update_task_memory_state(); cs->flags = 0; if (notify_on_release(parent)) set_bit(CS_NOTIFY_ON_RELEASE, &cs->flags); @@ -1688,7 +1705,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) /* the vfs holds both inode->i_sem already */ down(&manage_sem); - refresh_mems(); + cpuset_update_task_memory_state(); if (atomic_read(&cs->count) > 0) { up(&manage_sem); return -EBUSY; @@ -1872,36 +1889,6 @@ void cpuset_init_current_mems_allowed(void) current->mems_allowed = NODE_MASK_ALL; } -/** - * cpuset_update_current_mems_allowed - update mems parameters to new values - * - * If the current tasks cpusets mems_allowed changed behind our backs, - * update current->mems_allowed and mems_generation to the new value. - * Do not call this routine if in_interrupt(). - * - * Call without callback_sem or task_lock() held. May be called - * with or without manage_sem held. Unless exiting, it will acquire - * task_lock(). Also might acquire callback_sem during call to - * refresh_mems(). - */ - -void cpuset_update_current_mems_allowed(void) -{ - struct cpuset *cs; - int need_to_refresh = 0; - - task_lock(current); - cs = current->cpuset; - if (!cs) - goto done; - if (current->cpuset_mems_generation != cs->mems_generation) - need_to_refresh = 1; -done: - task_unlock(current); - if (need_to_refresh) - refresh_mems(); -} - /** * cpuset_zonelist_valid_mems_allowed - check zonelist vs. curremt mems_allowed * @zl: the zonelist to be checked diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 9dea2b8a7d48..515bfeee027e 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -387,7 +387,7 @@ static int contextualize_policy(int mode, nodemask_t *nodes) if (!nodes) return 0; - cpuset_update_current_mems_allowed(); + cpuset_update_task_memory_state(); if (!cpuset_nodes_subset_current_mems_allowed(*nodes)) return -EINVAL; return mpol_check_policy(mode, nodes); @@ -461,7 +461,7 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask, struct vm_area_struct *vma = NULL; struct mempolicy *pol = current->mempolicy; - cpuset_update_current_mems_allowed(); + cpuset_update_task_memory_state(); if (flags & ~(unsigned long)(MPOL_F_NODE|MPOL_F_ADDR)) return -EINVAL; if (flags & MPOL_F_ADDR) { @@ -1089,7 +1089,7 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr) { struct mempolicy *pol = get_vma_policy(current, vma, addr); - cpuset_update_current_mems_allowed(); + cpuset_update_task_memory_state(); if (unlikely(pol->policy == MPOL_INTERLEAVE)) { unsigned nid; @@ -1115,7 +1115,7 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr) * interrupt context and apply the current process NUMA policy. * Returns NULL when no page can be allocated. * - * Don't call cpuset_update_current_mems_allowed() unless + * Don't call cpuset_update_task_memory_state() unless * 1) it's ok to take cpuset_sem (can WAIT), and * 2) allocating for current task (not interrupt). */ @@ -1124,7 +1124,7 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order) struct mempolicy *pol = current->mempolicy; if ((gfp & __GFP_WAIT) && !in_interrupt()) - cpuset_update_current_mems_allowed(); + cpuset_update_task_memory_state(); if (!pol || in_interrupt()) pol = &default_policy; if (pol->policy == MPOL_INTERLEAVE) -- cgit v1.2.3 From 909d75a3b77bdd8baa9429bad3b69a654d2954ce Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:55 -0800 Subject: [PATCH] cpuset: implement cpuset_mems_allowed Provide a cpuset_mems_allowed() method, which the sys_migrate_pages() code needed, to obtain the mems_allowed vector of a cpuset, and replaced the workaround in sys_migrate_pages() to call this new method. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 8 +++++++- kernel/cpuset.c | 29 ++++++++++++++++++++++++++--- mm/mempolicy.c | 3 --- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 1feebf16ab08..37d2dd7ca3e9 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -18,7 +18,8 @@ extern int cpuset_init(void); extern void cpuset_init_smp(void); extern void cpuset_fork(struct task_struct *p); extern void cpuset_exit(struct task_struct *p); -extern cpumask_t cpuset_cpus_allowed(const struct task_struct *p); +extern cpumask_t cpuset_cpus_allowed(struct task_struct *p); +extern nodemask_t cpuset_mems_allowed(struct task_struct *p); void cpuset_init_current_mems_allowed(void); void cpuset_update_task_memory_state(void); #define cpuset_nodes_subset_current_mems_allowed(nodes) \ @@ -50,6 +51,11 @@ static inline cpumask_t cpuset_cpus_allowed(struct task_struct *p) return cpu_possible_map; } +static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) +{ + return node_possible_map; +} + static inline void cpuset_init_current_mems_allowed(void) {} static inline void cpuset_update_task_memory_state(void) {} #define cpuset_nodes_subset_current_mems_allowed(nodes) (1) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index e9917d71628a..0d0dbbd6560a 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1871,14 +1871,14 @@ void cpuset_exit(struct task_struct *tsk) * tasks cpuset. **/ -cpumask_t cpuset_cpus_allowed(const struct task_struct *tsk) +cpumask_t cpuset_cpus_allowed(struct task_struct *tsk) { cpumask_t mask; down(&callback_sem); - task_lock((struct task_struct *)tsk); + task_lock(tsk); guarantee_online_cpus(tsk->cpuset, &mask); - task_unlock((struct task_struct *)tsk); + task_unlock(tsk); up(&callback_sem); return mask; @@ -1889,6 +1889,29 @@ void cpuset_init_current_mems_allowed(void) current->mems_allowed = NODE_MASK_ALL; } +/** + * cpuset_mems_allowed - return mems_allowed mask from a tasks cpuset. + * @tsk: pointer to task_struct from which to obtain cpuset->mems_allowed. + * + * Description: Returns the nodemask_t mems_allowed of the cpuset + * attached to the specified @tsk. Guaranteed to return some non-empty + * subset of node_online_map, even if this means going outside the + * tasks cpuset. + **/ + +nodemask_t cpuset_mems_allowed(struct task_struct *tsk) +{ + nodemask_t mask; + + down(&callback_sem); + task_lock(tsk); + guarantee_online_mems(tsk->cpuset, &mask); + task_unlock(tsk); + up(&callback_sem); + + return mask; +} + /** * cpuset_zonelist_valid_mems_allowed - check zonelist vs. curremt mems_allowed * @zl: the zonelist to be checked diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 515bfeee027e..34d566ac147f 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -772,9 +772,6 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, return do_set_mempolicy(mode, &nodes); } -/* Macro needed until Paul implements this function in kernel/cpusets.c */ -#define cpuset_mems_allowed(task) node_online_map - asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, const unsigned long __user *old_nodes, const unsigned long __user *new_nodes) -- cgit v1.2.3 From 74cb21553f4bf244185b9bec4c26e4e3169ad55e Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:56 -0800 Subject: [PATCH] cpuset: numa_policy_rebind cleanup Cleanup, reorganize and make more robust the mempolicy.c code to rebind mempolicies relative to the containing cpuset after a tasks memory placement changes. The real motivator for this cleanup patch is to lay more groundwork for the upcoming patch to correctly rebind NUMA mempolicies that are attached to vma's after the containing cpuset memory placement changes. NUMA mempolicies are constrained by the cpuset their task is a member of. When either (1) a task is moved to a different cpuset, or (2) the 'mems' mems_allowed of a cpuset is changed, then the NUMA mempolicies have embedded node numbers (for MPOL_BIND, MPOL_INTERLEAVE and MPOL_PREFERRED) that need to be recalculated, relative to their new cpuset placement. The old code used an unreliable method of determining what was the old mems_allowed constraining the mempolicy. It just looked at the tasks mems_allowed value. This sort of worked with the present code, that just rebinds the -task- mempolicy, and leaves any -vma- mempolicies broken, referring to the old nodes. But in an upcoming patch, the vma mempolicies will be rebound as well. Then the order in which the various task and vma mempolicies are updated will no longer be deterministic, and one can no longer count on the task->mems_allowed holding the old value for as long as needed. It's not even clear if the current code was guaranteed to work reliably for task mempolicies. So I added a mems_allowed field to each mempolicy, stating exactly what mems_allowed the policy is relative to, and updated synchronously and reliably anytime that the mempolicy is rebound. Also removed a useless wrapper routine, numa_policy_rebind(), and had its caller, cpuset_update_task_memory_state(), call directly to the rewritten policy_rebind() routine, and made that rebind routine extern instead of static, and added a "mpol_" prefix to its name, making it mpol_rebind_policy(). Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mempolicy.h | 12 ++++++++++-- kernel/cpuset.c | 2 +- mm/mempolicy.c | 31 +++++++++++++++++++------------ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 05fddd5bee5d..74357cb9bc7c 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -68,6 +68,7 @@ struct mempolicy { nodemask_t nodes; /* interleave */ /* undefined for default */ } v; + nodemask_t cpuset_mems_allowed; /* mempolicy relative to these nodes */ }; /* @@ -146,7 +147,9 @@ struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp, extern void numa_default_policy(void); extern void numa_policy_init(void); -extern void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new); +extern void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *new); +extern void mpol_rebind_task(struct task_struct *tsk, + const nodemask_t *new); extern struct mempolicy default_policy; extern struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr); @@ -221,7 +224,12 @@ static inline void numa_default_policy(void) { } -static inline void numa_policy_rebind(const nodemask_t *old, +static inline void mpol_rebind_policy(struct mempolicy *pol, + const nodemask_t *new) +{ +} + +static inline void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new) { } diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 0d0dbbd6560a..8f764de3a9e7 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -643,7 +643,7 @@ void cpuset_update_task_memory_state() tsk->cpuset_mems_generation = cs->mems_generation; task_unlock(tsk); up(&callback_sem); - numa_policy_rebind(&oldmem, &tsk->mems_allowed); + mpol_rebind_task(tsk, &tsk->mems_allowed); if (!nodes_equal(oldmem, tsk->mems_allowed)) { if (migrate) { do_migrate_pages(tsk->mm, &oldmem, diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 34d566ac147f..c39bd86f4ea0 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -180,6 +180,7 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) break; } policy->policy = mode; + policy->cpuset_mems_allowed = cpuset_mems_allowed(current); return policy; } @@ -1411,25 +1412,31 @@ void numa_default_policy(void) } /* Migrate a policy to a different set of nodes */ -static void rebind_policy(struct mempolicy *pol, const nodemask_t *old, - const nodemask_t *new) +void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask) { + nodemask_t *mpolmask; nodemask_t tmp; if (!pol) return; + mpolmask = &pol->cpuset_mems_allowed; + if (nodes_equal(*mpolmask, *newmask)) + return; switch (pol->policy) { case MPOL_DEFAULT: break; case MPOL_INTERLEAVE: - nodes_remap(tmp, pol->v.nodes, *old, *new); + nodes_remap(tmp, pol->v.nodes, *mpolmask, *newmask); pol->v.nodes = tmp; - current->il_next = node_remap(current->il_next, *old, *new); + *mpolmask = *newmask; + current->il_next = node_remap(current->il_next, + *mpolmask, *newmask); break; case MPOL_PREFERRED: pol->v.preferred_node = node_remap(pol->v.preferred_node, - *old, *new); + *mpolmask, *newmask); + *mpolmask = *newmask; break; case MPOL_BIND: { nodemask_t nodes; @@ -1439,7 +1446,7 @@ static void rebind_policy(struct mempolicy *pol, const nodemask_t *old, nodes_clear(nodes); for (z = pol->v.zonelist->zones; *z; z++) node_set((*z)->zone_pgdat->node_id, nodes); - nodes_remap(tmp, nodes, *old, *new); + nodes_remap(tmp, nodes, *mpolmask, *newmask); nodes = tmp; zonelist = bind_zonelist(&nodes); @@ -1454,6 +1461,7 @@ static void rebind_policy(struct mempolicy *pol, const nodemask_t *old, kfree(pol->v.zonelist); pol->v.zonelist = zonelist; } + *mpolmask = *newmask; break; } default: @@ -1463,14 +1471,13 @@ static void rebind_policy(struct mempolicy *pol, const nodemask_t *old, } /* - * Someone moved this task to different nodes. Fixup mempolicies. - * - * TODO - fixup current->mm->vma and shmfs/tmpfs/hugetlbfs policies as well, - * once we have a cpuset mechanism to mark which cpuset subtree is migrating. + * Wrapper for mpol_rebind_policy() that just requires task + * pointer, and updates task mempolicy. */ -void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new) + +void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new) { - rebind_policy(current->mempolicy, old, new); + mpol_rebind_policy(tsk->mempolicy, new); } /* -- cgit v1.2.3 From 202f72d5d1b5c2c084f63ef996c736d208b447b5 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:57 -0800 Subject: [PATCH] cpuset: number_of_cpusets optimization Easy little optimization hack to avoid actually having to call cpuset_zone_allowed() and check mems_allowed, in the main page allocation routine, __alloc_pages(). This saves several CPU cycles per page allocation on systems not using cpusets. A counter is updated each time a cpuset is created or removed, and whenever there is only one cpuset in the system, it must be the root cpuset, which contains all CPUs and all Memory Nodes. In that case, when the counter is one, all allocations are allowed. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 10 +++++++++- kernel/cpuset.c | 12 +++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 37d2dd7ca3e9..34081c168af5 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -14,6 +14,8 @@ #ifdef CONFIG_CPUSETS +extern int number_of_cpusets; /* How many cpusets are defined in system? */ + extern int cpuset_init(void); extern void cpuset_init_smp(void); extern void cpuset_fork(struct task_struct *p); @@ -25,7 +27,13 @@ void cpuset_update_task_memory_state(void); #define cpuset_nodes_subset_current_mems_allowed(nodes) \ nodes_subset((nodes), current->mems_allowed) int cpuset_zonelist_valid_mems_allowed(struct zonelist *zl); -extern int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask); + +extern int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask); +static int inline cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) +{ + return number_of_cpusets <= 1 || __cpuset_zone_allowed(z, gfp_mask); +} + extern int cpuset_excl_nodes_overlap(const struct task_struct *p); #define cpuset_memory_pressure_bump() \ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 8f764de3a9e7..6004719f26ee 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -56,6 +56,13 @@ #define CPUSET_SUPER_MAGIC 0x27e0eb +/* + * Tracks how many cpusets are currently defined in system. + * When there is only one cpuset (the root cpuset) we can + * short circuit some hooks. + */ +int number_of_cpusets; + /* See "Frequency meter" comments, below. */ struct fmeter { @@ -1664,6 +1671,7 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode) down(&callback_sem); list_add(&cs->sibling, &cs->parent->children); + number_of_cpusets++; up(&callback_sem); err = cpuset_create_dir(cs, name, mode); @@ -1726,6 +1734,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) spin_unlock(&d->d_lock); cpuset_d_remove_dir(d); dput(d); + number_of_cpusets--; up(&callback_sem); if (list_empty(&parent->children)) check_for_release(parent, &pathbuf); @@ -1769,6 +1778,7 @@ int __init cpuset_init(void) root->d_inode->i_nlink++; top_cpuset.dentry = root; root->d_inode->i_op = &cpuset_dir_inode_operations; + number_of_cpusets = 1; err = cpuset_populate_dir(root); /* memory_pressure_enabled is in root cpuset only */ if (err == 0) @@ -1982,7 +1992,7 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs) * GFP_USER - only nodes in current tasks mems allowed ok. **/ -int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) +int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) { int node; /* node that zone z is on */ const struct cpuset *cs; /* current cpuset ancestors */ -- cgit v1.2.3 From 4225399a66b315d4d1fb1cb61b75dda201c832e3 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:01:59 -0800 Subject: [PATCH] cpuset: rebind vma mempolicies fix Fix more of longstanding bug in cpuset/mempolicy interaction. NUMA mempolicies (mm/mempolicy.c) are constrained by the current tasks cpuset to just the Memory Nodes allowed by that cpuset. The kernel maintains internal state for each mempolicy, tracking what nodes are used for the MPOL_INTERLEAVE, MPOL_BIND or MPOL_PREFERRED policies. When a tasks cpuset memory placement changes, whether because the cpuset changed, or because the task was attached to a different cpuset, then the tasks mempolicies have to be rebound to the new cpuset placement, so as to preserve the cpuset-relative numbering of the nodes in that policy. An earlier fix handled such mempolicy rebinding for mempolicies attached to a task. This fix rebinds mempolicies attached to vma's (address ranges in a tasks address space.) Due to the need to hold the task->mm->mmap_sem semaphore while updating vma's, the rebinding of vma mempolicies has to be done when the cpuset memory placement is changed, at which time mmap_sem can be safely acquired. The tasks mempolicy is rebound later, when the task next attempts to allocate memory and notices that its task->cpuset_mems_generation is out-of-date with its cpusets mems_generation. Because walking the tasklist to find all tasks attached to a changing cpuset requires holding tasklist_lock, a spinlock, one cannot update the vma's of the affected tasks while doing the tasklist scan. In general, one cannot acquire a semaphore (which can sleep) while already holding a spinlock (such as tasklist_lock). So a list of mm references has to be built up during the tasklist scan, then the tasklist lock dropped, then for each mm, its mmap_sem acquired, and the vma's in that mm rebound. Once the tasklist lock is dropped, affected tasks may fork new tasks, before their mm's are rebound. A kernel global 'cpuset_being_rebound' is set to point to the cpuset being rebound (there can only be one; cpuset modifications are done under a global 'manage_sem' semaphore), and the mpol_copy code that is used to copy a tasks mempolicies during fork catches such forking tasks, and ensures their children are also rebound. When a task is moved to a different cpuset, it is easier, as there is only one task involved. It's mm->vma's are scanned, using the same mpol_rebind_policy() as used above. It may happen that both the mpol_copy hook and the update done via the tasklist scan update the same mm twice. This is ok, as the mempolicies of each vma in an mm keep track of what mems_allowed they are relative to, and safely no-op a second request to rebind to the same nodes. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mempolicy.h | 18 ++++++++++ kernel/cpuset.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++ mm/mempolicy.c | 29 +++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 74357cb9bc7c..c7ac77e873b3 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -150,6 +150,16 @@ extern void numa_policy_init(void); extern void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *new); extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new); +extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new); +#define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x)) + +#ifdef CONFIG_CPUSET +#define current_cpuset_is_being_rebound() \ + (cpuset_being_rebound == current->cpuset) +#else +#define current_cpuset_is_being_rebound() 0 +#endif + extern struct mempolicy default_policy; extern struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr); @@ -165,6 +175,8 @@ static inline void check_highest_zone(int k) int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags); +extern void *cpuset_being_rebound; /* Trigger mpol_copy vma rebind */ + #else struct mempolicy {}; @@ -234,6 +246,12 @@ static inline void mpol_rebind_task(struct task_struct *tsk, { } +static inline void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new) +{ +} + +#define set_cpuset_being_rebound(x) do {} while (0) + static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr) { diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 6004719f26ee..19f87565be17 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -812,12 +812,24 @@ static int update_cpumask(struct cpuset *cs, char *buf) } /* + * Handle user request to change the 'mems' memory placement + * of a cpuset. Needs to validate the request, update the + * cpusets mems_allowed and mems_generation, and for each + * task in the cpuset, rebind any vma mempolicies. + * * Call with manage_sem held. May take callback_sem during call. + * Will take tasklist_lock, scan tasklist for tasks in cpuset cs, + * lock each such tasks mm->mmap_sem, scan its vma's and rebind + * their mempolicies to the cpusets new mems_allowed. */ static int update_nodemask(struct cpuset *cs, char *buf) { struct cpuset trialcs; + struct task_struct *g, *p; + struct mm_struct **mmarray; + int i, n, ntasks; + int fudge; int retval; trialcs = *cs; @@ -839,6 +851,76 @@ static int update_nodemask(struct cpuset *cs, char *buf) cs->mems_generation = atomic_read(&cpuset_mems_generation); up(&callback_sem); + set_cpuset_being_rebound(cs); /* causes mpol_copy() rebind */ + + fudge = 10; /* spare mmarray[] slots */ + fudge += cpus_weight(cs->cpus_allowed); /* imagine one fork-bomb/cpu */ + retval = -ENOMEM; + + /* + * Allocate mmarray[] to hold mm reference for each task + * in cpuset cs. Can't kmalloc GFP_KERNEL while holding + * tasklist_lock. We could use GFP_ATOMIC, but with a + * few more lines of code, we can retry until we get a big + * enough mmarray[] w/o using GFP_ATOMIC. + */ + while (1) { + ntasks = atomic_read(&cs->count); /* guess */ + ntasks += fudge; + mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL); + if (!mmarray) + goto done; + write_lock_irq(&tasklist_lock); /* block fork */ + if (atomic_read(&cs->count) <= ntasks) + break; /* got enough */ + write_unlock_irq(&tasklist_lock); /* try again */ + kfree(mmarray); + } + + n = 0; + + /* Load up mmarray[] with mm reference for each task in cpuset. */ + do_each_thread(g, p) { + struct mm_struct *mm; + + if (n >= ntasks) { + printk(KERN_WARNING + "Cpuset mempolicy rebind incomplete.\n"); + continue; + } + if (p->cpuset != cs) + continue; + mm = get_task_mm(p); + if (!mm) + continue; + mmarray[n++] = mm; + } while_each_thread(g, p); + write_unlock_irq(&tasklist_lock); + + /* + * Now that we've dropped the tasklist spinlock, we can + * rebind the vma mempolicies of each mm in mmarray[] to their + * new cpuset, and release that mm. The mpol_rebind_mm() + * call takes mmap_sem, which we couldn't take while holding + * tasklist_lock. Forks can happen again now - the mpol_copy() + * cpuset_being_rebound check will catch such forks, and rebind + * their vma mempolicies too. Because we still hold the global + * cpuset manage_sem, we know that no other rebind effort will + * be contending for the global variable cpuset_being_rebound. + * It's ok if we rebind the same mm twice; mpol_rebind_mm() + * is idempotent. + */ + for (i = 0; i < n; i++) { + struct mm_struct *mm = mmarray[i]; + + mpol_rebind_mm(mm, &cs->mems_allowed); + mmput(mm); + } + + /* We're done rebinding vma's to this cpusets new mems_allowed. */ + kfree(mmarray); + set_cpuset_being_rebound(NULL); + retval = 0; done: return retval; } @@ -1011,6 +1093,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) struct cpuset *oldcs; cpumask_t cpus; nodemask_t from, to; + struct mm_struct *mm; if (sscanf(pidbuf, "%d", &pid) != 1) return -EIO; @@ -1060,6 +1143,13 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) to = cs->mems_allowed; up(&callback_sem); + + mm = get_task_mm(tsk); + if (mm) { + mpol_rebind_mm(mm, &to); + mmput(mm); + } + if (is_memory_migrate(cs)) do_migrate_pages(tsk->mm, &from, &to, MPOL_MF_MOVE_ALL); put_task_struct(tsk); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index c39bd86f4ea0..1850d0aef4ac 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1131,6 +1131,15 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order) } EXPORT_SYMBOL(alloc_pages_current); +/* + * If mpol_copy() sees current->cpuset == cpuset_being_rebound, then it + * rebinds the mempolicy its copying by calling mpol_rebind_policy() + * with the mems_allowed returned by cpuset_mems_allowed(). This + * keeps mempolicies cpuset relative after its cpuset moves. See + * further kernel/cpuset.c update_nodemask(). + */ +void *cpuset_being_rebound; + /* Slow path of a mempolicy copy */ struct mempolicy *__mpol_copy(struct mempolicy *old) { @@ -1138,6 +1147,10 @@ struct mempolicy *__mpol_copy(struct mempolicy *old) if (!new) return ERR_PTR(-ENOMEM); + if (current_cpuset_is_being_rebound()) { + nodemask_t mems = cpuset_mems_allowed(current); + mpol_rebind_policy(old, &mems); + } *new = *old; atomic_set(&new->refcnt, 1); if (new->policy == MPOL_BIND) { @@ -1480,6 +1493,22 @@ void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new) mpol_rebind_policy(tsk->mempolicy, new); } +/* + * Rebind each vma in mm to new nodemask. + * + * Call holding a reference to mm. Takes mm->mmap_sem during call. + */ + +void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new) +{ + struct vm_area_struct *vma; + + down_write(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) + mpol_rebind_policy(vma->vm_policy, new); + up_write(&mm->mmap_sem); +} + /* * Display pages allocated per node and memory policy via /proc. */ -- cgit v1.2.3 From 04c19fa6f16047abff2288ddbc1f0798ede5a849 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:02:00 -0800 Subject: [PATCH] cpuset: migrate all tasks in cpuset at once Given the mechanism in the previous patch to handle rebinding the per-vma mempolicies of all tasks in a cpuset that changes its memory placement, it is now easier to handle the page migration requirements of such tasks at the same time. The previous code didn't actually attempt to migrate the pages of the tasks in a cpuset whose memory placement changed until the next time each such task tried to allocate memory. This was undesirable, as users invoking memory page migration exected to happen when the placement changed, not some unspecified time later when the task needed more memory. It is now trivial to handle the page migration at the same time as the per-vma rebinding is done. The routine cpuset.c:update_nodemask(), which handles changing a cpusets memory placement ('mems') now checks for the special case of being asked to write a placement that is the same as before. It was harmless enough before to just recompute everything again, even though nothing had changed. But page migration is a heavy weight operation - moving pages about. So now it is worth avoiding that if asked to move a cpuset to its current location. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 19f87565be17..cf8203a5fa71 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -639,25 +639,14 @@ void cpuset_update_task_memory_state() task_unlock(tsk); if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) { - nodemask_t oldmem = tsk->mems_allowed; - int migrate; - down(&callback_sem); task_lock(tsk); cs = tsk->cpuset; /* Maybe changed when task not locked */ - migrate = is_memory_migrate(cs); guarantee_online_mems(cs, &tsk->mems_allowed); tsk->cpuset_mems_generation = cs->mems_generation; task_unlock(tsk); up(&callback_sem); mpol_rebind_task(tsk, &tsk->mems_allowed); - if (!nodes_equal(oldmem, tsk->mems_allowed)) { - if (migrate) { - do_migrate_pages(tsk->mm, &oldmem, - &tsk->mems_allowed, - MPOL_MF_MOVE_ALL); - } - } } } @@ -815,7 +804,9 @@ static int update_cpumask(struct cpuset *cs, char *buf) * Handle user request to change the 'mems' memory placement * of a cpuset. Needs to validate the request, update the * cpusets mems_allowed and mems_generation, and for each - * task in the cpuset, rebind any vma mempolicies. + * task in the cpuset, rebind any vma mempolicies and if + * the cpuset is marked 'memory_migrate', migrate the tasks + * pages to the new memory. * * Call with manage_sem held. May take callback_sem during call. * Will take tasklist_lock, scan tasklist for tasks in cpuset cs, @@ -826,9 +817,11 @@ static int update_cpumask(struct cpuset *cs, char *buf) static int update_nodemask(struct cpuset *cs, char *buf) { struct cpuset trialcs; + nodemask_t oldmem; struct task_struct *g, *p; struct mm_struct **mmarray; int i, n, ntasks; + int migrate; int fudge; int retval; @@ -837,6 +830,11 @@ static int update_nodemask(struct cpuset *cs, char *buf) if (retval < 0) goto done; nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map); + oldmem = cs->mems_allowed; + if (nodes_equal(oldmem, trialcs.mems_allowed)) { + retval = 0; /* Too easy - nothing to do */ + goto done; + } if (nodes_empty(trialcs.mems_allowed)) { retval = -ENOSPC; goto done; @@ -908,12 +906,17 @@ static int update_nodemask(struct cpuset *cs, char *buf) * cpuset manage_sem, we know that no other rebind effort will * be contending for the global variable cpuset_being_rebound. * It's ok if we rebind the same mm twice; mpol_rebind_mm() - * is idempotent. + * is idempotent. Also migrate pages in each mm to new nodes. */ + migrate = is_memory_migrate(cs); for (i = 0; i < n; i++) { struct mm_struct *mm = mmarray[i]; mpol_rebind_mm(mm, &cs->mems_allowed); + if (migrate) { + do_migrate_pages(mm, &oldmem, &cs->mems_allowed, + MPOL_MF_MOVE_ALL); + } mmput(mm); } -- cgit v1.2.3 From c417f0242ebe578924a30d4e53d35b5059fed4e7 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:02:01 -0800 Subject: [PATCH] cpuset: remove test for null cpuset from alloc code path Remove a couple of more lines of code from the cpuset hooks in the page allocation code path. There was a check for a NULL cpuset pointer in the routine cpuset_update_task_memory_state() that was only needed during system boot, after the memory subsystem was initialized, before the cpuset subsystem was initialized, to catch a NULL task->cpuset pointer. Add a cpuset_init_early() routine, just before the mem_init() call in init/main.c, that sets up just enough of the init tasks cpuset structure to render cpuset_update_task_memory_state() calls harmless. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cpuset.h | 2 ++ init/main.c | 1 + kernel/cpuset.c | 22 ++++++++++++++++------ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 34081c168af5..c472f972bd6d 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -16,6 +16,7 @@ extern int number_of_cpusets; /* How many cpusets are defined in system? */ +extern int cpuset_init_early(void); extern int cpuset_init(void); extern void cpuset_init_smp(void); extern void cpuset_fork(struct task_struct *p); @@ -49,6 +50,7 @@ extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer); #else /* !CONFIG_CPUSETS */ +static inline int cpuset_init_early(void) { return 0; } static inline int cpuset_init(void) { return 0; } static inline void cpuset_init_smp(void) {} static inline void cpuset_fork(struct task_struct *p) {} diff --git a/init/main.c b/init/main.c index 2ed3638deec7..afe5eb84ad52 100644 --- a/init/main.c +++ b/init/main.c @@ -512,6 +512,7 @@ asmlinkage void __init start_kernel(void) } #endif vfs_caches_init_early(); + cpuset_init_early(); mem_init(); kmem_cache_init(); setup_per_cpu_pageset(); diff --git a/kernel/cpuset.c b/kernel/cpuset.c index cf8203a5fa71..fc949e4a625c 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -603,9 +603,7 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask) * Do not call this routine if in_interrupt(). * * Call without callback_sem or task_lock() held. May be called - * with or without manage_sem held. Except in early boot or - * an exiting task, when tsk->cpuset is NULL, this routine will - * acquire task_lock(). We don't need to use task_lock to guard + * with or without manage_sem held. Doesn't need task_lock to guard * against another task changing a non-NULL cpuset pointer to NULL, * as that is only done by a task on itself, and if the current task * is here, it is not simultaneously in the exit code NULL'ing its @@ -631,9 +629,6 @@ void cpuset_update_task_memory_state() struct task_struct *tsk = current; struct cpuset *cs = tsk->cpuset; - if (unlikely(!cs)) - return; - task_lock(tsk); my_cpusets_mem_gen = cs->mems_generation; task_unlock(tsk); @@ -1836,6 +1831,21 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) return 0; } +/* + * cpuset_init_early - just enough so that the calls to + * cpuset_update_task_memory_state() in early init code + * are harmless. + */ + +int __init cpuset_init_early(void) +{ + struct task_struct *tsk = current; + + tsk->cpuset = &top_cpuset; + tsk->cpuset->mems_generation = atomic_read(&cpuset_mems_generation); + return 0; +} + /** * cpuset_init - initialize cpusets at system boot * -- cgit v1.2.3 From 6b9c2603ce07f70de9c7a8d335ecd028e8ff11f3 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:02:02 -0800 Subject: [PATCH] cpuset: use rcu directly optimization Optimize the cpuset impact on page allocation, the most performance critical cpuset hook in the kernel. On each page allocation, the cpuset hook needs to check for a possible change in the current tasks cpuset. It can now handle the common case, of no change, without taking any spinlock or semaphore, thanks to RCU. Convert a spinlock on the current task to an rcu_read_lock(), saving approximately a memory barrier and an atomic op, depending on architecture. This is done by adding rcu_assign_pointer() and synchronize_rcu() calls to the write side of the task->cpuset pointer, in cpuset.c:attach_task(), to delay freeing up a detached cpuset until after any critical sections referencing that pointer. Thanks to Andi Kleen, Nick Piggin and Eric Dumazet for ideas. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index fc949e4a625c..6fe28d6f282b 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -248,6 +249,11 @@ static struct super_block *cpuset_sb; * a tasks cpuset pointer we use task_lock(), which acts on a spinlock * (task->alloc_lock) already in the task_struct routinely used for * such matters. + * + * P.S. One more locking exception. RCU is used to guard the + * update of a tasks cpuset pointer by attach_task() and the + * access of task->cpuset->mems_generation via that pointer in + * the routine cpuset_update_task_memory_state(). */ static DECLARE_MUTEX(manage_sem); @@ -610,12 +616,24 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask) * cpuset pointer. This routine also might acquire callback_sem and * current->mm->mmap_sem during call. * - * The task_lock() is required to dereference current->cpuset safely. - * Without it, we could pick up the pointer value of current->cpuset - * in one instruction, and then attach_task could give us a different - * cpuset, and then the cpuset we had could be removed and freed, - * and then on our next instruction, we could dereference a no longer - * valid cpuset pointer to get its mems_generation field. + * Reading current->cpuset->mems_generation doesn't need task_lock + * to guard the current->cpuset derefence, because it is guarded + * from concurrent freeing of current->cpuset by attach_task(), + * using RCU. + * + * The rcu_dereference() is technically probably not needed, + * as I don't actually mind if I see a new cpuset pointer but + * an old value of mems_generation. However this really only + * matters on alpha systems using cpusets heavily. If I dropped + * that rcu_dereference(), it would save them a memory barrier. + * For all other arch's, rcu_dereference is a no-op anyway, and for + * alpha systems not using cpusets, another planned optimization, + * avoiding the rcu critical section for tasks in the root cpuset + * which is statically allocated, so can't vanish, will make this + * irrelevant. Better to use RCU as intended, than to engage in + * some cute trick to save a memory barrier that is impossible to + * test, for alpha systems using cpusets heavily, which might not + * even exist. * * This routine is needed to update the per-task mems_allowed data, * within the tasks context, when it is trying to allocate memory @@ -627,11 +645,12 @@ void cpuset_update_task_memory_state() { int my_cpusets_mem_gen; struct task_struct *tsk = current; - struct cpuset *cs = tsk->cpuset; + struct cpuset *cs; - task_lock(tsk); + rcu_read_lock(); + cs = rcu_dereference(tsk->cpuset); my_cpusets_mem_gen = cs->mems_generation; - task_unlock(tsk); + rcu_read_unlock(); if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) { down(&callback_sem); @@ -1131,7 +1150,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) return -ESRCH; } atomic_inc(&cs->count); - tsk->cpuset = cs; + rcu_assign_pointer(tsk->cpuset, cs); task_unlock(tsk); guarantee_online_cpus(cs, &cpus); @@ -1151,6 +1170,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) if (is_memory_migrate(cs)) do_migrate_pages(tsk->mm, &from, &to, MPOL_MF_MOVE_ALL); put_task_struct(tsk); + synchronize_rcu(); if (atomic_dec_and_test(&oldcs->count)) check_for_release(oldcs, ppathbuf); return 0; -- cgit v1.2.3 From 7edc59628b2f5d6516b4677b3b56f5f056e45cd9 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:02:03 -0800 Subject: [PATCH] cpuset: mark number_of_cpusets read_mostly Mark cpuset global 'number_of_cpusets' as __read_mostly. This global is accessed everytime a zone is considered in the zonelist loops beneath __alloc_pages, looking for a free memory page. If number_of_cpusets is just one, then we can short circuit the mems_allowed check. Since this global is read alot on a hot path, and written rarely, it is an excellent candidate for __read_mostly. Thanks to Christoph Lameter for the suggestion. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 6fe28d6f282b..681a5d58d40d 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -62,7 +62,7 @@ * When there is only one cpuset (the root cpuset) we can * short circuit some hooks. */ -int number_of_cpusets; +int number_of_cpusets __read_mostly; /* See "Frequency meter" comments, below. */ -- cgit v1.2.3 From 03a285f58064b8e0af08383e082e383753d9c33e Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Sun, 8 Jan 2006 01:02:04 -0800 Subject: [PATCH] cpuset: skip rcu check if task is in root cpuset For systems that aren't using cpusets, but have them CONFIG_CPUSET enabled in their kernel (eventually this may be most distribution kernels), this patch removes even the minimal rcu_read_lock() from the memory page allocation path. Actually, it removes that rcu call for any task that is in the root cpuset (top_cpuset), which on systems not actively using cpusets, is all tasks. We don't need the rcu check for tasks in the top_cpuset, because the top_cpuset is statically allocated, so at no risk of being freed out from underneath us. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cpuset.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 681a5d58d40d..e04c2da9dadb 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -647,10 +647,15 @@ void cpuset_update_task_memory_state() struct task_struct *tsk = current; struct cpuset *cs; - rcu_read_lock(); - cs = rcu_dereference(tsk->cpuset); - my_cpusets_mem_gen = cs->mems_generation; - rcu_read_unlock(); + if (tsk->cpuset == &top_cpuset) { + /* Don't need rcu for top_cpuset. It's never freed. */ + my_cpusets_mem_gen = top_cpuset.mems_generation; + } else { + rcu_read_lock(); + cs = rcu_dereference(tsk->cpuset); + my_cpusets_mem_gen = cs->mems_generation; + rcu_read_unlock(); + } if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) { down(&callback_sem); -- cgit v1.2.3 From de25968cc87cc5b76d09de8b4cbddc8f24fcf5f7 Mon Sep 17 00:00:00 2001 From: Tim Schmielau Date: Sun, 8 Jan 2006 01:02:05 -0800 Subject: [PATCH] fix more missing includes Include fixes for 2.6.14-git11. Should allow to remove sched.h from module.h on i386, x86_64, arm, ia64, ppc, ppc64, and s390. Probably more to come since I haven't yet checked the other archs. Signed-off-by: Tim Schmielau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/common/scoop.c | 1 + arch/arm/mach-realview/localtimer.c | 1 + arch/mips/sgi-ip27/ip27-berr.c | 1 + drivers/char/agp/sworks-agp.c | 1 + drivers/infiniband/hw/mthca/mthca_dev.h | 1 + drivers/infiniband/ulp/srp/ib_srp.c | 1 + drivers/macintosh/windfarm_smu_controls.c | 1 + drivers/macintosh/windfarm_smu_sensors.c | 1 + drivers/mtd/onenand/generic.c | 1 + drivers/mtd/rfd_ftl.c | 1 + drivers/pci/hotplug/pciehp.h | 1 + drivers/pci/hotplug/pciehp_hpc.c | 3 +++ drivers/rapidio/rio-scan.c | 2 ++ drivers/rapidio/rio-sysfs.c | 1 + drivers/rapidio/rio.c | 1 + drivers/usb/host/ohci-au1xxx.c | 1 + drivers/usb/host/ohci-lh7a404.c | 1 + drivers/usb/host/ohci-ppc-soc.c | 1 + include/linux/rio_drv.h | 1 + 19 files changed, 22 insertions(+) diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index b6de43e73699..a2dfe0b0f1ec 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c index c9d7c596b200..caf6b8bb6c95 100644 --- a/arch/arm/mach-realview/localtimer.c +++ b/arch/arm/mach-realview/localtimer.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/sgi-ip27/ip27-berr.c b/arch/mips/sgi-ip27/ip27-berr.c index 07631a97670b..ce907eda221b 100644 --- a/arch/mips/sgi-ip27/ip27-berr.c +++ b/arch/mips/sgi-ip27/ip27-berr.c @@ -11,6 +11,7 @@ #include #include #include /* for SIGBUS */ +#include /* schow_regs(), force_sig() */ #include #include diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 3f8f7fa6b0ff..268f78d926d3 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "agp.h" diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 497ff794ef6a..795b379260bf 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "mthca_provider.h" diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ee9fe226ae99..dd488d3cffa9 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -39,6 +39,7 @@ #include #include #include +#include #include diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 2c3158c81ff2..4d811600bdab 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index b558cc209d49..1a00d9c75a23 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 45c077d0f063..af06a80f44de 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 20ce212638fc..a3e00a4635a5 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 6a61b9f286e1..0aac6a61337d 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -32,6 +32,7 @@ #include #include #include +#include /* signal_pending() */ #include #include "pci_hotplug.h" diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 0b8b26beb163..ac1e495c314e 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 4f7ed4bd3be9..94e30fe4b8f3 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "rio.h" diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 30a11436e241..bef9316e95df 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -15,6 +15,7 @@ #include #include #include +#include /* for capable() */ #include "rio.h" diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 3ca1011ceaac..5e382470faa2 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rio.h" diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index d9cf3b327d96..77cd6ac07e3c 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -19,6 +19,7 @@ */ #include +#include #include diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 3959ccc88332..0020ed7a39d0 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -17,6 +17,7 @@ */ #include +#include #include diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 2ec6a78bd65e..b2a8dfa48870 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -15,6 +15,7 @@ */ #include +#include /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h index 3bd7cce19e26..157d7e3236b5 100644 --- a/include/linux/rio_drv.h +++ b/include/linux/rio_drv.h @@ -21,6 +21,7 @@ #include #include #include +#include #include extern int __rio_local_read_config_32(struct rio_mport *port, u32 offset, -- cgit v1.2.3 From 705b6c7b34f2621f95f606d0e683daa10cdb8eb9 Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Sun, 8 Jan 2006 01:02:06 -0800 Subject: [PATCH] new driver synclink_gt New character device driver for the SyncLink GT and SyncLink AC families of synchronous and asynchronous serial adapters Signed-off-by: Paul Fulghum Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 8 + drivers/char/Makefile | 1 + drivers/char/synclink_gt.c | 4501 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/synclink.h | 9 +- 4 files changed, 4518 insertions(+), 1 deletion(-) create mode 100644 drivers/char/synclink_gt.c diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index b1b34edcd70c..dd7e6901c575 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -220,6 +220,14 @@ config SYNCLINKMP The module will be called synclinkmp. If you want to do that, say M here. +config SYNCLINK_GT + tristate "SyncLink GT/AC support" + depends on SERIAL_NONSTANDARD + help + Support for SyncLink GT and SyncLink AC families of + synchronous and asynchronous serial adapters + manufactured by Microgate Systems, Ltd. (www.microgate.com) + config N_HDLC tristate "HDLC line discipline support" depends on SERIAL_NONSTANDARD diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4aeae687e88a..d973d14d8f7f 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_RISCOM8) += riscom8.o obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o +obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c new file mode 100644 index 000000000000..2b9cde94e2f7 --- /dev/null +++ b/drivers/char/synclink_gt.c @@ -0,0 +1,4501 @@ +/* + * $Id: synclink_gt.c,v 4.20 2005/11/08 19:51:55 paulkf Exp $ + * + * Device driver for Microgate SyncLink GT serial adapters. + * + * written by Paul Fulghum for Microgate Corporation + * paulkf@microgate.com + * + * Microgate and SyncLink are trademarks of Microgate Corporation + * + * This code is released under the GNU General Public License (GPL) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * DEBUG OUTPUT DEFINITIONS + * + * uncomment lines below to enable specific types of debug output + * + * DBGINFO information - most verbose output + * DBGERR serious errors + * DBGBH bottom half service routine debugging + * DBGISR interrupt service routine debugging + * DBGDATA output receive and transmit data + * DBGTBUF output transmit DMA buffers and registers + * DBGRBUF output receive DMA buffers and registers + */ + +#define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt +#define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt +#define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt +#define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt +#define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label)) +//#define DBGTBUF(info) dump_tbufs(info) +//#define DBGRBUF(info) dump_rbufs(info) + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "linux/synclink.h" + +#ifdef CONFIG_HDLC_MODULE +#define CONFIG_HDLC 1 +#endif + +/* + * module identification + */ +static char *driver_name = "SyncLink GT"; +static char *driver_version = "$Revision: 4.20 $"; +static char *tty_driver_name = "synclink_gt"; +static char *tty_dev_prefix = "ttySLG"; +MODULE_LICENSE("GPL"); +#define MGSL_MAGIC 0x5401 +#define MAX_DEVICES 12 + +static struct pci_device_id pci_table[] = { + {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {0,}, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, pci_table); + +static int init_one(struct pci_dev *dev,const struct pci_device_id *ent); +static void remove_one(struct pci_dev *dev); +static struct pci_driver pci_driver = { + .name = "synclink_gt", + .id_table = pci_table, + .probe = init_one, + .remove = __devexit_p(remove_one), +}; + +static int pci_registered; + +/* + * module configuration and status + */ +static struct slgt_info *slgt_device_list; +static int slgt_device_count; + +static int ttymajor; +static int debug_level; +static int maxframe[MAX_DEVICES]; +static int dosyncppp[MAX_DEVICES]; + +module_param(ttymajor, int, 0); +module_param(debug_level, int, 0); +module_param_array(maxframe, int, NULL, 0); +module_param_array(dosyncppp, int, NULL, 0); + +MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned"); +MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail"); +MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); +MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable"); + +/* + * tty support and callbacks + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +static struct tty_driver *serial_driver; + +static int open(struct tty_struct *tty, struct file * filp); +static void close(struct tty_struct *tty, struct file * filp); +static void hangup(struct tty_struct *tty); +static void set_termios(struct tty_struct *tty, struct termios *old_termios); + +static int write(struct tty_struct *tty, const unsigned char *buf, int count); +static void put_char(struct tty_struct *tty, unsigned char ch); +static void send_xchar(struct tty_struct *tty, char ch); +static void wait_until_sent(struct tty_struct *tty, int timeout); +static int write_room(struct tty_struct *tty); +static void flush_chars(struct tty_struct *tty); +static void flush_buffer(struct tty_struct *tty); +static void tx_hold(struct tty_struct *tty); +static void tx_release(struct tty_struct *tty); + +static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data); +static int chars_in_buffer(struct tty_struct *tty); +static void throttle(struct tty_struct * tty); +static void unthrottle(struct tty_struct * tty); +static void set_break(struct tty_struct *tty, int break_state); + +/* + * generic HDLC support and callbacks + */ +#ifdef CONFIG_HDLC +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +static void hdlcdev_tx_done(struct slgt_info *info); +static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); +static int hdlcdev_init(struct slgt_info *info); +static void hdlcdev_exit(struct slgt_info *info); +#endif + + +/* + * device specific structures, macros and functions + */ + +#define SLGT_MAX_PORTS 4 +#define SLGT_REG_SIZE 256 + +/* + * DMA buffer descriptor and access macros + */ +struct slgt_desc +{ + unsigned short count; + unsigned short status; + unsigned int pbuf; /* physical address of data buffer */ + unsigned int next; /* physical address of next descriptor */ + + /* driver book keeping */ + char *buf; /* virtual address of data buffer */ + unsigned int pdesc; /* physical address of this descriptor */ + dma_addr_t buf_dma_addr; +}; + +#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b)) +#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b)) +#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b)) +#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0)) +#define desc_count(a) (le16_to_cpu((a).count)) +#define desc_status(a) (le16_to_cpu((a).status)) +#define desc_complete(a) (le16_to_cpu((a).status) & BIT15) +#define desc_eof(a) (le16_to_cpu((a).status) & BIT2) +#define desc_crc_error(a) (le16_to_cpu((a).status) & BIT1) +#define desc_abort(a) (le16_to_cpu((a).status) & BIT0) +#define desc_residue(a) ((le16_to_cpu((a).status) & 0x38) >> 3) + +struct _input_signal_events { + int ri_up; + int ri_down; + int dsr_up; + int dsr_down; + int dcd_up; + int dcd_down; + int cts_up; + int cts_down; +}; + +/* + * device instance data structure + */ +struct slgt_info { + void *if_ptr; /* General purpose pointer (used by SPPP) */ + + struct slgt_info *next_device; /* device list link */ + + int magic; + int flags; + + char device_name[25]; + struct pci_dev *pdev; + + int port_count; /* count of ports on adapter */ + int adapter_num; /* adapter instance number */ + int port_num; /* port instance number */ + + /* array of pointers to port contexts on this adapter */ + struct slgt_info *port_array[SLGT_MAX_PORTS]; + + int count; /* count of opens */ + int line; /* tty line instance number */ + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + + struct mgsl_icount icount; + + struct tty_struct *tty; + int timeout; + int x_char; /* xon/xoff character */ + int blocked_open; /* # of blocked opens */ + unsigned int read_status_mask; + unsigned int ignore_status_mask; + + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + wait_queue_head_t status_event_wait_q; + wait_queue_head_t event_wait_q; + struct timer_list tx_timer; + struct timer_list rx_timer; + + spinlock_t lock; /* spinlock for synchronizing with ISR */ + + struct work_struct task; + u32 pending_bh; + int bh_requested; + int bh_running; + + int isr_overflow; + int irq_requested; /* nonzero if IRQ requested */ + int irq_occurred; /* for diagnostics use */ + + /* device configuration */ + + unsigned int bus_type; + unsigned int irq_level; + unsigned long irq_flags; + + unsigned char __iomem * reg_addr; /* memory mapped registers address */ + u32 phys_reg_addr; + u32 reg_offset; + int reg_addr_requested; + + MGSL_PARAMS params; /* communications parameters */ + u32 idle_mode; + u32 max_frame_size; /* as set by device config */ + + unsigned int raw_rx_size; + unsigned int if_mode; + + /* device status */ + + int rx_enabled; + int rx_restart; + + int tx_enabled; + int tx_active; + + unsigned char signals; /* serial signal states */ + unsigned int init_error; /* initialization error */ + + unsigned char *tx_buf; + int tx_count; + + char flag_buf[MAX_ASYNC_BUFFER_SIZE]; + char char_buf[MAX_ASYNC_BUFFER_SIZE]; + BOOLEAN drop_rts_on_tx_done; + struct _input_signal_events input_signal_events; + + int dcd_chkcount; /* check counts to prevent */ + int cts_chkcount; /* too many IRQs if a signal */ + int dsr_chkcount; /* is floating */ + int ri_chkcount; + + char *bufs; /* virtual address of DMA buffer lists */ + dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */ + + unsigned int rbuf_count; + struct slgt_desc *rbufs; + unsigned int rbuf_current; + unsigned int rbuf_index; + + unsigned int tbuf_count; + struct slgt_desc *tbufs; + unsigned int tbuf_current; + unsigned int tbuf_start; + + unsigned char *tmp_rbuf; + unsigned int tmp_rbuf_count; + + /* SPPP/Cisco HDLC device parts */ + + int netcount; + int dosyncppp; + spinlock_t netlock; +#ifdef CONFIG_HDLC + struct net_device *netdev; +#endif + +}; + +static MGSL_PARAMS default_params = { + .mode = MGSL_MODE_HDLC, + .loopback = 0, + .flags = HDLC_FLAG_UNDERRUN_ABORT15, + .encoding = HDLC_ENCODING_NRZI_SPACE, + .clock_speed = 0, + .addr_filter = 0xff, + .crc_type = HDLC_CRC_16_CCITT, + .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS, + .preamble = HDLC_PREAMBLE_PATTERN_NONE, + .data_rate = 9600, + .data_bits = 8, + .stop_bits = 1, + .parity = ASYNC_PARITY_NONE +}; + + +#define BH_RECEIVE 1 +#define BH_TRANSMIT 2 +#define BH_STATUS 4 +#define IO_PIN_SHUTDOWN_LIMIT 100 + +#define DMABUFSIZE 256 +#define DESC_LIST_SIZE 4096 + +#define MASK_PARITY BIT1 +#define MASK_FRAMING BIT2 +#define MASK_BREAK BIT3 +#define MASK_OVERRUN BIT4 + +#define GSR 0x00 /* global status */ +#define TDR 0x80 /* tx data */ +#define RDR 0x80 /* rx data */ +#define TCR 0x82 /* tx control */ +#define TIR 0x84 /* tx idle */ +#define TPR 0x85 /* tx preamble */ +#define RCR 0x86 /* rx control */ +#define VCR 0x88 /* V.24 control */ +#define CCR 0x89 /* clock control */ +#define BDR 0x8a /* baud divisor */ +#define SCR 0x8c /* serial control */ +#define SSR 0x8e /* serial status */ +#define RDCSR 0x90 /* rx DMA control/status */ +#define TDCSR 0x94 /* tx DMA control/status */ +#define RDDAR 0x98 /* rx DMA descriptor address */ +#define TDDAR 0x9c /* tx DMA descriptor address */ + +#define RXIDLE BIT14 +#define RXBREAK BIT14 +#define IRQ_TXDATA BIT13 +#define IRQ_TXIDLE BIT12 +#define IRQ_TXUNDER BIT11 /* HDLC */ +#define IRQ_RXDATA BIT10 +#define IRQ_RXIDLE BIT9 /* HDLC */ +#define IRQ_RXBREAK BIT9 /* async */ +#define IRQ_RXOVER BIT8 +#define IRQ_DSR BIT7 +#define IRQ_CTS BIT6 +#define IRQ_DCD BIT5 +#define IRQ_RI BIT4 +#define IRQ_ALL 0x3ff0 +#define IRQ_MASTER BIT0 + +#define slgt_irq_on(info, mask) \ + wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask))) +#define slgt_irq_off(info, mask) \ + wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask))) + +static __u8 rd_reg8(struct slgt_info *info, unsigned int addr); +static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value); +static __u16 rd_reg16(struct slgt_info *info, unsigned int addr); +static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value); +static __u32 rd_reg32(struct slgt_info *info, unsigned int addr); +static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value); + +static void msc_set_vcr(struct slgt_info *info); + +static int startup(struct slgt_info *info); +static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info); +static void shutdown(struct slgt_info *info); +static void program_hw(struct slgt_info *info); +static void change_params(struct slgt_info *info); + +static int register_test(struct slgt_info *info); +static int irq_test(struct slgt_info *info); +static int loopback_test(struct slgt_info *info); +static int adapter_test(struct slgt_info *info); + +static void reset_adapter(struct slgt_info *info); +static void reset_port(struct slgt_info *info); +static void async_mode(struct slgt_info *info); +static void hdlc_mode(struct slgt_info *info); + +static void rx_stop(struct slgt_info *info); +static void rx_start(struct slgt_info *info); +static void reset_rbufs(struct slgt_info *info); +static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); +static void rdma_reset(struct slgt_info *info); +static int rx_get_frame(struct slgt_info *info); +static int rx_get_buf(struct slgt_info *info); + +static void tx_start(struct slgt_info *info); +static void tx_stop(struct slgt_info *info); +static void tx_set_idle(struct slgt_info *info); +static unsigned int free_tbuf_count(struct slgt_info *info); +static void reset_tbufs(struct slgt_info *info); +static void tdma_reset(struct slgt_info *info); +static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); + +static void get_signals(struct slgt_info *info); +static void set_signals(struct slgt_info *info); +static void enable_loopback(struct slgt_info *info); +static void set_rate(struct slgt_info *info, u32 data_rate); + +static int bh_action(struct slgt_info *info); +static void bh_handler(void* context); +static void bh_transmit(struct slgt_info *info); +static void isr_serial(struct slgt_info *info); +static void isr_rdma(struct slgt_info *info); +static void isr_txeom(struct slgt_info *info, unsigned short status); +static void isr_tdma(struct slgt_info *info); +static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs); + +static int alloc_dma_bufs(struct slgt_info *info); +static void free_dma_bufs(struct slgt_info *info); +static int alloc_desc(struct slgt_info *info); +static void free_desc(struct slgt_info *info); +static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); +static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); + +static int alloc_tmp_rbuf(struct slgt_info *info); +static void free_tmp_rbuf(struct slgt_info *info); + +static void tx_timeout(unsigned long context); +static void rx_timeout(unsigned long context); + +/* + * ioctl handlers + */ +static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount); +static int get_params(struct slgt_info *info, MGSL_PARAMS __user *params); +static int set_params(struct slgt_info *info, MGSL_PARAMS __user *params); +static int get_txidle(struct slgt_info *info, int __user *idle_mode); +static int set_txidle(struct slgt_info *info, int idle_mode); +static int tx_enable(struct slgt_info *info, int enable); +static int tx_abort(struct slgt_info *info); +static int rx_enable(struct slgt_info *info, int enable); +static int modem_input_wait(struct slgt_info *info,int arg); +static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr); +static int tiocmget(struct tty_struct *tty, struct file *file); +static int tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); +static void set_break(struct tty_struct *tty, int break_state); +static int get_interface(struct slgt_info *info, int __user *if_mode); +static int set_interface(struct slgt_info *info, int if_mode); + +/* + * driver functions + */ +static void add_device(struct slgt_info *info); +static void device_init(int adapter_num, struct pci_dev *pdev); +static int claim_resources(struct slgt_info *info); +static void release_resources(struct slgt_info *info); + +/* + * DEBUG OUTPUT CODE + */ +#ifndef DBGINFO +#define DBGINFO(fmt) +#endif +#ifndef DBGERR +#define DBGERR(fmt) +#endif +#ifndef DBGBH +#define DBGBH(fmt) +#endif +#ifndef DBGISR +#define DBGISR(fmt) +#endif + +#ifdef DBGDATA +static void trace_block(struct slgt_info *info, const char *data, int count, const char *label) +{ + int i; + int linecount; + printk("%s %s data:\n",info->device_name, label); + while(count) { + linecount = (count > 16) ? 16 : count; + for(i=0; i < linecount; i++) + printk("%02X ",(unsigned char)data[i]); + for(;i<17;i++) + printk(" "); + for(i=0;i=040 && data[i]<=0176) + printk("%c",data[i]); + else + printk("."); + } + printk("\n"); + data += linecount; + count -= linecount; + } +} +#else +#define DBGDATA(info, buf, size, label) +#endif + +#ifdef DBGTBUF +static void dump_tbufs(struct slgt_info *info) +{ + int i; + printk("tbuf_current=%d\n", info->tbuf_current); + for (i=0 ; i < info->tbuf_count ; i++) { + printk("%d: count=%04X status=%04X\n", + i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status)); + } +} +#else +#define DBGTBUF(info) +#endif + +#ifdef DBGRBUF +static void dump_rbufs(struct slgt_info *info) +{ + int i; + printk("rbuf_current=%d\n", info->rbuf_current); + for (i=0 ; i < info->rbuf_count ; i++) { + printk("%d: count=%04X status=%04X\n", + i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status)); + } +} +#else +#define DBGRBUF(info) +#endif + +static inline int sanity_check(struct slgt_info *info, char *devname, const char *name) +{ +#ifdef SANITY_CHECK + if (!info) { + printk("null struct slgt_info for (%s) in %s\n", devname, name); + return 1; + } + if (info->magic != MGSL_MAGIC) { + printk("bad magic number struct slgt_info (%s) in %s\n", devname, name); + return 1; + } +#else + if (!info) + return 1; +#endif + return 0; +} + +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_receive_buf - pass receive data to line discipline + */ +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + +/* tty callbacks */ + +static int open(struct tty_struct *tty, struct file *filp) +{ + struct slgt_info *info; + int retval, line; + unsigned long flags; + + line = tty->index; + if ((line < 0) || (line >= slgt_device_count)) { + DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); + return -ENODEV; + } + + info = slgt_device_list; + while(info && info->line != line) + info = info->next_device; + if (sanity_check(info, tty->name, "open")) + return -ENODEV; + if (info->init_error) { + DBGERR(("%s init error=%d\n", info->device_name, info->init_error)); + return -ENODEV; + } + + tty->driver_data = info; + info->tty = tty; + + DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->count)); + + /* If port is closing, signal caller to try again */ + if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); + goto cleanup; + } + + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + spin_lock_irqsave(&info->netlock, flags); + if (info->netcount) { + retval = -EBUSY; + spin_unlock_irqrestore(&info->netlock, flags); + goto cleanup; + } + info->count++; + spin_unlock_irqrestore(&info->netlock, flags); + + if (info->count == 1) { + /* 1st open on this device, init hardware */ + retval = startup(info); + if (retval < 0) + goto cleanup; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { + DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval)); + goto cleanup; + } + + retval = 0; + +cleanup: + if (retval) { + if (tty->count == 1) + info->tty = NULL; /* tty layer will release tty struct */ + if(info->count) + info->count--; + } + + DBGINFO(("%s open rc=%d\n", info->device_name, retval)); + return retval; +} + +static void close(struct tty_struct *tty, struct file *filp) +{ + struct slgt_info *info = tty->driver_data; + + if (sanity_check(info, tty->name, "close")) + return; + DBGINFO(("%s close entry, count=%d\n", info->device_name, info->count)); + + if (!info->count) + return; + + if (tty_hung_up_p(filp)) + goto cleanup; + + if ((tty->count == 1) && (info->count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + DBGERR(("%s close: bad refcount; tty->count=1, " + "info->count=%d\n", info->device_name, info->count)); + info->count = 1; + } + + info->count--; + + /* if at least one open remaining, leave hardware active */ + if (info->count) + goto cleanup; + + info->flags |= ASYNC_CLOSING; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + DBGINFO(("%s call tty_wait_until_sent\n", info->device_name)); + tty_wait_until_sent(tty, info->closing_wait); + } + + if (info->flags & ASYNC_INITIALIZED) + wait_until_sent(tty, info->timeout); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + tty_ldisc_flush(tty); + + shutdown(info); + + tty->closing = 0; + info->tty = NULL; + + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs(info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + + wake_up_interruptible(&info->close_wait); + +cleanup: + DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->count)); +} + +static void hangup(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + + if (sanity_check(info, tty->name, "hangup")) + return; + DBGINFO(("%s hangup\n", info->device_name)); + + flush_buffer(tty); + shutdown(info); + + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->tty = NULL; + + wake_up_interruptible(&info->open_wait); +} + +static void set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + DBGINFO(("%s set_termios\n", tty->driver->name)); + + /* just return if nothing has changed */ + if ((tty->termios->c_cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_params(info); + + /* Handle transition to B0 status */ + if (old_termios->c_cflag & CBAUD && + !(tty->termios->c_cflag & CBAUD)) { + info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + tty->termios->c_cflag & CBAUD) { + info->signals |= SerialSignal_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->signals |= SerialSignal_RTS; + } + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + /* Handle turning off CRTSCTS */ + if (old_termios->c_cflag & CRTSCTS && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + tx_release(tty); + } +} + +static int write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + int ret = 0; + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "write")) + goto cleanup; + DBGINFO(("%s write count=%d\n", info->device_name, count)); + + if (!tty || !info->tx_buf) + goto cleanup; + + if (count > info->max_frame_size) { + ret = -EIO; + goto cleanup; + } + + if (!count) + goto cleanup; + + if (info->params.mode == MGSL_MODE_RAW) { + unsigned int bufs_needed = (count/DMABUFSIZE); + unsigned int bufs_free = free_tbuf_count(info); + if (count % DMABUFSIZE) + ++bufs_needed; + if (bufs_needed > bufs_free) + goto cleanup; + } else { + if (info->tx_active) + goto cleanup; + if (info->tx_count) { + /* send accumulated data from send_char() calls */ + /* as frame and wait before accepting more data. */ + tx_load(info, info->tx_buf, info->tx_count); + goto start; + } + } + + ret = info->tx_count = count; + tx_load(info, buf, count); + goto start; + +start: + if (info->tx_count && !tty->stopped && !tty->hw_stopped) { + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + +cleanup: + DBGINFO(("%s write rc=%d\n", info->device_name, ret)); + return ret; +} + +static void put_char(struct tty_struct *tty, unsigned char ch) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "put_char")) + return; + DBGINFO(("%s put_char(%d)\n", info->device_name, ch)); + if (!tty || !info->tx_buf) + return; + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active && (info->tx_count < info->max_frame_size)) + info->tx_buf[info->tx_count++] = ch; + spin_unlock_irqrestore(&info->lock,flags); +} + +static void send_xchar(struct tty_struct *tty, char ch) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "send_xchar")) + return; + DBGINFO(("%s send_xchar(%d)\n", info->device_name, ch)); + info->x_char = ch; + if (ch) { + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_enabled) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +static void wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct slgt_info *info = tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (!info ) + return; + if (sanity_check(info, tty->name, "wait_until_sent")) + return; + DBGINFO(("%s wait_until_sent entry\n", info->device_name)); + if (!(info->flags & ASYNC_INITIALIZED)) + goto exit; + + orig_jiffies = jiffies; + + /* Set check interval to 1/5 of estimated time to + * send a character, and make it at least 1. The check + * interval should also be less than the timeout. + * Note: use tight timings here to satisfy the NIST-PCTS. + */ + + if (info->params.data_rate) { + char_time = info->timeout/(32 * 5); + if (!char_time) + char_time++; + } else + char_time = 1; + + if (timeout) + char_time = min_t(unsigned long, char_time, timeout); + + while (info->tx_active) { + msleep_interruptible(jiffies_to_msecs(char_time)); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + +exit: + DBGINFO(("%s wait_until_sent exit\n", info->device_name)); +} + +static int write_room(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + int ret; + + if (sanity_check(info, tty->name, "write_room")) + return 0; + ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; + DBGINFO(("%s write_room=%d\n", info->device_name, ret)); + return ret; +} + +static void flush_chars(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "flush_chars")) + return; + DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count)); + + if (info->tx_count <= 0 || tty->stopped || + tty->hw_stopped || !info->tx_buf) + return; + + DBGINFO(("%s flush_chars start transmit\n", info->device_name)); + + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active && info->tx_count) { + tx_load(info, info->tx_buf,info->tx_count); + tx_start(info); + } + spin_unlock_irqrestore(&info->lock,flags); +} + +static void flush_buffer(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "flush_buffer")) + return; + DBGINFO(("%s flush_buffer\n", info->device_name)); + + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + info->tx_count = 0; + spin_unlock_irqrestore(&info->lock,flags); + + wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); +} + +/* + * throttle (stop) transmitter + */ +static void tx_hold(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "tx_hold")) + return; + DBGINFO(("%s tx_hold\n", info->device_name)); + spin_lock_irqsave(&info->lock,flags); + if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC) + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); +} + +/* + * release (start) transmitter + */ +static void tx_release(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "tx_release")) + return; + DBGINFO(("%s tx_release\n", info->device_name)); + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active && info->tx_count) { + tx_load(info, info->tx_buf, info->tx_count); + tx_start(info); + } + spin_unlock_irqrestore(&info->lock,flags); +} + +/* + * Service an IOCTL request + * + * Arguments + * + * tty pointer to tty instance data + * file pointer to associated file object for device + * cmd IOCTL command code + * arg command argument/context + * + * Return 0 if success, otherwise error code + */ +static int ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct slgt_info *info = tty->driver_data; + struct mgsl_icount cnow; /* kernel counter temps */ + struct serial_icounter_struct __user *p_cuser; /* user space */ + unsigned long flags; + void __user *argp = (void __user *)arg; + + if (sanity_check(info, tty->name, "ioctl")) + return -ENODEV; + DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case MGSL_IOCGPARAMS: + return get_params(info, argp); + case MGSL_IOCSPARAMS: + return set_params(info, argp); + case MGSL_IOCGTXIDLE: + return get_txidle(info, argp); + case MGSL_IOCSTXIDLE: + return set_txidle(info, (int)arg); + case MGSL_IOCTXENABLE: + return tx_enable(info, (int)arg); + case MGSL_IOCRXENABLE: + return rx_enable(info, (int)arg); + case MGSL_IOCTXABORT: + return tx_abort(info); + case MGSL_IOCGSTATS: + return get_stats(info, argp); + case MGSL_IOCWAITEVENT: + return wait_mgsl_event(info, argp); + case TIOCMIWAIT: + return modem_input_wait(info,(int)arg); + case MGSL_IOCGIF: + return get_interface(info, argp); + case MGSL_IOCSIF: + return set_interface(info,(int)arg); + case TIOCGICOUNT: + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->lock,flags); + p_cuser = argp; + if (put_user(cnow.cts, &p_cuser->cts) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd) || + put_user(cnow.rx, &p_cuser->rx) || + put_user(cnow.tx, &p_cuser->tx) || + put_user(cnow.frame, &p_cuser->frame) || + put_user(cnow.overrun, &p_cuser->overrun) || + put_user(cnow.parity, &p_cuser->parity) || + put_user(cnow.brk, &p_cuser->brk) || + put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* + * proc fs support + */ +static inline int line_info(char *buf, struct slgt_info *info) +{ + char stat_buf[30]; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", + info->device_name, info->phys_reg_addr, + info->irq_level, info->max_frame_size); + + /* output current serial signal states */ + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (info->signals & SerialSignal_RTS) + strcat(stat_buf, "|RTS"); + if (info->signals & SerialSignal_CTS) + strcat(stat_buf, "|CTS"); + if (info->signals & SerialSignal_DTR) + strcat(stat_buf, "|DTR"); + if (info->signals & SerialSignal_DSR) + strcat(stat_buf, "|DSR"); + if (info->signals & SerialSignal_DCD) + strcat(stat_buf, "|CD"); + if (info->signals & SerialSignal_RI) + strcat(stat_buf, "|RI"); + + if (info->params.mode != MGSL_MODE_ASYNC) { + ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", + info->icount.txok, info->icount.rxok); + if (info->icount.txunder) + ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + if (info->icount.txabort) + ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + if (info->icount.rxshort) + ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + if (info->icount.rxlong) + ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + if (info->icount.rxover) + ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + if (info->icount.rxcrc) + ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); + } else { + ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", + info->icount.tx, info->icount.rx); + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + } + + /* Append serial signal status to end */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + + ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + info->tx_active,info->bh_requested,info->bh_running, + info->pending_bh); + + return ret; +} + +/* Called to print information about devices + */ +static int read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0, l; + off_t begin = 0; + struct slgt_info *info; + + len += sprintf(page, "synclink_gt driver:%s\n", driver_version); + + info = slgt_device_list; + while( info ) { + l = line_info(page + len, info); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + info = info->next_device; + } + + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * return count of bytes in transmit buffer + */ +static int chars_in_buffer(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + if (sanity_check(info, tty->name, "chars_in_buffer")) + return 0; + DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count)); + return info->tx_count; +} + +/* + * signal remote device to throttle send data (our receive data) + */ +static void throttle(struct tty_struct * tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "throttle")) + return; + DBGINFO(("%s throttle\n", info->device_name)); + if (I_IXOFF(tty)) + send_xchar(tty, STOP_CHAR(tty)); + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->lock,flags); + info->signals &= ~SerialSignal_RTS; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* + * signal remote device to stop throttling send data (our receive data) + */ +static void unthrottle(struct tty_struct * tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "unthrottle")) + return; + DBGINFO(("%s unthrottle\n", info->device_name)); + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->lock,flags); + info->signals |= SerialSignal_RTS; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* + * set or clear transmit break condition + * break_state -1=set break condition, 0=clear + */ +static void set_break(struct tty_struct *tty, int break_state) +{ + struct slgt_info *info = tty->driver_data; + unsigned short value; + unsigned long flags; + + if (sanity_check(info, tty->name, "set_break")) + return; + DBGINFO(("%s set_break(%d)\n", info->device_name, break_state)); + + spin_lock_irqsave(&info->lock,flags); + value = rd_reg16(info, TCR); + if (break_state == -1) + value |= BIT6; + else + value &= ~BIT6; + wr_reg16(info, TCR, value); + spin_unlock_irqrestore(&info->lock,flags); +} + +#ifdef CONFIG_HDLC + +/** + * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * set encoding and frame check sequence (FCS) options + * + * dev pointer to network device structure + * encoding serial encoding setting + * parity FCS setting + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) +{ + struct slgt_info *info = dev_to_port(dev); + unsigned char new_encoding; + unsigned short new_crctype; + + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; + + DBGINFO(("%s hdlcdev_attach\n", info->device_name)); + + switch (encoding) + { + case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; + case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; + case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; + case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; + case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; + default: return -EINVAL; + } + + switch (parity) + { + case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; + case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; + case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; + default: return -EINVAL; + } + + info->params.encoding = new_encoding; + info->params.crc_type = new_crctype;; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + program_hw(info); + + return 0; +} + +/** + * called by generic HDLC layer to send frame + * + * skb socket buffer containing HDLC frame + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + + DBGINFO(("%s hdlc_xmit\n", dev->name)); + + /* stop sending until this frame completes */ + netif_stop_queue(dev); + + /* copy data to device buffers */ + info->tx_count = skb->len; + tx_load(info, skb->data, skb->len); + + /* update network statistics */ + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* done with socket buffer, so free it */ + dev_kfree_skb(skb); + + /* save start time for transmit timeout detection */ + dev->trans_start = jiffies; + + /* start hardware transmitter if necessary */ + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; +} + +/** + * called by network layer when interface enabled + * claim resources and initialize hardware + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_open(struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + int rc; + unsigned long flags; + + DBGINFO(("%s hdlcdev_open\n", dev->name)); + + /* generic HDLC layer open processing */ + if ((rc = hdlc_open(dev))) + return rc; + + /* arbitrate between network and tty opens */ + spin_lock_irqsave(&info->netlock, flags); + if (info->count != 0 || info->netcount != 0) { + DBGINFO(("%s hdlc_open busy\n", dev->name)); + spin_unlock_irqrestore(&info->netlock, flags); + return -EBUSY; + } + info->netcount=1; + spin_unlock_irqrestore(&info->netlock, flags); + + /* claim resources and init adapter */ + if ((rc = startup(info)) != 0) { + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + return rc; + } + + /* assert DTR and RTS, apply hardware settings */ + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + program_hw(info); + + /* enable network layer transmit */ + dev->trans_start = jiffies; + netif_start_queue(dev); + + /* inform generic HDLC layer of current DCD status */ + spin_lock_irqsave(&info->lock, flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock, flags); + hdlc_set_carrier(info->signals & SerialSignal_DCD, dev); + + return 0; +} + +/** + * called by network layer when interface is disabled + * shutdown hardware and release resources + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_close(struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + unsigned long flags; + + DBGINFO(("%s hdlcdev_close\n", dev->name)); + + netif_stop_queue(dev); + + /* shutdown adapter and release resources */ + shutdown(info); + + hdlc_close(dev); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + + return 0; +} + +/** + * called by network layer to process IOCTL call to network device + * + * dev pointer to network device structure + * ifr pointer to network interface request structure + * cmd IOCTL command code + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + struct slgt_info *info = dev_to_port(dev); + unsigned int flags; + + DBGINFO(("%s hdlcdev_ioctl\n", dev->name)); + + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; + + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: /* return current sync_serial_settings */ + + ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + + flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + + switch (flags){ + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; + case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; + default: new_line.clock_type = CLOCK_DEFAULT; + } + + new_line.clock_rate = info->params.clock_speed; + new_line.loopback = info->params.loopback ? 1:0; + + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + switch (new_line.clock_type) + { + case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; + case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; + case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; + case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; + case CLOCK_DEFAULT: flags = info->params.flags & + (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; + default: return -EINVAL; + } + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + info->params.flags |= flags; + + info->params.loopback = new_line.loopback; + + if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) + info->params.clock_speed = new_line.clock_rate; + else + info->params.clock_speed = 0; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + program_hw(info); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } +} + +/** + * called by network layer when transmit timeout is detected + * + * dev pointer to network device structure + */ +static void hdlcdev_tx_timeout(struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + + DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name)); + + stats->tx_errors++; + stats->tx_aborted_errors++; + + spin_lock_irqsave(&info->lock,flags); + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); + + netif_wake_queue(dev); +} + +/** + * called by device driver when transmit completes + * reenable network layer transmit if stopped + * + * info pointer to device instance information + */ +static void hdlcdev_tx_done(struct slgt_info *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +/** + * called by device driver when frame received + * pass frame to network layer + * + * info pointer to device instance information + * buf pointer to buffer contianing frame data + * size count of data bytes in buf + */ +static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) +{ + struct sk_buff *skb = dev_alloc_skb(size); + struct net_device *dev = info->netdev; + struct net_device_stats *stats = hdlc_stats(dev); + + DBGINFO(("%s hdlcdev_rx\n", dev->name)); + + if (skb == NULL) { + DBGERR(("%s: can't alloc skb, drop packet\n", dev->name)); + stats->rx_dropped++; + return; + } + + memcpy(skb_put(skb, size),buf,size); + + skb->protocol = hdlc_type_trans(skb, info->netdev); + + stats->rx_packets++; + stats->rx_bytes += size; + + netif_rx(skb); + + info->netdev->last_rx = jiffies; +} + +/** + * called by device driver when adding device instance + * do generic HDLC initialization + * + * info pointer to device instance information + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_init(struct slgt_info *info) +{ + int rc; + struct net_device *dev; + hdlc_device *hdlc; + + /* allocate and initialize network and HDLC layer objects */ + + if (!(dev = alloc_hdlcdev(info))) { + printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); + return -ENOMEM; + } + + /* for network layer reporting purposes only */ + dev->mem_start = info->phys_reg_addr; + dev->mem_end = info->phys_reg_addr + SLGT_REG_SIZE - 1; + dev->irq = info->irq_level; + + /* network layer callbacks and settings */ + dev->do_ioctl = hdlcdev_ioctl; + dev->open = hdlcdev_open; + dev->stop = hdlcdev_close; + dev->tx_timeout = hdlcdev_tx_timeout; + dev->watchdog_timeo = 10*HZ; + dev->tx_queue_len = 50; + + /* generic HDLC layer callbacks and settings */ + hdlc = dev_to_hdlc(dev); + hdlc->attach = hdlcdev_attach; + hdlc->xmit = hdlcdev_xmit; + + /* register objects with HDLC layer */ + if ((rc = register_hdlc_device(dev))) { + printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); + free_netdev(dev); + return rc; + } + + info->netdev = dev; + return 0; +} + +/** + * called by device driver when removing device instance + * do generic HDLC cleanup + * + * info pointer to device instance information + */ +static void hdlcdev_exit(struct slgt_info *info) +{ + unregister_hdlc_device(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; +} + +#endif /* ifdef CONFIG_HDLC */ + +/* + * get async data from rx DMA buffers + */ +static void rx_async(struct slgt_info *info) +{ + struct tty_struct *tty = info->tty; + struct mgsl_icount *icount = &info->icount; + unsigned int start, end; + unsigned char *p; + unsigned char status; + struct slgt_desc *bufs = info->rbufs; + int i, count; + + start = end = info->rbuf_current; + + while(desc_complete(bufs[end])) { + count = desc_count(bufs[end]) - info->rbuf_index; + p = bufs[end].buf + info->rbuf_index; + + DBGISR(("%s rx_async count=%d\n", info->device_name, count)); + DBGDATA(info, p, count, "rx"); + + for(i=0 ; i < count; i+=2, p+=2) { + if (tty) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + tty_flip_buffer_push(tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = *p; + *tty->flip.flag_buf_ptr = 0; + } + icount->rx++; + + if ((status = *(p+1) & (BIT9 + BIT8))) { + if (status & BIT9) + icount->parity++; + else if (status & BIT8) + icount->frame++; + /* discard char if tty control flags say so */ + if (status & info->ignore_status_mask) + continue; + if (tty) { + if (status & BIT9) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & BIT8) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + } + if (tty) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + } + + if (i < count) { + /* receive buffer not completed */ + info->rbuf_index += i; + info->rx_timer.expires = jiffies + 1; + add_timer(&info->rx_timer); + break; + } + + info->rbuf_index = 0; + free_rbufs(info, end, end); + + if (++end == info->rbuf_count) + end = 0; + + /* if entire list searched then no frame available */ + if (end == start) + break; + } + + if (tty && tty->flip.count) + tty_flip_buffer_push(tty); +} + +/* + * return next bottom half action to perform + */ +static int bh_action(struct slgt_info *info) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&info->lock,flags); + + if (info->pending_bh & BH_RECEIVE) { + info->pending_bh &= ~BH_RECEIVE; + rc = BH_RECEIVE; + } else if (info->pending_bh & BH_TRANSMIT) { + info->pending_bh &= ~BH_TRANSMIT; + rc = BH_TRANSMIT; + } else if (info->pending_bh & BH_STATUS) { + info->pending_bh &= ~BH_STATUS; + rc = BH_STATUS; + } else { + /* Mark BH routine as complete */ + info->bh_running = 0; + info->bh_requested = 0; + rc = 0; + } + + spin_unlock_irqrestore(&info->lock,flags); + + return rc; +} + +/* + * perform bottom half processing + */ +static void bh_handler(void* context) +{ + struct slgt_info *info = context; + int action; + + if (!info) + return; + info->bh_running = 1; + + while((action = bh_action(info))) { + switch (action) { + case BH_RECEIVE: + DBGBH(("%s bh receive\n", info->device_name)); + switch(info->params.mode) { + case MGSL_MODE_ASYNC: + rx_async(info); + break; + case MGSL_MODE_HDLC: + while(rx_get_frame(info)); + break; + case MGSL_MODE_RAW: + while(rx_get_buf(info)); + break; + } + /* restart receiver if rx DMA buffers exhausted */ + if (info->rx_restart) + rx_start(info); + break; + case BH_TRANSMIT: + bh_transmit(info); + break; + case BH_STATUS: + DBGBH(("%s bh status\n", info->device_name)); + info->ri_chkcount = 0; + info->dsr_chkcount = 0; + info->dcd_chkcount = 0; + info->cts_chkcount = 0; + break; + default: + DBGBH(("%s unknown action\n", info->device_name)); + break; + } + } + DBGBH(("%s bh_handler exit\n", info->device_name)); +} + +static void bh_transmit(struct slgt_info *info) +{ + struct tty_struct *tty = info->tty; + + DBGBH(("%s bh_transmit\n", info->device_name)); + if (tty) { + tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +static void dsr_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_DSR); + return; + } + info->icount.dsr++; + if (info->signals & SerialSignal_DSR) + info->input_signal_events.dsr_up++; + else + info->input_signal_events.dsr_down++; + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; +} + +static void cts_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_CTS); + return; + } + info->icount.cts++; + if (info->signals & SerialSignal_CTS) + info->input_signal_events.cts_up++; + else + info->input_signal_events.cts_down++; + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; + + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty) { + if (info->tty->hw_stopped) { + if (info->signals & SerialSignal_CTS) { + info->tty->hw_stopped = 0; + info->pending_bh |= BH_TRANSMIT; + return; + } + } else { + if (!(info->signals & SerialSignal_CTS)) + info->tty->hw_stopped = 1; + } + } + } +} + +static void dcd_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_DCD); + return; + } + info->icount.dcd++; + if (info->signals & SerialSignal_DCD) { + info->input_signal_events.dcd_up++; + } else { + info->input_signal_events.dcd_down++; + } +#ifdef CONFIG_HDLC + if (info->netcount) + hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev); +#endif + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; + + if (info->flags & ASYNC_CHECK_CD) { + if (info->signals & SerialSignal_DCD) + wake_up_interruptible(&info->open_wait); + else { + if (info->tty) + tty_hangup(info->tty); + } + } +} + +static void ri_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_RI); + return; + } + info->icount.dcd++; + if (info->signals & SerialSignal_RI) { + info->input_signal_events.ri_up++; + } else { + info->input_signal_events.ri_down++; + } + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; +} + +static void isr_serial(struct slgt_info *info) +{ + unsigned short status = rd_reg16(info, SSR); + + DBGISR(("%s isr_serial status=%04X\n", info->device_name, status)); + + wr_reg16(info, SSR, status); /* clear pending */ + + info->irq_occurred = 1; + + if (info->params.mode == MGSL_MODE_ASYNC) { + if (status & IRQ_TXIDLE) { + if (info->tx_count) + isr_txeom(info, status); + } + if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { + info->icount.brk++; + /* process break detection if tty control allows */ + if (info->tty) { + if (!(status & info->ignore_status_mask)) { + if (info->read_status_mask & MASK_BREAK) { + *info->tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(info->tty); + } + } + } + } + } else { + if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) + isr_txeom(info, status); + + if (status & IRQ_RXIDLE) { + if (status & RXIDLE) + info->icount.rxidle++; + else + info->icount.exithunt++; + wake_up_interruptible(&info->event_wait_q); + } + + if (status & IRQ_RXOVER) + rx_start(info); + } + + if (status & IRQ_DSR) + dsr_change(info); + if (status & IRQ_CTS) + cts_change(info); + if (status & IRQ_DCD) + dcd_change(info); + if (status & IRQ_RI) + ri_change(info); +} + +static void isr_rdma(struct slgt_info *info) +{ + unsigned int status = rd_reg32(info, RDCSR); + + DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status)); + + /* RDCSR (rx DMA control/status) + * + * 31..07 reserved + * 06 save status byte to DMA buffer + * 05 error + * 04 eol (end of list) + * 03 eob (end of buffer) + * 02 IRQ enable + * 01 reset + * 00 enable + */ + wr_reg32(info, RDCSR, status); /* clear pending */ + + if (status & (BIT5 + BIT4)) { + DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); + info->rx_restart = 1; + } + info->pending_bh |= BH_RECEIVE; +} + +static void isr_tdma(struct slgt_info *info) +{ + unsigned int status = rd_reg32(info, TDCSR); + + DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status)); + + /* TDCSR (tx DMA control/status) + * + * 31..06 reserved + * 05 error + * 04 eol (end of list) + * 03 eob (end of buffer) + * 02 IRQ enable + * 01 reset + * 00 enable + */ + wr_reg32(info, TDCSR, status); /* clear pending */ + + if (status & (BIT5 + BIT4 + BIT3)) { + // another transmit buffer has completed + // run bottom half to get more send data from user + info->pending_bh |= BH_TRANSMIT; + } +} + +static void isr_txeom(struct slgt_info *info, unsigned short status) +{ + DBGISR(("%s txeom status=%04x\n", info->device_name, status)); + + slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); + tdma_reset(info); + reset_tbufs(info); + if (status & IRQ_TXUNDER) { + unsigned short val = rd_reg16(info, TCR); + wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, TCR, val); /* clear reset bit */ + } + + if (info->tx_active) { + if (info->params.mode != MGSL_MODE_ASYNC) { + if (status & IRQ_TXUNDER) + info->icount.txunder++; + else if (status & IRQ_TXIDLE) + info->icount.txok++; + } + + info->tx_active = 0; + info->tx_count = 0; + + del_timer(&info->tx_timer); + + if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { + info->signals &= ~SerialSignal_RTS; + info->drop_rts_on_tx_done = 0; + set_signals(info); + } + +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_tx_done(info); + else +#endif + { + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + tx_stop(info); + return; + } + info->pending_bh |= BH_TRANSMIT; + } + } +} + +/* interrupt service routine + * + * irq interrupt number + * dev_id device ID supplied during interrupt registration + * regs interrupted processor context + */ +static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct slgt_info *info; + unsigned int gsr; + unsigned int i; + + DBGISR(("slgt_interrupt irq=%d entry\n", irq)); + + info = dev_id; + if (!info) + return IRQ_NONE; + + spin_lock(&info->lock); + + while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { + DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); + info->irq_occurred = 1; + for(i=0; i < info->port_count ; i++) { + if (info->port_array[i] == NULL) + continue; + if (gsr & (BIT8 << i)) + isr_serial(info->port_array[i]); + if (gsr & (BIT16 << (i*2))) + isr_rdma(info->port_array[i]); + if (gsr & (BIT17 << (i*2))) + isr_tdma(info->port_array[i]); + } + } + + for(i=0; i < info->port_count ; i++) { + struct slgt_info *port = info->port_array[i]; + + if (port && (port->count || port->netcount) && + port->pending_bh && !port->bh_running && + !port->bh_requested) { + DBGISR(("%s bh queued\n", port->device_name)); + schedule_work(&port->task); + port->bh_requested = 1; + } + } + + spin_unlock(&info->lock); + + DBGISR(("slgt_interrupt irq=%d exit\n", irq)); + return IRQ_HANDLED; +} + +static int startup(struct slgt_info *info) +{ + DBGINFO(("%s startup\n", info->device_name)); + + if (info->flags & ASYNC_INITIALIZED) + return 0; + + if (!info->tx_buf) { + info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); + if (!info->tx_buf) { + DBGERR(("%s can't allocate tx buffer\n", info->device_name)); + return -ENOMEM; + } + } + + info->pending_bh = 0; + + memset(&info->icount, 0, sizeof(info->icount)); + + /* program hardware for current parameters */ + change_params(info); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags |= ASYNC_INITIALIZED; + + return 0; +} + +/* + * called by close() and hangup() to shutdown hardware + */ +static void shutdown(struct slgt_info *info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + DBGINFO(("%s shutdown\n", info->device_name)); + + /* clear status wait queue because status changes */ + /* can't happen after shutting down the hardware */ + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + + del_timer_sync(&info->tx_timer); + del_timer_sync(&info->rx_timer); + + kfree(info->tx_buf); + info->tx_buf = NULL; + + spin_lock_irqsave(&info->lock,flags); + + tx_stop(info); + rx_stop(info); + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); + + if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + set_signals(info); + } + + spin_unlock_irqrestore(&info->lock,flags); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; +} + +static void program_hw(struct slgt_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(&info->lock,flags); + + rx_stop(info); + tx_stop(info); + + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW || + info->netcount) + hdlc_mode(info); + else + async_mode(info); + + set_signals(info); + + info->dcd_chkcount = 0; + info->cts_chkcount = 0; + info->ri_chkcount = 0; + info->dsr_chkcount = 0; + + slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR); + get_signals(info); + + if (info->netcount || + (info->tty && info->tty->termios->c_cflag & CREAD)) + rx_start(info); + + spin_unlock_irqrestore(&info->lock,flags); +} + +/* + * reconfigure adapter based on new parameters + */ +static void change_params(struct slgt_info *info) +{ + unsigned cflag; + int bits_per_char; + + if (!info->tty || !info->tty->termios) + return; + DBGINFO(("%s change_params\n", info->device_name)); + + cflag = info->tty->termios->c_cflag; + + /* if B0 rate (hangup) specified then negate DTR and RTS */ + /* otherwise assert DTR and RTS */ + if (cflag & CBAUD) + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + + /* byte size and parity */ + + switch (cflag & CSIZE) { + case CS5: info->params.data_bits = 5; break; + case CS6: info->params.data_bits = 6; break; + case CS7: info->params.data_bits = 7; break; + case CS8: info->params.data_bits = 8; break; + default: info->params.data_bits = 7; break; + } + + info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1; + + if (cflag & PARENB) + info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN; + else + info->params.parity = ASYNC_PARITY_NONE; + + /* calculate number of jiffies to transmit a full + * FIFO (32 bytes) at specified data rate + */ + bits_per_char = info->params.data_bits + + info->params.stop_bits + 1; + + info->params.data_rate = tty_get_baud_rate(info->tty); + + if (info->params.data_rate) { + info->timeout = (32*HZ*bits_per_char) / + info->params.data_rate; + } + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /* process tty input control flags */ + + info->read_status_mask = IRQ_RXOVER; + if (I_INPCK(info->tty)) + info->read_status_mask |= MASK_PARITY | MASK_FRAMING; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= MASK_BREAK; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= MASK_BREAK; + /* If ignoring parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= MASK_OVERRUN; + } + + program_hw(info); +} + +static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount) +{ + DBGINFO(("%s get_stats\n", info->device_name)); + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount))) + return -EFAULT; + } + return 0; +} + +static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params) +{ + DBGINFO(("%s get_params\n", info->device_name)); + if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS))) + return -EFAULT; + return 0; +} + +static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params) +{ + unsigned long flags; + MGSL_PARAMS tmp_params; + + DBGINFO(("%s set_params\n", info->device_name)); + if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS))) + return -EFAULT; + + spin_lock_irqsave(&info->lock, flags); + memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS)); + spin_unlock_irqrestore(&info->lock, flags); + + change_params(info); + + return 0; +} + +static int get_txidle(struct slgt_info *info, int __user *idle_mode) +{ + DBGINFO(("%s get_txidle=%d\n", info->device_name, info->idle_mode)); + if (put_user(info->idle_mode, idle_mode)) + return -EFAULT; + return 0; +} + +static int set_txidle(struct slgt_info *info, int idle_mode) +{ + unsigned long flags; + DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode)); + spin_lock_irqsave(&info->lock,flags); + info->idle_mode = idle_mode; + tx_set_idle(info); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int tx_enable(struct slgt_info *info, int enable) +{ + unsigned long flags; + DBGINFO(("%s tx_enable(%d)\n", info->device_name, enable)); + spin_lock_irqsave(&info->lock,flags); + if (enable) { + if (!info->tx_enabled) + tx_start(info); + } else { + if (info->tx_enabled) + tx_stop(info); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* + * abort transmit HDLC frame + */ +static int tx_abort(struct slgt_info *info) +{ + unsigned long flags; + DBGINFO(("%s tx_abort\n", info->device_name)); + spin_lock_irqsave(&info->lock,flags); + tdma_reset(info); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int rx_enable(struct slgt_info *info, int enable) +{ + unsigned long flags; + DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable)); + spin_lock_irqsave(&info->lock,flags); + if (enable) { + if (!info->rx_enabled) + rx_start(info); + } else { + if (info->rx_enabled) + rx_stop(info); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* + * wait for specified event to occur + */ +static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr) +{ + unsigned long flags; + int s; + int rc=0; + struct mgsl_icount cprev, cnow; + int events; + int mask; + struct _input_signal_events oldsigs, newsigs; + DECLARE_WAITQUEUE(wait, current); + + if (get_user(mask, mask_ptr)) + return -EFAULT; + + DBGINFO(("%s wait_mgsl_event(%d)\n", info->device_name, mask)); + + spin_lock_irqsave(&info->lock,flags); + + /* return immediately if state matches requested events */ + get_signals(info); + s = info->signals; + + events = mask & + ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + + ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + + ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + + ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); + if (events) { + spin_unlock_irqrestore(&info->lock,flags); + goto exit; + } + + /* save current irq counts */ + cprev = info->icount; + oldsigs = info->input_signal_events; + + /* enable hunt and idle irqs if needed */ + if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) { + unsigned short val = rd_reg16(info, SCR); + if (!(val & IRQ_RXIDLE)) + wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE)); + } + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&info->event_wait_q, &wait); + + spin_unlock_irqrestore(&info->lock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get current irq counts */ + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + newsigs = info->input_signal_events; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + /* if no change, wait aborted for some reason */ + if (newsigs.dsr_up == oldsigs.dsr_up && + newsigs.dsr_down == oldsigs.dsr_down && + newsigs.dcd_up == oldsigs.dcd_up && + newsigs.dcd_down == oldsigs.dcd_down && + newsigs.cts_up == oldsigs.cts_up && + newsigs.cts_down == oldsigs.cts_down && + newsigs.ri_up == oldsigs.ri_up && + newsigs.ri_down == oldsigs.ri_down && + cnow.exithunt == cprev.exithunt && + cnow.rxidle == cprev.rxidle) { + rc = -EIO; + break; + } + + events = mask & + ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + + (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + + (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + + (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + + (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + + (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + + (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + + (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + + (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + + (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); + if (events) + break; + + cprev = cnow; + oldsigs = newsigs; + } + + remove_wait_queue(&info->event_wait_q, &wait); + set_current_state(TASK_RUNNING); + + + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + spin_lock_irqsave(&info->lock,flags); + if (!waitqueue_active(&info->event_wait_q)) { + /* disable enable exit hunt mode/idle rcvd IRQs */ + wr_reg16(info, SCR, + (unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE)); + } + spin_unlock_irqrestore(&info->lock,flags); + } +exit: + if (rc == 0) + rc = put_user(events, mask_ptr); + return rc; +} + +static int get_interface(struct slgt_info *info, int __user *if_mode) +{ + DBGINFO(("%s get_interface=%x\n", info->device_name, info->if_mode)); + if (put_user(info->if_mode, if_mode)) + return -EFAULT; + return 0; +} + +static int set_interface(struct slgt_info *info, int if_mode) +{ + unsigned long flags; + unsigned char val; + + DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode)); + spin_lock_irqsave(&info->lock,flags); + info->if_mode = if_mode; + + msc_set_vcr(info); + + /* TCR (tx control) 07 1=RTS driver control */ + val = rd_reg16(info, TCR); + if (info->if_mode & MGSL_INTERFACE_RTS_EN) + val |= BIT7; + else + val &= ~BIT7; + wr_reg16(info, TCR, val); + + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int modem_input_wait(struct slgt_info *info,int arg) +{ + unsigned long flags; + int rc; + struct mgsl_icount cprev, cnow; + DECLARE_WAITQUEUE(wait, current); + + /* save current irq counts */ + spin_lock_irqsave(&info->lock,flags); + cprev = info->icount; + add_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get new irq counts */ + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + /* if no change, wait aborted for some reason */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; + break; + } + + /* check for change in caller specified modem input */ + if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || + (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || + (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || + (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { + rc = 0; + break; + } + + cprev = cnow; + } + remove_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_RUNNING); + return rc; +} + +/* + * return state of serial control and status signals + */ +static int tiocmget(struct tty_struct *tty, struct file *file) +{ + struct slgt_info *info = tty->driver_data; + unsigned int result; + unsigned long flags; + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) + + ((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) + + ((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) + + ((info->signals & SerialSignal_RI) ? TIOCM_RNG:0) + + ((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) + + ((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0); + + DBGINFO(("%s tiocmget value=%08X\n", info->device_name, result)); + return result; +} + +/* + * set modem control signals (DTR/RTS) + * + * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit + * TIOCMSET = set/clear signal values + * value bit mask for command + */ +static int tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + DBGINFO(("%s tiocmset(%x,%x)\n", info->device_name, set, clear)); + + if (set & TIOCM_RTS) + info->signals |= SerialSignal_RTS; + if (set & TIOCM_DTR) + info->signals |= SerialSignal_DTR; + if (clear & TIOCM_RTS) + info->signals &= ~SerialSignal_RTS; + if (clear & TIOCM_DTR) + info->signals &= ~SerialSignal_DTR; + + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* + * block current process until the device is ready to open + */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct slgt_info *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + DBGINFO(("%s block_til_ready\n", tty->driver->name)); + + if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + /* nonblock mode is set or port is not enabled */ + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* Wait for carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + spin_lock_irqsave(&info->lock, flags); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + info->count--; + } + spin_unlock_irqrestore(&info->lock, flags); + info->blocked_open++; + + while (1) { + if ((tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->lock,flags); + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + set_current_state(TASK_INTERRUPTIBLE); + + if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ + retval = (info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + if (!(info->flags & ASYNC_CLOSING) && + (do_clocal || (info->signals & SerialSignal_DCD)) ) { + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + + if (extra_count) + info->count++; + info->blocked_open--; + + if (!retval) + info->flags |= ASYNC_NORMAL_ACTIVE; + + DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); + return retval; +} + +static int alloc_tmp_rbuf(struct slgt_info *info) +{ + info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL); + if (info->tmp_rbuf == NULL) + return -ENOMEM; + return 0; +} + +static void free_tmp_rbuf(struct slgt_info *info) +{ + kfree(info->tmp_rbuf); + info->tmp_rbuf = NULL; +} + +/* + * allocate DMA descriptor lists. + */ +static int alloc_desc(struct slgt_info *info) +{ + unsigned int i; + unsigned int pbufs; + + /* allocate memory to hold descriptor lists */ + info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr); + if (info->bufs == NULL) + return -ENOMEM; + + memset(info->bufs, 0, DESC_LIST_SIZE); + + info->rbufs = (struct slgt_desc*)info->bufs; + info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count; + + pbufs = (unsigned int)info->bufs_dma_addr; + + /* + * Build circular lists of descriptors + */ + + for (i=0; i < info->rbuf_count; i++) { + /* physical address of this descriptor */ + info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc)); + + /* physical address of next descriptor */ + if (i == info->rbuf_count - 1) + info->rbufs[i].next = cpu_to_le32(pbufs); + else + info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc))); + set_desc_count(info->rbufs[i], DMABUFSIZE); + } + + for (i=0; i < info->tbuf_count; i++) { + /* physical address of this descriptor */ + info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc)); + + /* physical address of next descriptor */ + if (i == info->tbuf_count - 1) + info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc)); + else + info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc))); + } + + return 0; +} + +static void free_desc(struct slgt_info *info) +{ + if (info->bufs != NULL) { + pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr); + info->bufs = NULL; + info->rbufs = NULL; + info->tbufs = NULL; + } +} + +static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) +{ + int i; + for (i=0; i < count; i++) { + if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL) + return -ENOMEM; + bufs[i].pbuf = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr); + } + return 0; +} + +static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) +{ + int i; + for (i=0; i < count; i++) { + if (bufs[i].buf == NULL) + continue; + pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr); + bufs[i].buf = NULL; + } +} + +static int alloc_dma_bufs(struct slgt_info *info) +{ + info->rbuf_count = 32; + info->tbuf_count = 32; + + if (alloc_desc(info) < 0 || + alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 || + alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 || + alloc_tmp_rbuf(info) < 0) { + DBGERR(("%s DMA buffer alloc fail\n", info->device_name)); + return -ENOMEM; + } + reset_rbufs(info); + return 0; +} + +static void free_dma_bufs(struct slgt_info *info) +{ + if (info->bufs) { + free_bufs(info, info->rbufs, info->rbuf_count); + free_bufs(info, info->tbufs, info->tbuf_count); + free_desc(info); + } + free_tmp_rbuf(info); +} + +static int claim_resources(struct slgt_info *info) +{ + if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) { + DBGERR(("%s reg addr conflict, addr=%08X\n", + info->device_name, info->phys_reg_addr)); + info->init_error = DiagStatus_AddressConflict; + goto errout; + } + else + info->reg_addr_requested = 1; + + info->reg_addr = ioremap(info->phys_reg_addr, PAGE_SIZE); + if (!info->reg_addr) { + DBGERR(("%s cant map device registers, addr=%08X\n", + info->device_name, info->phys_reg_addr)); + info->init_error = DiagStatus_CantAssignPciResources; + goto errout; + } + info->reg_addr += info->reg_offset; + return 0; + +errout: + release_resources(info); + return -ENODEV; +} + +static void release_resources(struct slgt_info *info) +{ + if (info->irq_requested) { + free_irq(info->irq_level, info); + info->irq_requested = 0; + } + + if (info->reg_addr_requested) { + release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE); + info->reg_addr_requested = 0; + } + + if (info->reg_addr) { + iounmap(info->reg_addr - info->reg_offset); + info->reg_addr = NULL; + } +} + +/* Add the specified device instance data structure to the + * global linked list of devices and increment the device count. + */ +static void add_device(struct slgt_info *info) +{ + char *devstr; + + info->next_device = NULL; + info->line = slgt_device_count; + sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line); + + if (info->line < MAX_DEVICES) { + if (maxframe[info->line]) + info->max_frame_size = maxframe[info->line]; + info->dosyncppp = dosyncppp[info->line]; + } + + slgt_device_count++; + + if (!slgt_device_list) + slgt_device_list = info; + else { + struct slgt_info *current_dev = slgt_device_list; + while(current_dev->next_device) + current_dev = current_dev->next_device; + current_dev->next_device = info; + } + + if (info->max_frame_size < 4096) + info->max_frame_size = 4096; + else if (info->max_frame_size > 65535) + info->max_frame_size = 65535; + + switch(info->pdev->device) { + case SYNCLINK_GT_DEVICE_ID: + devstr = "GT"; + break; + case SYNCLINK_GT4_DEVICE_ID: + devstr = "GT4"; + break; + case SYNCLINK_AC_DEVICE_ID: + devstr = "AC"; + info->params.mode = MGSL_MODE_ASYNC; + break; + default: + devstr = "(unknown model)"; + } + printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u\n", + devstr, info->device_name, info->phys_reg_addr, + info->irq_level, info->max_frame_size); + +#ifdef CONFIG_HDLC + hdlcdev_init(info); +#endif +} + +/* + * allocate device instance structure, return NULL on failure + */ +static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) +{ + struct slgt_info *info; + + info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL); + + if (!info) { + DBGERR(("%s device alloc failed adapter=%d port=%d\n", + driver_name, adapter_num, port_num)); + } else { + memset(info, 0, sizeof(struct slgt_info)); + info->magic = MGSL_MAGIC; + INIT_WORK(&info->task, bh_handler, info); + info->max_frame_size = 4096; + info->raw_rx_size = DMABUFSIZE; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->status_event_wait_q); + init_waitqueue_head(&info->event_wait_q); + spin_lock_init(&info->netlock); + memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); + info->idle_mode = HDLC_TXIDLE_FLAGS; + info->adapter_num = adapter_num; + info->port_num = port_num; + + init_timer(&info->tx_timer); + info->tx_timer.data = (unsigned long)info; + info->tx_timer.function = tx_timeout; + + init_timer(&info->rx_timer); + info->rx_timer.data = (unsigned long)info; + info->rx_timer.function = rx_timeout; + + /* Copy configuration info to device instance data */ + info->pdev = pdev; + info->irq_level = pdev->irq; + info->phys_reg_addr = pci_resource_start(pdev,0); + + /* veremap works on page boundaries + * map full page starting at the page boundary + */ + info->reg_offset = info->phys_reg_addr & (PAGE_SIZE-1); + info->phys_reg_addr &= ~(PAGE_SIZE-1); + + info->bus_type = MGSL_BUS_TYPE_PCI; + info->irq_flags = SA_SHIRQ; + + info->init_error = -1; /* assume error, set to 0 on successful init */ + } + + return info; +} + +static void device_init(int adapter_num, struct pci_dev *pdev) +{ + struct slgt_info *port_array[SLGT_MAX_PORTS]; + int i; + int port_count = 1; + + if (pdev->device == SYNCLINK_GT4_DEVICE_ID) + port_count = 4; + + /* allocate device instances for all ports */ + for (i=0; i < port_count; ++i) { + port_array[i] = alloc_dev(adapter_num, i, pdev); + if (port_array[i] == NULL) { + for (--i; i >= 0; --i) + kfree(port_array[i]); + return; + } + } + + /* give copy of port_array to all ports and add to device list */ + for (i=0; i < port_count; ++i) { + memcpy(port_array[i]->port_array, port_array, sizeof(port_array)); + add_device(port_array[i]); + port_array[i]->port_count = port_count; + spin_lock_init(&port_array[i]->lock); + } + + /* Allocate and claim adapter resources */ + if (!claim_resources(port_array[0])) { + + alloc_dma_bufs(port_array[0]); + + /* copy resource information from first port to others */ + for (i = 1; i < port_count; ++i) { + port_array[i]->lock = port_array[0]->lock; + port_array[i]->irq_level = port_array[0]->irq_level; + port_array[i]->reg_addr = port_array[0]->reg_addr; + alloc_dma_bufs(port_array[i]); + } + + if (request_irq(port_array[0]->irq_level, + slgt_interrupt, + port_array[0]->irq_flags, + port_array[0]->device_name, + port_array[0]) < 0) { + DBGERR(("%s request_irq failed IRQ=%d\n", + port_array[0]->device_name, + port_array[0]->irq_level)); + } else { + port_array[0]->irq_requested = 1; + adapter_test(port_array[0]); + for (i=1 ; i < port_count ; i++) + port_array[i]->init_error = port_array[0]->init_error; + } + } +} + +static int __devinit init_one(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + if (pci_enable_device(dev)) { + printk("error enabling pci device %p\n", dev); + return -EIO; + } + pci_set_master(dev); + device_init(slgt_device_count, dev); + return 0; +} + +static void __devexit remove_one(struct pci_dev *dev) +{ +} + +static struct tty_operations ops = { + .open = open, + .close = close, + .write = write, + .put_char = put_char, + .flush_chars = flush_chars, + .write_room = write_room, + .chars_in_buffer = chars_in_buffer, + .flush_buffer = flush_buffer, + .ioctl = ioctl, + .throttle = throttle, + .unthrottle = unthrottle, + .send_xchar = send_xchar, + .break_ctl = set_break, + .wait_until_sent = wait_until_sent, + .read_proc = read_proc, + .set_termios = set_termios, + .stop = tx_hold, + .start = tx_release, + .hangup = hangup, + .tiocmget = tiocmget, + .tiocmset = tiocmset, +}; + +static void slgt_cleanup(void) +{ + int rc; + struct slgt_info *info; + struct slgt_info *tmp; + + printk("unload %s %s\n", driver_name, driver_version); + + if (serial_driver) { + if ((rc = tty_unregister_driver(serial_driver))) + DBGERR(("tty_unregister_driver error=%d\n", rc)); + put_tty_driver(serial_driver); + } + + /* reset devices */ + info = slgt_device_list; + while(info) { + reset_port(info); + info = info->next_device; + } + + /* release devices */ + info = slgt_device_list; + while(info) { +#ifdef CONFIG_HDLC + hdlcdev_exit(info); +#endif + free_dma_bufs(info); + free_tmp_rbuf(info); + if (info->port_num == 0) + release_resources(info); + tmp = info; + info = info->next_device; + kfree(tmp); + } + + if (pci_registered) + pci_unregister_driver(&pci_driver); +} + +/* + * Driver initialization entry point. + */ +static int __init slgt_init(void) +{ + int rc; + + printk("%s %s\n", driver_name, driver_version); + + slgt_device_count = 0; + if ((rc = pci_register_driver(&pci_driver)) < 0) { + printk("%s pci_register_driver error=%d\n", driver_name, rc); + return rc; + } + pci_registered = 1; + + if (!slgt_device_list) { + printk("%s no devices found\n",driver_name); + return -ENODEV; + } + + serial_driver = alloc_tty_driver(MAX_DEVICES); + if (!serial_driver) { + rc = -ENOMEM; + goto error; + } + + /* Initialize the tty_driver structure */ + + serial_driver->owner = THIS_MODULE; + serial_driver->driver_name = tty_driver_name; + serial_driver->name = tty_dev_prefix; + serial_driver->major = ttymajor; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(serial_driver, &ops); + if ((rc = tty_register_driver(serial_driver)) < 0) { + DBGERR(("%s can't register serial driver\n", driver_name)); + put_tty_driver(serial_driver); + serial_driver = NULL; + goto error; + } + + printk("%s %s, tty major#%d\n", + driver_name, driver_version, + serial_driver->major); + + return 0; + +error: + slgt_cleanup(); + return rc; +} + +static void __exit slgt_exit(void) +{ + slgt_cleanup(); +} + +module_init(slgt_init); +module_exit(slgt_exit); + +/* + * register access routines + */ + +#define CALC_REGADDR() \ + unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \ + if (addr >= 0x80) \ + reg_addr += (info->port_num) * 32; + +static __u8 rd_reg8(struct slgt_info *info, unsigned int addr) +{ + CALC_REGADDR(); + return readb((void __iomem *)reg_addr); +} + +static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value) +{ + CALC_REGADDR(); + writeb(value, (void __iomem *)reg_addr); +} + +static __u16 rd_reg16(struct slgt_info *info, unsigned int addr) +{ + CALC_REGADDR(); + return readw((void __iomem *)reg_addr); +} + +static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value) +{ + CALC_REGADDR(); + writew(value, (void __iomem *)reg_addr); +} + +static __u32 rd_reg32(struct slgt_info *info, unsigned int addr) +{ + CALC_REGADDR(); + return readl((void __iomem *)reg_addr); +} + +static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value) +{ + CALC_REGADDR(); + writel(value, (void __iomem *)reg_addr); +} + +static void rdma_reset(struct slgt_info *info) +{ + unsigned int i; + + /* set reset bit */ + wr_reg32(info, RDCSR, BIT1); + + /* wait for enable bit cleared */ + for(i=0 ; i < 1000 ; i++) + if (!(rd_reg32(info, RDCSR) & BIT0)) + break; +} + +static void tdma_reset(struct slgt_info *info) +{ + unsigned int i; + + /* set reset bit */ + wr_reg32(info, TDCSR, BIT1); + + /* wait for enable bit cleared */ + for(i=0 ; i < 1000 ; i++) + if (!(rd_reg32(info, TDCSR) & BIT0)) + break; +} + +/* + * enable internal loopback + * TxCLK and RxCLK are generated from BRG + * and TxD is looped back to RxD internally. + */ +static void enable_loopback(struct slgt_info *info) +{ + /* SCR (serial control) BIT2=looopback enable */ + wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2)); + + if (info->params.mode != MGSL_MODE_ASYNC) { + /* CCR (clock control) + * 07..05 tx clock source (010 = BRG) + * 04..02 rx clock source (010 = BRG) + * 01 auxclk enable (0 = disable) + * 00 BRG enable (1 = enable) + * + * 0100 1001 + */ + wr_reg8(info, CCR, 0x49); + + /* set speed if available, otherwise use default */ + if (info->params.clock_speed) + set_rate(info, info->params.clock_speed); + else + set_rate(info, 3686400); + } +} + +/* + * set baud rate generator to specified rate + */ +static void set_rate(struct slgt_info *info, u32 rate) +{ + unsigned int div; + static unsigned int osc = 14745600; + + /* div = osc/rate - 1 + * + * Round div up if osc/rate is not integer to + * force to next slowest rate. + */ + + if (rate) { + div = osc/rate; + if (!(osc % rate) && div) + div--; + wr_reg16(info, BDR, (unsigned short)div); + } +} + +static void rx_stop(struct slgt_info *info) +{ + unsigned short val; + + /* disable and reset receiver */ + val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ + wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, RCR, val); /* clear reset bit */ + + slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE); + + /* clear pending rx interrupts */ + wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER); + + rdma_reset(info); + + info->rx_enabled = 0; + info->rx_restart = 0; +} + +static void rx_start(struct slgt_info *info) +{ + unsigned short val; + + slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA); + + /* clear pending rx overrun IRQ */ + wr_reg16(info, SSR, IRQ_RXOVER); + + /* reset and disable receiver */ + val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ + wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, RCR, val); /* clear reset bit */ + + rdma_reset(info); + reset_rbufs(info); + + /* set 1st descriptor address */ + wr_reg32(info, RDDAR, info->rbufs[0].pdesc); + + if (info->params.mode != MGSL_MODE_ASYNC) { + /* enable rx DMA and DMA interrupt */ + wr_reg32(info, RDCSR, (BIT2 + BIT0)); + } else { + /* enable saving of rx status, rx DMA and DMA interrupt */ + wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); + } + + slgt_irq_on(info, IRQ_RXOVER); + + /* enable receiver */ + wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1)); + + info->rx_restart = 0; + info->rx_enabled = 1; +} + +static void tx_start(struct slgt_info *info) +{ + if (!info->tx_enabled) { + wr_reg16(info, TCR, + (unsigned short)(rd_reg16(info, TCR) | BIT1)); + info->tx_enabled = TRUE; + } + + if (info->tx_count) { + info->drop_rts_on_tx_done = 0; + + if (info->params.mode != MGSL_MODE_ASYNC) { + if (info->params.flags & HDLC_FLAG_AUTO_RTS) { + get_signals(info); + if (!(info->signals & SerialSignal_RTS)) { + info->signals |= SerialSignal_RTS; + set_signals(info); + info->drop_rts_on_tx_done = 1; + } + } + + slgt_irq_off(info, IRQ_TXDATA); + slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); + /* clear tx idle and underrun status bits */ + wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); + + if (!(rd_reg32(info, TDCSR) & BIT0)) { + /* tx DMA stopped, restart tx DMA */ + tdma_reset(info); + /* set 1st descriptor address */ + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); + if (info->params.mode == MGSL_MODE_RAW) + wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ + else + wr_reg32(info, TDCSR, BIT0); /* DMA enable */ + } + + if (info->params.mode != MGSL_MODE_RAW) { + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); + add_timer(&info->tx_timer); + } + } else { + tdma_reset(info); + /* set 1st descriptor address */ + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); + + slgt_irq_off(info, IRQ_TXDATA); + slgt_irq_on(info, IRQ_TXIDLE); + /* clear tx idle status bit */ + wr_reg16(info, SSR, IRQ_TXIDLE); + + /* enable tx DMA */ + wr_reg32(info, TDCSR, BIT0); + } + + info->tx_active = 1; + } +} + +static void tx_stop(struct slgt_info *info) +{ + unsigned short val; + + del_timer(&info->tx_timer); + + tdma_reset(info); + + /* reset and disable transmitter */ + val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ + wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, TCR, val); /* clear reset */ + + slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); + + /* clear tx idle and underrun status bit */ + wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); + + reset_tbufs(info); + + info->tx_enabled = 0; + info->tx_active = 0; +} + +static void reset_port(struct slgt_info *info) +{ + if (!info->reg_addr) + return; + + tx_stop(info); + rx_stop(info); + + info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + set_signals(info); + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); +} + +static void reset_adapter(struct slgt_info *info) +{ + int i; + for (i=0; i < info->port_count; ++i) { + if (info->port_array[i]) + reset_port(info->port_array[i]); + } +} + +static void async_mode(struct slgt_info *info) +{ + unsigned short val; + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); + tx_stop(info); + rx_stop(info); + + /* TCR (tx control) + * + * 15..13 mode, 010=async + * 12..10 encoding, 000=NRZ + * 09 parity enable + * 08 1=odd parity, 0=even parity + * 07 1=RTS driver control + * 06 1=break enable + * 05..04 character length + * 00=5 bits + * 01=6 bits + * 10=7 bits + * 11=8 bits + * 03 0=1 stop bit, 1=2 stop bits + * 02 reset + * 01 enable + * 00 auto-CTS enable + */ + val = 0x4000; + + if (info->if_mode & MGSL_INTERFACE_RTS_EN) + val |= BIT7; + + if (info->params.parity != ASYNC_PARITY_NONE) { + val |= BIT9; + if (info->params.parity == ASYNC_PARITY_ODD) + val |= BIT8; + } + + switch (info->params.data_bits) + { + case 6: val |= BIT4; break; + case 7: val |= BIT5; break; + case 8: val |= BIT5 + BIT4; break; + } + + if (info->params.stop_bits != 1) + val |= BIT3; + + if (info->params.flags & HDLC_FLAG_AUTO_CTS) + val |= BIT0; + + wr_reg16(info, TCR, val); + + /* RCR (rx control) + * + * 15..13 mode, 010=async + * 12..10 encoding, 000=NRZ + * 09 parity enable + * 08 1=odd parity, 0=even parity + * 07..06 reserved, must be 0 + * 05..04 character length + * 00=5 bits + * 01=6 bits + * 10=7 bits + * 11=8 bits + * 03 reserved, must be zero + * 02 reset + * 01 enable + * 00 auto-DCD enable + */ + val = 0x4000; + + if (info->params.parity != ASYNC_PARITY_NONE) { + val |= BIT9; + if (info->params.parity == ASYNC_PARITY_ODD) + val |= BIT8; + } + + switch (info->params.data_bits) + { + case 6: val |= BIT4; break; + case 7: val |= BIT5; break; + case 8: val |= BIT5 + BIT4; break; + } + + if (info->params.flags & HDLC_FLAG_AUTO_DCD) + val |= BIT0; + + wr_reg16(info, RCR, val); + + /* CCR (clock control) + * + * 07..05 011 = tx clock source is BRG/16 + * 04..02 010 = rx clock source is BRG + * 01 0 = auxclk disabled + * 00 1 = BRG enabled + * + * 0110 1001 + */ + wr_reg8(info, CCR, 0x69); + + msc_set_vcr(info); + + tx_set_idle(info); + + /* SCR (serial control) + * + * 15 1=tx req on FIFO half empty + * 14 1=rx req on FIFO half full + * 13 tx data IRQ enable + * 12 tx idle IRQ enable + * 11 rx break on IRQ enable + * 10 rx data IRQ enable + * 09 rx break off IRQ enable + * 08 overrun IRQ enable + * 07 DSR IRQ enable + * 06 CTS IRQ enable + * 05 DCD IRQ enable + * 04 RI IRQ enable + * 03 reserved, must be zero + * 02 1=txd->rxd internal loopback enable + * 01 reserved, must be zero + * 00 1=master IRQ enable + */ + val = BIT15 + BIT14 + BIT0; + wr_reg16(info, SCR, val); + + slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER); + + set_rate(info, info->params.data_rate * 16); + + if (info->params.loopback) + enable_loopback(info); +} + +static void hdlc_mode(struct slgt_info *info) +{ + unsigned short val; + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); + tx_stop(info); + rx_stop(info); + + /* TCR (tx control) + * + * 15..13 mode, 000=HDLC 001=raw sync + * 12..10 encoding + * 09 CRC enable + * 08 CRC32 + * 07 1=RTS driver control + * 06 preamble enable + * 05..04 preamble length + * 03 share open/close flag + * 02 reset + * 01 enable + * 00 auto-CTS enable + */ + val = 0; + + if (info->params.mode == MGSL_MODE_RAW) + val |= BIT13; + if (info->if_mode & MGSL_INTERFACE_RTS_EN) + val |= BIT7; + + switch(info->params.encoding) + { + case HDLC_ENCODING_NRZB: val |= BIT10; break; + case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; + case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; + case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; + case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; + case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; + } + + switch (info->params.crc_type) + { + case HDLC_CRC_16_CCITT: val |= BIT9; break; + case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; + } + + if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) + val |= BIT6; + + switch (info->params.preamble_length) + { + case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break; + case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break; + case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break; + } + + if (info->params.flags & HDLC_FLAG_AUTO_CTS) + val |= BIT0; + + wr_reg16(info, TCR, val); + + /* TPR (transmit preamble) */ + + switch (info->params.preamble) + { + case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; + case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; + case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break; + case HDLC_PREAMBLE_PATTERN_10: val = 0x55; break; + case HDLC_PREAMBLE_PATTERN_01: val = 0xaa; break; + default: val = 0x7e; break; + } + wr_reg8(info, TPR, (unsigned char)val); + + /* RCR (rx control) + * + * 15..13 mode, 000=HDLC 001=raw sync + * 12..10 encoding + * 09 CRC enable + * 08 CRC32 + * 07..03 reserved, must be 0 + * 02 reset + * 01 enable + * 00 auto-DCD enable + */ + val = 0; + + if (info->params.mode == MGSL_MODE_RAW) + val |= BIT13; + + switch(info->params.encoding) + { + case HDLC_ENCODING_NRZB: val |= BIT10; break; + case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; + case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; + case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; + case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; + case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; + } + + switch (info->params.crc_type) + { + case HDLC_CRC_16_CCITT: val |= BIT9; break; + case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; + } + + if (info->params.flags & HDLC_FLAG_AUTO_DCD) + val |= BIT0; + + wr_reg16(info, RCR, val); + + /* CCR (clock control) + * + * 07..05 tx clock source + * 04..02 rx clock source + * 01 auxclk enable + * 00 BRG enable + */ + val = 0; + + if (info->params.flags & HDLC_FLAG_TXC_BRG) + { + // when RxC source is DPLL, BRG generates 16X DPLL + // reference clock, so take TxC from BRG/16 to get + // transmit clock at actual data rate + if (info->params.flags & HDLC_FLAG_RXC_DPLL) + val |= BIT6 + BIT5; /* 011, txclk = BRG/16 */ + else + val |= BIT6; /* 010, txclk = BRG */ + } + else if (info->params.flags & HDLC_FLAG_TXC_DPLL) + val |= BIT7; /* 100, txclk = DPLL Input */ + else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN) + val |= BIT5; /* 001, txclk = RXC Input */ + + if (info->params.flags & HDLC_FLAG_RXC_BRG) + val |= BIT3; /* 010, rxclk = BRG */ + else if (info->params.flags & HDLC_FLAG_RXC_DPLL) + val |= BIT4; /* 100, rxclk = DPLL */ + else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN) + val |= BIT2; /* 001, rxclk = TXC Input */ + + if (info->params.clock_speed) + val |= BIT1 + BIT0; + + wr_reg8(info, CCR, (unsigned char)val); + + if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL)) + { + // program DPLL mode + switch(info->params.encoding) + { + case HDLC_ENCODING_BIPHASE_MARK: + case HDLC_ENCODING_BIPHASE_SPACE: + val = BIT7; break; + case HDLC_ENCODING_BIPHASE_LEVEL: + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: + val = BIT7 + BIT6; break; + default: val = BIT6; // NRZ encodings + } + wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val)); + + // DPLL requires a 16X reference clock from BRG + set_rate(info, info->params.clock_speed * 16); + } + else + set_rate(info, info->params.clock_speed); + + tx_set_idle(info); + + msc_set_vcr(info); + + /* SCR (serial control) + * + * 15 1=tx req on FIFO half empty + * 14 1=rx req on FIFO half full + * 13 tx data IRQ enable + * 12 tx idle IRQ enable + * 11 underrun IRQ enable + * 10 rx data IRQ enable + * 09 rx idle IRQ enable + * 08 overrun IRQ enable + * 07 DSR IRQ enable + * 06 CTS IRQ enable + * 05 DCD IRQ enable + * 04 RI IRQ enable + * 03 reserved, must be zero + * 02 1=txd->rxd internal loopback enable + * 01 reserved, must be zero + * 00 1=master IRQ enable + */ + wr_reg16(info, SCR, BIT15 + BIT14 + BIT0); + + if (info->params.loopback) + enable_loopback(info); +} + +/* + * set transmit idle mode + */ +static void tx_set_idle(struct slgt_info *info) +{ + unsigned char val = 0xff; + + switch(info->idle_mode) + { + case HDLC_TXIDLE_FLAGS: val = 0x7e; break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break; + case HDLC_TXIDLE_ZEROS: val = 0x00; break; + case HDLC_TXIDLE_ONES: val = 0xff; break; + case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break; + case HDLC_TXIDLE_SPACE: val = 0x00; break; + case HDLC_TXIDLE_MARK: val = 0xff; break; + } + + wr_reg8(info, TIR, val); +} + +/* + * get state of V24 status (input) signals + */ +static void get_signals(struct slgt_info *info) +{ + unsigned short status = rd_reg16(info, SSR); + + /* clear all serial signals except DTR and RTS */ + info->signals &= SerialSignal_DTR + SerialSignal_RTS; + + if (status & BIT3) + info->signals |= SerialSignal_DSR; + if (status & BIT2) + info->signals |= SerialSignal_CTS; + if (status & BIT1) + info->signals |= SerialSignal_DCD; + if (status & BIT0) + info->signals |= SerialSignal_RI; +} + +/* + * set V.24 Control Register based on current configuration + */ +static void msc_set_vcr(struct slgt_info *info) +{ + unsigned char val = 0; + + /* VCR (V.24 control) + * + * 07..04 serial IF select + * 03 DTR + * 02 RTS + * 01 LL + * 00 RL + */ + + switch(info->if_mode & MGSL_INTERFACE_MASK) + { + case MGSL_INTERFACE_RS232: + val |= BIT5; /* 0010 */ + break; + case MGSL_INTERFACE_V35: + val |= BIT7 + BIT6 + BIT5; /* 1110 */ + break; + case MGSL_INTERFACE_RS422: + val |= BIT6; /* 0100 */ + break; + } + + if (info->signals & SerialSignal_DTR) + val |= BIT3; + if (info->signals & SerialSignal_RTS) + val |= BIT2; + if (info->if_mode & MGSL_INTERFACE_LL) + val |= BIT1; + if (info->if_mode & MGSL_INTERFACE_RL) + val |= BIT0; + wr_reg8(info, VCR, val); +} + +/* + * set state of V24 control (output) signals + */ +static void set_signals(struct slgt_info *info) +{ + unsigned char val = rd_reg8(info, VCR); + if (info->signals & SerialSignal_DTR) + val |= BIT3; + else + val &= ~BIT3; + if (info->signals & SerialSignal_RTS) + val |= BIT2; + else + val &= ~BIT2; + wr_reg8(info, VCR, val); +} + +/* + * free range of receive DMA buffers (i to last) + */ +static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last) +{ + int done = 0; + + while(!done) { + /* reset current buffer for reuse */ + info->rbufs[i].status = 0; + if (info->params.mode == MGSL_MODE_RAW) + set_desc_count(info->rbufs[i], info->raw_rx_size); + else + set_desc_count(info->rbufs[i], DMABUFSIZE); + + if (i == last) + done = 1; + if (++i == info->rbuf_count) + i = 0; + } + info->rbuf_current = i; +} + +/* + * mark all receive DMA buffers as free + */ +static void reset_rbufs(struct slgt_info *info) +{ + free_rbufs(info, 0, info->rbuf_count - 1); +} + +/* + * pass receive HDLC frame to upper layer + * + * return 1 if frame available, otherwise 0 + */ +static int rx_get_frame(struct slgt_info *info) +{ + unsigned int start, end; + unsigned short status; + unsigned int framesize = 0; + int rc = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + unsigned char addr_field = 0xff; + +check_again: + + framesize = 0; + addr_field = 0xff; + start = end = info->rbuf_current; + + for (;;) { + if (!desc_complete(info->rbufs[end])) + goto cleanup; + + if (framesize == 0 && info->params.addr_filter != 0xff) + addr_field = info->rbufs[end].buf[0]; + + framesize += desc_count(info->rbufs[end]); + + if (desc_eof(info->rbufs[end])) + break; + + if (++end == info->rbuf_count) + end = 0; + + if (end == info->rbuf_current) { + if (info->rx_enabled){ + spin_lock_irqsave(&info->lock,flags); + rx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + goto cleanup; + } + } + + /* status + * + * 15 buffer complete + * 14..06 reserved + * 05..04 residue + * 02 eof (end of frame) + * 01 CRC error + * 00 abort + */ + status = desc_status(info->rbufs[end]); + + /* ignore CRC bit if not using CRC (bit is undefined) */ + if (info->params.crc_type == HDLC_CRC_NONE) + status &= ~BIT1; + + if (framesize == 0 || + (addr_field != 0xff && addr_field != info->params.addr_filter)) { + free_rbufs(info, start, end); + goto check_again; + } + + if (framesize < 2 || status & (BIT1+BIT0)) { + if (framesize < 2 || (status & BIT0)) + info->icount.rxshort++; + else + info->icount.rxcrc++; + framesize = 0; + +#ifdef CONFIG_HDLC + { + struct net_device_stats *stats = hdlc_stats(info->netdev); + stats->rx_errors++; + stats->rx_frame_errors++; + } +#endif + } else { + /* adjust frame size for CRC, if any */ + if (info->params.crc_type == HDLC_CRC_16_CCITT) + framesize -= 2; + else if (info->params.crc_type == HDLC_CRC_32_CCITT) + framesize -= 4; + } + + DBGBH(("%s rx frame status=%04X size=%d\n", + info->device_name, status, framesize)); + DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx"); + + if (framesize) { + if (framesize > info->max_frame_size) + info->icount.rxlong++; + else { + /* copy dma buffer(s) to contiguous temp buffer */ + int copy_count = framesize; + int i = start; + unsigned char *p = info->tmp_rbuf; + info->tmp_rbuf_count = framesize; + + info->icount.rxok++; + + while(copy_count) { + int partial_count = min(copy_count, DMABUFSIZE); + memcpy(p, info->rbufs[i].buf, partial_count); + p += partial_count; + copy_count -= partial_count; + if (++i == info->rbuf_count) + i = 0; + } + +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_rx(info,info->tmp_rbuf, framesize); + else +#endif + ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize); + } + } + free_rbufs(info, start, end); + rc = 1; + +cleanup: + return rc; +} + +/* + * pass receive buffer (RAW synchronous mode) to tty layer + * return 1 if buffer available, otherwise 0 + */ +static int rx_get_buf(struct slgt_info *info) +{ + unsigned int i = info->rbuf_current; + + if (!desc_complete(info->rbufs[i])) + return 0; + DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx"); + DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i]))); + ldisc_receive_buf(info->tty, info->rbufs[i].buf, + info->flag_buf, desc_count(info->rbufs[i])); + free_rbufs(info, i, i); + return 1; +} + +static void reset_tbufs(struct slgt_info *info) +{ + unsigned int i; + info->tbuf_current = 0; + for (i=0 ; i < info->tbuf_count ; i++) { + info->tbufs[i].status = 0; + info->tbufs[i].count = 0; + } +} + +/* + * return number of free transmit DMA buffers + */ +static unsigned int free_tbuf_count(struct slgt_info *info) +{ + unsigned int count = 0; + unsigned int i = info->tbuf_current; + + do + { + if (desc_count(info->tbufs[i])) + break; /* buffer in use */ + ++count; + if (++i == info->tbuf_count) + i=0; + } while (i != info->tbuf_current); + + /* last buffer with zero count may be in use, assume it is */ + if (count) + --count; + + return count; +} + +/* + * load transmit DMA buffer(s) with data + */ +static void tx_load(struct slgt_info *info, const char *buf, unsigned int size) +{ + unsigned short count; + unsigned int i; + struct slgt_desc *d; + + if (size == 0) + return; + + DBGDATA(info, buf, size, "tx"); + + info->tbuf_start = i = info->tbuf_current; + + while (size) { + d = &info->tbufs[i]; + if (++i == info->tbuf_count) + i = 0; + + count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size); + memcpy(d->buf, buf, count); + + size -= count; + buf += count; + + if (!size && info->params.mode != MGSL_MODE_RAW) + set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */ + else + set_desc_eof(*d, 0); + + set_desc_count(*d, count); + } + + info->tbuf_current = i; +} + +static int register_test(struct slgt_info *info) +{ + static unsigned short patterns[] = + {0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696}; + static unsigned int count = sizeof(patterns)/sizeof(patterns[0]); + unsigned int i; + int rc = 0; + + for (i=0 ; i < count ; i++) { + wr_reg16(info, TIR, patterns[i]); + wr_reg16(info, BDR, patterns[(i+1)%count]); + if ((rd_reg16(info, TIR) != patterns[i]) || + (rd_reg16(info, BDR) != patterns[(i+1)%count])) { + rc = -ENODEV; + break; + } + } + + info->init_error = rc ? 0 : DiagStatus_AddressFailure; + return rc; +} + +static int irq_test(struct slgt_info *info) +{ + unsigned long timeout; + unsigned long flags; + struct tty_struct *oldtty = info->tty; + u32 speed = info->params.data_rate; + + info->params.data_rate = 921600; + info->tty = NULL; + + spin_lock_irqsave(&info->lock, flags); + async_mode(info); + slgt_irq_on(info, IRQ_TXIDLE); + + /* enable transmitter */ + wr_reg16(info, TCR, + (unsigned short)(rd_reg16(info, TCR) | BIT1)); + + /* write one byte and wait for tx idle */ + wr_reg16(info, TDR, 0); + + /* assume failure */ + info->init_error = DiagStatus_IrqFailure; + info->irq_occurred = FALSE; + + spin_unlock_irqrestore(&info->lock, flags); + + timeout=100; + while(timeout-- && !info->irq_occurred) + msleep_interruptible(10); + + spin_lock_irqsave(&info->lock,flags); + reset_port(info); + spin_unlock_irqrestore(&info->lock,flags); + + info->params.data_rate = speed; + info->tty = oldtty; + + info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure; + return info->irq_occurred ? 0 : -ENODEV; +} + +static int loopback_test_rx(struct slgt_info *info) +{ + unsigned char *src, *dest; + int count; + + if (desc_complete(info->rbufs[0])) { + count = desc_count(info->rbufs[0]); + src = info->rbufs[0].buf; + dest = info->tmp_rbuf; + + for( ; count ; count-=2, src+=2) { + /* src=data byte (src+1)=status byte */ + if (!(*(src+1) & (BIT9 + BIT8))) { + *dest = *src; + dest++; + info->tmp_rbuf_count++; + } + } + DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx"); + return 1; + } + return 0; +} + +static int loopback_test(struct slgt_info *info) +{ +#define TESTFRAMESIZE 20 + + unsigned long timeout; + u16 count = TESTFRAMESIZE; + unsigned char buf[TESTFRAMESIZE]; + int rc = -ENODEV; + unsigned long flags; + + struct tty_struct *oldtty = info->tty; + MGSL_PARAMS params; + + memcpy(¶ms, &info->params, sizeof(params)); + + info->params.mode = MGSL_MODE_ASYNC; + info->params.data_rate = 921600; + info->params.loopback = 1; + info->tty = NULL; + + /* build and send transmit frame */ + for (count = 0; count < TESTFRAMESIZE; ++count) + buf[count] = (unsigned char)count; + + info->tmp_rbuf_count = 0; + memset(info->tmp_rbuf, 0, TESTFRAMESIZE); + + /* program hardware for HDLC and enabled receiver */ + spin_lock_irqsave(&info->lock,flags); + async_mode(info); + rx_start(info); + info->tx_count = count; + tx_load(info, buf, count); + tx_start(info); + spin_unlock_irqrestore(&info->lock, flags); + + /* wait for receive complete */ + for (timeout = 100; timeout; --timeout) { + msleep_interruptible(10); + if (loopback_test_rx(info)) { + rc = 0; + break; + } + } + + /* verify received frame length and contents */ + if (!rc && (info->tmp_rbuf_count != count || + memcmp(buf, info->tmp_rbuf, count))) { + rc = -ENODEV; + } + + spin_lock_irqsave(&info->lock,flags); + reset_adapter(info); + spin_unlock_irqrestore(&info->lock,flags); + + memcpy(&info->params, ¶ms, sizeof(info->params)); + info->tty = oldtty; + + info->init_error = rc ? DiagStatus_DmaFailure : 0; + return rc; +} + +static int adapter_test(struct slgt_info *info) +{ + DBGINFO(("testing %s\n", info->device_name)); + if ((info->init_error = register_test(info)) < 0) { + printk("register test failure %s addr=%08X\n", + info->device_name, info->phys_reg_addr); + } else if ((info->init_error = irq_test(info)) < 0) { + printk("IRQ test failure %s IRQ=%d\n", + info->device_name, info->irq_level); + } else if ((info->init_error = loopback_test(info)) < 0) { + printk("loopback test failure %s\n", info->device_name); + } + return info->init_error; +} + +/* + * transmit timeout handler + */ +static void tx_timeout(unsigned long context) +{ + struct slgt_info *info = (struct slgt_info*)context; + unsigned long flags; + + DBGINFO(("%s tx_timeout\n", info->device_name)); + if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + info->icount.txtimeout++; + } + spin_lock_irqsave(&info->lock,flags); + info->tx_active = 0; + info->tx_count = 0; + spin_unlock_irqrestore(&info->lock,flags); + +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_tx_done(info); + else +#endif + bh_transmit(info); +} + +/* + * receive buffer polling timer + */ +static void rx_timeout(unsigned long context) +{ + struct slgt_info *info = (struct slgt_info*)context; + unsigned long flags; + + DBGINFO(("%s rx_timeout\n", info->device_name)); + spin_lock_irqsave(&info->lock, flags); + info->pending_bh |= BH_RECEIVE; + spin_unlock_irqrestore(&info->lock, flags); + bh_handler(info); +} + diff --git a/include/linux/synclink.h b/include/linux/synclink.h index 763bd290f28d..1b7cd8d1a71b 100644 --- a/include/linux/synclink.h +++ b/include/linux/synclink.h @@ -1,7 +1,7 @@ /* * SyncLink Multiprotocol Serial Adapter Driver * - * $Id: synclink.h,v 3.6 2002/02/20 21:58:20 paulkf Exp $ + * $Id: synclink.h,v 3.10 2005/11/08 19:50:54 paulkf Exp $ * * Copyright (C) 1998-2000 by Microgate Corporation * @@ -128,10 +128,14 @@ #define MGSL_BUS_TYPE_EISA 2 #define MGSL_BUS_TYPE_PCI 5 +#define MGSL_INTERFACE_MASK 0xf #define MGSL_INTERFACE_DISABLE 0 #define MGSL_INTERFACE_RS232 1 #define MGSL_INTERFACE_V35 2 #define MGSL_INTERFACE_RS422 3 +#define MGSL_INTERFACE_RTS_EN 0x10 +#define MGSL_INTERFACE_LL 0x20 +#define MGSL_INTERFACE_RL 0x40 typedef struct _MGSL_PARAMS { @@ -163,6 +167,9 @@ typedef struct _MGSL_PARAMS #define SYNCLINK_DEVICE_ID 0x0010 #define MGSCC_DEVICE_ID 0x0020 #define SYNCLINK_SCA_DEVICE_ID 0x0030 +#define SYNCLINK_GT_DEVICE_ID 0x0070 +#define SYNCLINK_GT4_DEVICE_ID 0x0080 +#define SYNCLINK_AC_DEVICE_ID 0x0090 #define MGSL_MAX_SERIAL_NUMBER 30 /* -- cgit v1.2.3 From 9ded96f24c3a5fcbef954e88c443385a1af37eb9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2006 01:02:07 -0800 Subject: [PATCH] IRQ type flags Some ARM platforms have the ability to program the interrupt controller to detect various interrupt edges and/or levels. For some platforms, this is critical to setup correctly, particularly those which the setting is dependent on the device. Currently, ARM drivers do (eg) the following: err = request_irq(irq, ...); set_irq_type(irq, IRQT_RISING); However, if the interrupt has previously been programmed to be level sensitive (for whatever reason) then this will cause an interrupt storm. Hence, if we combine set_irq_type() with request_irq(), we can then safely set the type prior to unmasking the interrupt. The unfortunate problem is that in order to support this, these flags need to be visible outside of the ARM architecture - drivers such as smc91x need these flags and they're cross-architecture. Finally, the SA_TRIGGER_* flag passed to request_irq() should reflect the property that the device would like. The IRQ controller code should do its best to select the most appropriate supported mode. Signed-off-by: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/kernel/irq.c | 14 ++++++++++++-- arch/arm/mach-omap1/serial.c | 3 +-- arch/arm/mach-pxa/corgi.c | 7 +++---- arch/arm/mach-pxa/poodle.c | 7 +++---- arch/arm/mach-pxa/spitz.c | 7 +++---- arch/arm/mach-s3c2410/usb-simtec.c | 6 +++--- drivers/i2c/chips/tps65010.c | 11 ++++++----- drivers/input/keyboard/corgikbd.c | 6 ++---- drivers/input/keyboard/spitzkbd.c | 27 ++++++++++++++------------- drivers/mfd/ucb1x00-core.c | 5 ++--- drivers/net/smc91x.c | 5 +---- drivers/net/smc91x.h | 18 +++++++++--------- include/asm-arm/irq.h | 12 ++++++++---- include/linux/signal.h | 13 +++++++++++++ 14 files changed, 80 insertions(+), 61 deletions(-) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 869c466e6258..b5645c4462cf 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -684,8 +684,12 @@ int setup_irq(unsigned int irq, struct irqaction *new) spin_lock_irqsave(&irq_controller_lock, flags); p = &desc->action; if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) { + /* + * Can't share interrupts unless both agree to and are + * the same type. + */ + if (!(old->flags & new->flags & SA_SHIRQ) || + (~old->flags & new->flags) & SA_TRIGGER_MASK) { spin_unlock_irqrestore(&irq_controller_lock, flags); return -EBUSY; } @@ -705,6 +709,12 @@ int setup_irq(unsigned int irq, struct irqaction *new) desc->running = 0; desc->pending = 0; desc->disable_depth = 1; + + if (new->flags & SA_TRIGGER_MASK) { + unsigned int type = new->flags & SA_TRIGGER_MASK; + desc->chip->set_type(irq, type); + } + if (!desc->noautoenable) { desc->disable_depth = 0; desc->chip->unmask(irq); diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index fcfb81d13cfe..7a68f098a025 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -252,9 +252,8 @@ static void __init omap_serial_set_port_wakeup(int gpio_nr) return; } omap_set_gpio_direction(gpio_nr, 1); - set_irq_type(OMAP_GPIO_IRQ(gpio_nr), IRQT_RISING); ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt, - 0, "serial wakeup", NULL); + SA_TRIGGER_RISING, "serial wakeup", NULL); if (ret) { omap_free_gpio(gpio_nr); printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n", diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 100fb31b5156..5a7b873f29b3 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -213,15 +213,14 @@ static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(in corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250); - err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int, SA_INTERRUPT, - "MMC card detect", data); + err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "MMC card detect", data); if (err) { printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); return -1; } - set_irq_type(CORGI_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); - return 0; } diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index eef3de26ad37..663c95005985 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -146,15 +146,14 @@ static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)( poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250); - err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int, SA_INTERRUPT, - "MMC card detect", data); + err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "MMC card detect", data); if (err) { printk(KERN_ERR "poodle_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); return -1; } - set_irq_type(POODLE_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); - return 0; } diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index f2007db0cda5..a9eacc06555f 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -296,15 +296,14 @@ static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(in spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250); - err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, SA_INTERRUPT, - "MMC card detect", data); + err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "MMC card detect", data); if (err) { printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); return -1; } - set_irq_type(SPITZ_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); - return 0; } diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c index 5098b50158a3..495f8c6ffcb6 100644 --- a/arch/arm/mach-s3c2410/usb-simtec.c +++ b/arch/arm/mach-s3c2410/usb-simtec.c @@ -84,13 +84,13 @@ static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on) int ret; if (on) { - ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, SA_INTERRUPT, + ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, + SA_INTERRUPT | SA_TRIGGER_RISING | + SA_TRIGGER_FALLING, "USB Over-current", info); if (ret != 0) { printk(KERN_ERR "failed to request usb oc irq\n"); } - - set_irq_type(IRQ_USBOC, IRQT_BOTHEDGE); } else { free_irq(IRQ_USBOC, info); } diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index e70b3db69edd..1af3dfbb8086 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -494,6 +494,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) { struct tps65010 *tps; int status; + unsigned long irqflags; if (the_tps) { dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); @@ -520,13 +521,14 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) } #ifdef CONFIG_ARM + irqflags = SA_SAMPLE_RANDOM | SA_TRIGGER_LOW; if (machine_is_omap_h2()) { tps->model = TPS65010; omap_cfg_reg(W4_GPIO58); tps->irq = OMAP_GPIO_IRQ(58); omap_request_gpio(58); omap_set_gpio_direction(58, 1); - set_irq_type(tps->irq, IRQT_FALLING); + irqflags |= SA_TRIGGER_FALLING; } if (machine_is_omap_osk()) { tps->model = TPS65010; @@ -534,7 +536,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); omap_request_gpio(OMAP_MPUIO(1)); omap_set_gpio_direction(OMAP_MPUIO(1), 1); - set_irq_type(tps->irq, IRQT_FALLING); + irqflags |= SA_TRIGGER_FALLING; } if (machine_is_omap_h3()) { tps->model = TPS65013; @@ -542,13 +544,12 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) // FIXME set up this board's IRQ ... } #else -#define set_irq_type(num,trigger) do{}while(0) + irqflags = SA_SAMPLE_RANDOM; #endif if (tps->irq > 0) { - set_irq_type(tps->irq, IRQT_LOW); status = request_irq(tps->irq, tps65010_irq, - SA_SAMPLE_RANDOM, DRIVER_NAME, tps); + irqflags, DRIVER_NAME, tps); if (status < 0) { dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", tps->irq, status); diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 64672d491222..e301ee4ca264 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -343,10 +342,9 @@ static int __init corgikbd_probe(struct platform_device *pdev) for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) { pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN); if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt, - SA_INTERRUPT, "corgikbd", corgikbd)) + SA_INTERRUPT | SA_TRIGGER_RISING, + "corgikbd", corgikbd)) printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i); - else - set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING); } /* Set Strobe lines as outputs - set high */ diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 6a15fe3bc527..83999d583122 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -407,10 +406,9 @@ static int __init spitzkbd_probe(struct platform_device *dev) for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) { pxa_gpio_mode(spitz_senses[i] | GPIO_IN); if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt, - SA_INTERRUPT, "Spitzkbd Sense", spitzkbd)) + SA_INTERRUPT|SA_TRIGGER_RISING, + "Spitzkbd Sense", spitzkbd)) printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i); - else - set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING); } /* Set Strobe lines as outputs - set high */ @@ -422,15 +420,18 @@ static int __init spitzkbd_probe(struct platform_device *dev) pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN); pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN); - request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd); - request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd); - request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd); - request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd); - - set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE); - set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE); - set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE); - set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE); + request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd Sync", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd PwrOn", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd SWA", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd SWB", spitzkbd); printk(KERN_INFO "input: Spitz Keyboard Registered\n"); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index e335d54c4659..b42e0fbab59b 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -27,7 +27,6 @@ #include #include -#include #include "ucb1x00.h" @@ -507,14 +506,14 @@ static int ucb1x00_probe(struct mcp *mcp) goto err_free; } - ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb); + ret = request_irq(ucb->irq, ucb1x00_irq, SA_TRIGGER_RISING, + "UCB1x00", ucb); if (ret) { printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", ucb->irq, ret); goto err_free; } - set_irq_type(ucb->irq, IRQT_RISING); mcp_set_drvdata(mcp, ucb); ret = class_device_register(&ucb->cdev); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 28bf2e69eb5e..7ec08127c9d6 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -88,7 +88,6 @@ static const char version[] = #include #include -#include #include "smc91x.h" @@ -2007,12 +2006,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) } /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev); if (retval) goto err_out; - set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); - #ifdef SMC_USE_PXA_DMA { int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 5c2824be4ee6..e0efd1964e72 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -90,7 +90,7 @@ __l--; \ } \ } while (0) -#define set_irq_type(irq, type) +#define SMC_IRQ_FLAGS (0) #elif defined(CONFIG_SA1100_PLEB) /* We can only do 16-bit reads and writes in the static memory space. */ @@ -109,7 +109,7 @@ #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define set_irq_type(irq, type) do {} while (0) +#define SMC_IRQ_FLAGS (0) #elif defined(CONFIG_SA1100_ASSABET) @@ -185,11 +185,11 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #include #include -#define SMC_IRQ_TRIGGER_TYPE (( \ +#define SMC_IRQ_FLAGS (( \ machine_is_omap_h2() \ || machine_is_omap_h3() \ || (machine_is_omap_innovator() && !cpu_is_omap1510()) \ - ) ? IRQT_FALLING : IRQT_RISING) + ) ? SA_TRIGGER_FALLING : SA_TRIGGER_RISING) #elif defined(CONFIG_SH_SH4202_MICRODEV) @@ -209,7 +209,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) -#define set_irq_type(irq, type) do {} while(0) +#define SMC_IRQ_FLAGS (0) #elif defined(CONFIG_ISA) @@ -237,7 +237,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insw(a, r, p, l) insw(((u32)a) + (r), p, l) #define SMC_outsw(a, r, p, l) outsw(((u32)a) + (r), p, l) -#define set_irq_type(irq, type) do {} while(0) +#define SMC_IRQ_FLAGS (0) #define RPC_LSA_DEFAULT RPC_LED_TX_RX #define RPC_LSB_DEFAULT RPC_LED_100_10 @@ -319,7 +319,7 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) au_writew(*_p++ , _a); \ } while(0) -#define set_irq_type(irq, type) do {} while (0) +#define SMC_IRQ_FLAGS (0) #else @@ -342,8 +342,8 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) #endif -#ifndef SMC_IRQ_TRIGGER_TYPE -#define SMC_IRQ_TRIGGER_TYPE IRQT_RISING +#ifndef SMC_IRQ_FLAGS +#define SMC_IRQ_FLAGS SA_TRIGGER_RISING #endif #ifdef SMC_USE_PXA_DMA diff --git a/include/asm-arm/irq.h b/include/asm-arm/irq.h index 59975ee43cf1..7772432d3fd7 100644 --- a/include/asm-arm/irq.h +++ b/include/asm-arm/irq.h @@ -25,10 +25,14 @@ extern void disable_irq_nosync(unsigned int); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); -#define __IRQT_FALEDGE (1 << 0) -#define __IRQT_RISEDGE (1 << 1) -#define __IRQT_LOWLVL (1 << 2) -#define __IRQT_HIGHLVL (1 << 3) +/* + * These correspond with the SA_TRIGGER_* defines, and therefore the + * IRQRESOURCE_IRQ_* defines. + */ +#define __IRQT_RISEDGE (1 << 0) +#define __IRQT_FALEDGE (1 << 1) +#define __IRQT_HIGHLVL (1 << 2) +#define __IRQT_LOWLVL (1 << 3) #define IRQT_NOEDGE (0) #define IRQT_RISING (__IRQT_RISEDGE) diff --git a/include/linux/signal.h b/include/linux/signal.h index 5dd5f02c5c5f..ea9eff16c4b7 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -18,6 +18,19 @@ #define SA_PROBE SA_ONESHOT #define SA_SAMPLE_RANDOM SA_RESTART #define SA_SHIRQ 0x04000000 +/* + * As above, these correspond to the IORESOURCE_IRQ_* defines in + * linux/ioport.h to select the interrupt line behaviour. When + * requesting an interrupt without specifying a SA_TRIGGER, the + * setting should be assumed to be "as already configured", which + * may be as per machine or firmware initialisation. + */ +#define SA_TRIGGER_LOW 0x00000008 +#define SA_TRIGGER_HIGH 0x00000004 +#define SA_TRIGGER_FALLING 0x00000002 +#define SA_TRIGGER_RISING 0x00000001 +#define SA_TRIGGER_MASK (SA_TRIGGER_HIGH|SA_TRIGGER_LOW|\ + SA_TRIGGER_RISING|SA_TRIGGER_FALLING) /* * Real Time signals may be queued. -- cgit v1.2.3 From a6bf6b211cdb92c315c24719a522d8b6f3998210 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:08 -0800 Subject: [PATCH] fat: move fat_clusters_flush() to write_super() It is overkill to update the FS_INFO whenever modifying prev_free/free_clusters, because those are just a hint. So, this patch uses ->write_super() for updating FS_INFO instead. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/fatent.c | 8 ++++++-- fs/fat/inode.c | 10 ++++++++-- fs/fat/misc.c | 2 -- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 4164cd54c4d1..20a22875f0a1 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -476,6 +476,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) sbi->prev_free = entry; if (sbi->free_clusters != -1) sbi->free_clusters--; + sb->s_dirt = 1; cluster[idx_clus] = entry; idx_clus++; @@ -496,6 +497,7 @@ int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) /* Couldn't allocate the free entries */ sbi->free_clusters = 0; + sb->s_dirt = 1; err = -ENOSPC; out: @@ -509,7 +511,6 @@ out: } for (i = 0; i < nr_bhs; i++) brelse(bhs[i]); - fat_clusters_flush(sb); if (err && idx_clus) fat_free_clusters(inode, cluster[0]); @@ -542,8 +543,10 @@ int fat_free_clusters(struct inode *inode, int cluster) } ops->ent_put(&fatent, FAT_ENT_FREE); - if (sbi->free_clusters != -1) + if (sbi->free_clusters != -1) { sbi->free_clusters++; + sb->s_dirt = 1; + } if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) { if (sb->s_flags & MS_SYNCHRONOUS) { @@ -605,6 +608,7 @@ int fat_count_free_clusters(struct super_block *sb) } while (fat_ent_next(sbi, &fatent)); } sbi->free_clusters = free; + sb->s_dirt = 1; fatent_brelse(&fatent); out: unlock_fat(sbi); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a0f9b9fe1307..897312616b0a 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -374,12 +374,17 @@ static void fat_clear_inode(struct inode *inode) unlock_kernel(); } -static void fat_put_super(struct super_block *sb) +static void fat_write_super(struct super_block *sb) { - struct msdos_sb_info *sbi = MSDOS_SB(sb); + sb->s_dirt = 0; if (!(sb->s_flags & MS_RDONLY)) fat_clusters_flush(sb); +} + +static void fat_put_super(struct super_block *sb) +{ + struct msdos_sb_info *sbi = MSDOS_SB(sb); if (sbi->nls_disk) { unload_nls(sbi->nls_disk); @@ -546,6 +551,7 @@ static struct super_operations fat_sops = { .write_inode = fat_write_inode, .delete_inode = fat_delete_inode, .put_super = fat_put_super, + .write_super = fat_write_super, .statfs = fat_statfs, .clear_inode = fat_clear_inode, .remount_fs = fat_remount, diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 2a0df2122f5d..9b592e37e259 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -67,8 +67,6 @@ void fat_clusters_flush(struct super_block *sb) if (sbi->prev_free != -1) fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); mark_buffer_dirty(bh); - if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bh); } brelse(bh); } -- cgit v1.2.3 From 83b7c996dc859c7b53f94d46ee5c5929cc0399e2 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:09 -0800 Subject: [PATCH] fat: use sb_find_get_block() instead of sb_getblk() We don't need to allocate buffer for checking the buffer is uptodate. This use sb_find_get_block() instead, and if it returns NULL it's not uptodate. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/fat/dir.c b/fs/fat/dir.c index ba824964b9bb..b2a26cd226b5 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -45,8 +45,8 @@ static inline void fat_dir_readahead(struct inode *dir, sector_t iblock, if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO)) return; - bh = sb_getblk(sb, phys); - if (bh && !buffer_uptodate(bh)) { + bh = sb_find_get_block(sb, phys); + if (bh == NULL || !buffer_uptodate(bh)) { for (sec = 0; sec < sbi->sec_per_clus; sec++) sb_breadahead(sb, phys + sec); } -- cgit v1.2.3 From a5425d2927a6a771f9ae8767b6bfb3c09225bcdd Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:10 -0800 Subject: [PATCH] fat: add the read/writepages() Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/inode.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 897312616b0a..f502c6b8cb49 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -90,9 +91,21 @@ static int fat_writepage(struct page *page, struct writeback_control *wbc) return block_write_full_page(page, fat_get_block, wbc); } +static int fat_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + return mpage_writepages(mapping, wbc, fat_get_block); +} + static int fat_readpage(struct file *file, struct page *page) { - return block_read_full_page(page, fat_get_block); + return mpage_readpage(page, fat_get_block); +} + +static int fat_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + return mpage_readpages(mapping, pages, nr_pages, fat_get_block); } static int fat_prepare_write(struct file *file, struct page *page, @@ -122,7 +135,9 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) static struct address_space_operations fat_aops = { .readpage = fat_readpage, + .readpages = fat_readpages, .writepage = fat_writepage, + .writepages = fat_writepages, .sync_page = block_sync_page, .prepare_write = fat_prepare_write, .commit_write = fat_commit_write, -- cgit v1.2.3 From 7c709d00d614d0f2b6a80895b2a1aedbe04e8478 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:10 -0800 Subject: [PATCH] fat: s/EXPORT_SYMBOL/EXPORT_SYMBOL_GPL/ All EXPORT_SYMBOL of fatfs is only for vfat/msdos. _GPL would be proper. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/dir.c | 14 +++++++------- fs/fat/fatent.c | 2 +- fs/fat/file.c | 2 +- fs/fat/inode.c | 10 +++++----- fs/fat/misc.c | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/fat/dir.c b/fs/fat/dir.c index b2a26cd226b5..4ce77475aed3 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -418,7 +418,7 @@ EODir: return err; } -EXPORT_SYMBOL(fat_search_long); +EXPORT_SYMBOL_GPL(fat_search_long); struct fat_ioctl_filldir_callback { struct dirent __user *dirent; @@ -780,7 +780,7 @@ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, return -ENOENT; } -EXPORT_SYMBOL(fat_get_dotdot_entry); +EXPORT_SYMBOL_GPL(fat_get_dotdot_entry); /* See if directory is empty */ int fat_dir_empty(struct inode *dir) @@ -803,7 +803,7 @@ int fat_dir_empty(struct inode *dir) return result; } -EXPORT_SYMBOL(fat_dir_empty); +EXPORT_SYMBOL_GPL(fat_dir_empty); /* * fat_subdirs counts the number of sub-directories of dir. It can be run @@ -849,7 +849,7 @@ int fat_scan(struct inode *dir, const unsigned char *name, return -ENOENT; } -EXPORT_SYMBOL(fat_scan); +EXPORT_SYMBOL_GPL(fat_scan); static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) { @@ -936,7 +936,7 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) return 0; } -EXPORT_SYMBOL(fat_remove_entries); +EXPORT_SYMBOL_GPL(fat_remove_entries); static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, struct buffer_head **bhs, int nr_bhs) @@ -1048,7 +1048,7 @@ error: return err; } -EXPORT_SYMBOL(fat_alloc_new_dir); +EXPORT_SYMBOL_GPL(fat_alloc_new_dir); static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, int *nr_cluster, struct msdos_dir_entry **de, @@ -1264,4 +1264,4 @@ error_remove: return err; } -EXPORT_SYMBOL(fat_add_entries); +EXPORT_SYMBOL_GPL(fat_add_entries); diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 20a22875f0a1..a1a9e0451217 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -581,7 +581,7 @@ error: return err; } -EXPORT_SYMBOL(fat_free_clusters); +EXPORT_SYMBOL_GPL(fat_free_clusters); int fat_count_free_clusters(struct super_block *sb) { diff --git a/fs/fat/file.c b/fs/fat/file.c index 7134403d5be2..15229fe569c3 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -173,7 +173,7 @@ out: return error; } -EXPORT_SYMBOL(fat_notify_change); +EXPORT_SYMBOL_GPL(fat_notify_change); /* Free all clusters after the skip'th cluster. */ static int fat_free(struct inode *inode, int skip) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index f502c6b8cb49..932c8d6d1f54 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -197,7 +197,7 @@ void fat_attach(struct inode *inode, loff_t i_pos) spin_unlock(&sbi->inode_hash_lock); } -EXPORT_SYMBOL(fat_attach); +EXPORT_SYMBOL_GPL(fat_attach); void fat_detach(struct inode *inode) { @@ -208,7 +208,7 @@ void fat_detach(struct inode *inode) spin_unlock(&sbi->inode_hash_lock); } -EXPORT_SYMBOL(fat_detach); +EXPORT_SYMBOL_GPL(fat_detach); struct inode *fat_iget(struct super_block *sb, loff_t i_pos) { @@ -362,7 +362,7 @@ out: return inode; } -EXPORT_SYMBOL(fat_build_inode); +EXPORT_SYMBOL_GPL(fat_build_inode); static void fat_delete_inode(struct inode *inode) { @@ -557,7 +557,7 @@ int fat_sync_inode(struct inode *inode) return fat_write_inode(inode, 1); } -EXPORT_SYMBOL(fat_sync_inode); +EXPORT_SYMBOL_GPL(fat_sync_inode); static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); static struct super_operations fat_sops = { @@ -1368,7 +1368,7 @@ out_fail: return error; } -EXPORT_SYMBOL(fat_fill_super); +EXPORT_SYMBOL_GPL(fat_fill_super); int __init fat_cache_init(void); void fat_cache_destroy(void); diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 9b592e37e259..32fb0a3f1da4 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -33,7 +33,7 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...) } } -EXPORT_SYMBOL(fat_fs_panic); +EXPORT_SYMBOL_GPL(fat_fs_panic); /* Flushes the number of free clusters on FAT32 */ /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ @@ -192,7 +192,7 @@ void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date) *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); } -EXPORT_SYMBOL(fat_date_unix2dos); +EXPORT_SYMBOL_GPL(fat_date_unix2dos); int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) { @@ -220,4 +220,4 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) return err; } -EXPORT_SYMBOL(fat_sync_bhs); +EXPORT_SYMBOL_GPL(fat_sync_bhs); -- cgit v1.2.3 From e5174baaea7585760f02eef23b225847d209a8db Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:11 -0800 Subject: [PATCH] fat: support ->direct_IO() This patch add to support of ->direct_IO() for mostly read. The user of this seems to want to use for streaming read. So, current direct I/O has limitation, it can only overwrite. (For write operation, mainly we need to handle the hole etc..) Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/cache.c | 14 +++++++-- fs/fat/dir.c | 6 ++-- fs/fat/inode.c | 82 ++++++++++++++++++++++++++++++++++++++++++------ include/linux/msdos_fs.h | 3 +- 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 77c24fcf712a..1acc941245fb 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -295,7 +295,8 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) return dclus; } -int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) +int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, + unsigned long *mapped_blocks) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); @@ -303,9 +304,12 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) int cluster, offset; *phys = 0; + *mapped_blocks = 0; if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { - if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) + if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) { *phys = sector + sbi->dir_start; + *mapped_blocks = 1; + } return 0; } last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) @@ -318,7 +322,11 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) cluster = fat_bmap_cluster(inode, cluster); if (cluster < 0) return cluster; - else if (cluster) + else if (cluster) { *phys = fat_clus_to_blknr(sbi, cluster) + offset; + *mapped_blocks = sbi->sec_per_clus - offset; + if (*mapped_blocks > last_block - sector) + *mapped_blocks = last_block - sector; + } return 0; } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 4ce77475aed3..eef1b81aa294 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -68,8 +68,8 @@ static int fat__get_entry(struct inode *dir, loff_t *pos, { struct super_block *sb = dir->i_sb; sector_t phys, iblock; - int offset; - int err; + unsigned long mapped_blocks; + int err, offset; next: if (*bh) @@ -77,7 +77,7 @@ next: *bh = NULL; iblock = *pos >> sb->s_blocksize_bits; - err = fat_bmap(dir, iblock, &phys); + err = fat_bmap(dir, iblock, &phys, &mapped_blocks); if (err || !phys) return -1; /* beyond EOF or error */ diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 932c8d6d1f54..e7f4aa7fc686 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #ifndef CONFIG_FAT_DEFAULT_IOCHARSET @@ -49,43 +50,77 @@ static int fat_add_cluster(struct inode *inode) return err; } -static int fat_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) +static int __fat_get_blocks(struct inode *inode, sector_t iblock, + unsigned long *max_blocks, + struct buffer_head *bh_result, int create) { struct super_block *sb = inode->i_sb; + struct msdos_sb_info *sbi = MSDOS_SB(sb); sector_t phys; - int err; + unsigned long mapped_blocks; + int err, offset; - err = fat_bmap(inode, iblock, &phys); + err = fat_bmap(inode, iblock, &phys, &mapped_blocks); if (err) return err; if (phys) { map_bh(bh_result, sb, phys); + *max_blocks = min(mapped_blocks, *max_blocks); return 0; } if (!create) return 0; + if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); return -EIO; } - if (!((unsigned long)iblock & (MSDOS_SB(sb)->sec_per_clus - 1))) { + + offset = (unsigned long)iblock & (sbi->sec_per_clus - 1); + if (!offset) { + /* TODO: multiple cluster allocation would be desirable. */ err = fat_add_cluster(inode); if (err) return err; } - MSDOS_I(inode)->mmu_private += sb->s_blocksize; - err = fat_bmap(inode, iblock, &phys); + /* available blocks on this cluster */ + mapped_blocks = sbi->sec_per_clus - offset; + + *max_blocks = min(mapped_blocks, *max_blocks); + MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; + + err = fat_bmap(inode, iblock, &phys, &mapped_blocks); if (err) return err; - if (!phys) - BUG(); + BUG_ON(!phys); + BUG_ON(*max_blocks != mapped_blocks); set_buffer_new(bh_result); map_bh(bh_result, sb, phys); return 0; } +static int fat_get_blocks(struct inode *inode, sector_t iblock, + unsigned long max_blocks, + struct buffer_head *bh_result, int create) +{ + struct super_block *sb = inode->i_sb; + int err; + + err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create); + if (err) + return err; + bh_result->b_size = max_blocks << sb->s_blocksize_bits; + return 0; +} + +static int fat_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + unsigned long max_blocks = 1; + return __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create); +} + static int fat_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, fat_get_block, wbc); @@ -128,6 +163,34 @@ static int fat_commit_write(struct file *file, struct page *page, return err; } +static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + + if (rw == WRITE) { + /* + * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(), + * so we need to update the ->mmu_private to block boundary. + * + * But we must fill the remaining area or hole by nul for + * updating ->mmu_private. + */ + loff_t size = offset + iov_length(iov, nr_segs); + if (MSDOS_I(inode)->mmu_private < size) + return -EINVAL; + } + + /* + * FAT need to use the DIO_LOCKING for avoiding the race + * condition of fat_get_block() and ->truncate(). + */ + return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, fat_get_blocks, NULL); +} + static sector_t _fat_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping, block, fat_get_block); @@ -141,6 +204,7 @@ static struct address_space_operations fat_aops = { .sync_page = block_sync_page, .prepare_write = fat_prepare_write, .commit_write = fat_commit_write, + .direct_IO = fat_direct_IO, .bmap = _fat_bmap }; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 941da5c016a0..e933e2a355ad 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -329,7 +329,8 @@ static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len) extern void fat_cache_inval_inode(struct inode *inode); extern int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus); -extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys); +extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, + unsigned long *mapped_blocks); /* fat/dir.c */ extern struct file_operations fat_dir_operations; -- cgit v1.2.3 From 268fc16e343b4f8e249468747db2e658da46a814 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:12 -0800 Subject: [PATCH] export/change sync_page_range/_nolock() This exports/changes the sync_page_range/_nolock(). The fatfs needs sync_page_range/_nolock() for expanding truncate, and changes "size_t count" to "loff_t count". Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/writeback.h | 4 +++- mm/filemap.c | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/writeback.h b/include/linux/writeback.h index b096159086e8..beaef5c7a0ea 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -103,7 +103,9 @@ void balance_dirty_pages_ratelimited(struct address_space *mapping); int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); int do_writepages(struct address_space *mapping, struct writeback_control *wbc); int sync_page_range(struct inode *inode, struct address_space *mapping, - loff_t pos, size_t count); + loff_t pos, loff_t count); +int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, + loff_t pos, loff_t count); /* pdflush.c */ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl diff --git a/mm/filemap.c b/mm/filemap.c index 4ef24a397684..8fdf36508023 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -280,7 +280,7 @@ static int wait_on_page_writeback_range(struct address_space *mapping, * it is otherwise livelockable. */ int sync_page_range(struct inode *inode, struct address_space *mapping, - loff_t pos, size_t count) + loff_t pos, loff_t count) { pgoff_t start = pos >> PAGE_CACHE_SHIFT; pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT; @@ -305,9 +305,8 @@ EXPORT_SYMBOL(sync_page_range); * as it forces O_SYNC writers to different parts of the same file * to be serialised right until io completion. */ -static int sync_page_range_nolock(struct inode *inode, - struct address_space *mapping, - loff_t pos, size_t count) +int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, + loff_t pos, loff_t count) { pgoff_t start = pos >> PAGE_CACHE_SHIFT; pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT; @@ -322,6 +321,7 @@ static int sync_page_range_nolock(struct inode *inode, ret = wait_on_page_writeback_range(mapping, start, end); return ret; } +EXPORT_SYMBOL(sync_page_range_nolock); /** * filemap_fdatawait - walk the list of under-writeback pages of the given -- cgit v1.2.3 From 05eb0b51fb46430050d5873458612f53e0234f2e Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:13 -0800 Subject: [PATCH] fat: support a truncate() for expanding size (generic_cont_expand) This patch changes generic_cont_expand(), in order to share the code with fatfs. - Use vmtruncate() if ->prepare_write() returns a error. Even if ->prepare_write() returns an error, it may already have added some blocks. So, this truncates blocks outside of ->i_size by vmtruncate(). - Add generic_cont_expand_simple(). The generic_cont_expand_simple() assumes that ->prepare_write() can handle the block boundary. With this, we don't need to care the extra byte. And for expanding a file size by truncate(), fatfs uses the added generic_cont_expand_simple(). Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/buffer.c | 60 ++++++++++++++++++++++++++++++++++----------- fs/fat/file.c | 31 ++++++++++++++++++++--- include/linux/buffer_head.h | 3 ++- 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 5287be18633b..55023231e460 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2160,11 +2160,12 @@ int block_read_full_page(struct page *page, get_block_t *get_block) * truncates. Uses prepare/commit_write to allow the filesystem to * deal with the hole. */ -int generic_cont_expand(struct inode *inode, loff_t size) +static int __generic_cont_expand(struct inode *inode, loff_t size, + pgoff_t index, unsigned int offset) { struct address_space *mapping = inode->i_mapping; struct page *page; - unsigned long index, offset, limit; + unsigned long limit; int err; err = -EFBIG; @@ -2176,24 +2177,24 @@ int generic_cont_expand(struct inode *inode, loff_t size) if (size > inode->i_sb->s_maxbytes) goto out; - offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */ - - /* ugh. in prepare/commit_write, if from==to==start of block, we - ** skip the prepare. make sure we never send an offset for the start - ** of a block - */ - if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) { - offset++; - } - index = size >> PAGE_CACHE_SHIFT; err = -ENOMEM; page = grab_cache_page(mapping, index); if (!page) goto out; err = mapping->a_ops->prepare_write(NULL, page, offset, offset); - if (!err) { - err = mapping->a_ops->commit_write(NULL, page, offset, offset); + if (err) { + /* + * ->prepare_write() may have instantiated a few blocks + * outside i_size. Trim these off again. + */ + unlock_page(page); + page_cache_release(page); + vmtruncate(inode, inode->i_size); + goto out; } + + err = mapping->a_ops->commit_write(NULL, page, offset, offset); + unlock_page(page); page_cache_release(page); if (err > 0) @@ -2202,6 +2203,36 @@ out: return err; } +int generic_cont_expand(struct inode *inode, loff_t size) +{ + pgoff_t index; + unsigned int offset; + + offset = (size & (PAGE_CACHE_SIZE - 1)); /* Within page */ + + /* ugh. in prepare/commit_write, if from==to==start of block, we + ** skip the prepare. make sure we never send an offset for the start + ** of a block + */ + if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) { + /* caller must handle this extra byte. */ + offset++; + } + index = size >> PAGE_CACHE_SHIFT; + + return __generic_cont_expand(inode, size, index, offset); +} + +int generic_cont_expand_simple(struct inode *inode, loff_t size) +{ + loff_t pos = size - 1; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + unsigned int offset = (pos & (PAGE_CACHE_SIZE - 1)) + 1; + + /* prepare/commit_write can handle even if from==to==start of block. */ + return __generic_cont_expand(inode, size, index, offset); +} + /* * For moronic filesystems that do not allow holes in file. * We may have to extend the file. @@ -3145,6 +3176,7 @@ EXPORT_SYMBOL(fsync_bdev); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_commit_write); EXPORT_SYMBOL(generic_cont_expand); +EXPORT_SYMBOL(generic_cont_expand_simple); EXPORT_SYMBOL(init_buffer); EXPORT_SYMBOL(invalidate_bdev); EXPORT_SYMBOL(ll_rw_block); diff --git a/fs/fat/file.c b/fs/fat/file.c index 15229fe569c3..9b07c328a6fc 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -11,6 +11,7 @@ #include #include #include +#include int fat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -124,6 +125,24 @@ struct file_operations fat_file_operations = { .sendfile = generic_file_sendfile, }; +static int fat_cont_expand(struct inode *inode, loff_t size) +{ + struct address_space *mapping = inode->i_mapping; + loff_t start = inode->i_size, count = size - inode->i_size; + int err; + + err = generic_cont_expand_simple(inode, size); + if (err) + goto out; + + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + if (IS_SYNC(inode)) + err = sync_page_range_nolock(inode, mapping, start, count); +out: + return err; +} + int fat_notify_change(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); @@ -132,11 +151,17 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr) lock_kernel(); - /* FAT cannot truncate to a longer file */ + /* + * Expand the file. Since inode_setattr() updates ->i_size + * before calling the ->truncate(), but FAT needs to fill the + * hole before it. + */ if (attr->ia_valid & ATTR_SIZE) { if (attr->ia_size > inode->i_size) { - error = -EPERM; - goto out; + error = fat_cont_expand(inode, attr->ia_size); + if (error || attr->ia_valid == ATTR_SIZE) + goto out; + attr->ia_valid &= ~ATTR_SIZE; } } diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 1db061bb6b08..9f159baf153f 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -197,7 +197,8 @@ int block_read_full_page(struct page*, get_block_t*); int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*); int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*, loff_t *); -int generic_cont_expand(struct inode *inode, loff_t size) ; +int generic_cont_expand(struct inode *inode, loff_t size); +int generic_cont_expand_simple(struct inode *inode, loff_t size); int block_commit_write(struct page *page, unsigned from, unsigned to); int block_sync_page(struct page *); sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); -- cgit v1.2.3 From 28fd129827b00e12829d48a5290f46277600619b Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 8 Jan 2006 01:02:14 -0800 Subject: [PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait) This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it. See mm/filemap.c: And changes the filemap_write_and_wait() and filemap_write_and_wait_range(). Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite() returns error. However, even if filemap_fdatawrite() returned an error, it may have submitted the partially data pages to the device. (e.g. in the case of -ENOSPC) Andrew Morton writes, If filemap_fdatawrite() returns an error, this might be due to some I/O problem: dead disk, unplugged cable, etc. Given the generally crappy quality of the kernel's handling of such exceptions, there's a good chance that the filemap_fdatawait() will get stuck in D state forever. So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO. Trond, could you please review the nfs part? Especially I'm not sure, nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not. Acked-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/vfs_dir.c | 3 +-- fs/9p/vfs_file.c | 3 +-- fs/buffer.c | 10 ++-------- fs/cifs/file.c | 6 ++---- fs/cifs/inode.c | 3 +-- fs/jfs/jfs_dmap.c | 3 +-- fs/jfs/jfs_imap.c | 6 ++---- fs/jfs/jfs_txnmgr.c | 6 ++---- fs/jfs/jfs_umount.c | 6 ++---- fs/jfs/resize.c | 3 +-- fs/jfs/super.c | 3 +-- fs/nfs/inode.c | 8 ++------ fs/smbfs/file.c | 3 +-- fs/smbfs/inode.c | 3 +-- fs/xfs/linux-2.6/xfs_fs_subr.c | 3 +-- mm/filemap.c | 40 +++++++++++++++++++++++++++------------- 16 files changed, 48 insertions(+), 61 deletions(-) diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 57a43b8feef5..17089d1905ff 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -193,8 +193,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) fid->fid); fidnum = fid->fid; - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); if (fidnum >= 0) { dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 89c849da8504..e13577da9130 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -165,8 +165,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) return -ENOLCK; if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); invalidate_inode_pages(&inode->i_data); } diff --git a/fs/buffer.c b/fs/buffer.c index 55023231e460..263df0f192aa 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -153,14 +153,8 @@ int sync_blockdev(struct block_device *bdev) { int ret = 0; - if (bdev) { - int err; - - ret = filemap_fdatawrite(bdev->bd_inode->i_mapping); - err = filemap_fdatawait(bdev->bd_inode->i_mapping); - if (!ret) - ret = err; - } + if (bdev) + ret = filemap_write_and_wait(bdev->bd_inode->i_mapping); return ret; } EXPORT_SYMBOL(sync_blockdev); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 14a1c72ced92..5ade53d7bca8 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -127,8 +127,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, if (file->f_dentry->d_inode->i_mapping) { /* BB no need to lock inode until after invalidate since namei code should already have it locked? */ - filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); - filemap_fdatawait(file->f_dentry->d_inode->i_mapping); + filemap_write_and_wait(file->f_dentry->d_inode->i_mapping); } cFYI(1, ("invalidating remote inode since open detected it " "changed")); @@ -419,8 +418,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, pCifsInode = CIFS_I(inode); if (pCifsInode) { if (can_flush) { - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); /* temporarily disable caching while we go to server to get inode info */ pCifsInode->clientCanCacheAll = FALSE; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 411c1f7f84da..9558f51bca55 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1148,8 +1148,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) /* BB check if we need to refresh inode from server now ? BB */ /* need to flush data before changing file size on server */ - filemap_fdatawrite(direntry->d_inode->i_mapping); - filemap_fdatawait(direntry->d_inode->i_mapping); + filemap_write_and_wait(direntry->d_inode->i_mapping); if (attrs->ia_valid & ATTR_SIZE) { /* To avoid spurious oplock breaks from server, in the case of diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 68000a50ceb6..2967b7393415 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -302,8 +302,7 @@ int dbSync(struct inode *ipbmap) /* * write out dirty pages of bmap */ - filemap_fdatawrite(ipbmap->i_mapping); - filemap_fdatawait(ipbmap->i_mapping); + filemap_write_and_wait(ipbmap->i_mapping); diWriteSpecial(ipbmap, 0); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 28201b194f53..31b4aa13dd4b 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -265,8 +265,7 @@ int diSync(struct inode *ipimap) /* * write out dirty pages of imap */ - filemap_fdatawrite(ipimap->i_mapping); - filemap_fdatawait(ipimap->i_mapping); + filemap_write_and_wait(ipimap->i_mapping); diWriteSpecial(ipimap, 0); @@ -565,8 +564,7 @@ void diFreeSpecial(struct inode *ip) jfs_err("diFreeSpecial called with NULL ip!"); return; } - filemap_fdatawrite(ip->i_mapping); - filemap_fdatawait(ip->i_mapping); + filemap_write_and_wait(ip->i_mapping); truncate_inode_pages(ip->i_mapping, 0); iput(ip); } diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index b660c93c92de..2ddb6b892bcf 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1231,10 +1231,8 @@ int txCommit(tid_t tid, /* transaction identifier */ * when we don't need to worry about it at all. * * if ((!S_ISDIR(ip->i_mode)) - * && (tblk->flag & COMMIT_DELETE) == 0) { - * filemap_fdatawrite(ip->i_mapping); - * filemap_fdatawait(ip->i_mapping); - * } + * && (tblk->flag & COMMIT_DELETE) == 0) + * filemap_write_and_wait(ip->i_mapping); */ /* diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c index 5cf91785b541..21eaf7ac0fcb 100644 --- a/fs/jfs/jfs_umount.c +++ b/fs/jfs/jfs_umount.c @@ -108,8 +108,7 @@ int jfs_umount(struct super_block *sb) * Make sure all metadata makes it to disk before we mark * the superblock as clean */ - filemap_fdatawrite(sbi->direct_inode->i_mapping); - filemap_fdatawait(sbi->direct_inode->i_mapping); + filemap_write_and_wait(sbi->direct_inode->i_mapping); /* * ensure all file system file pages are propagated to their @@ -161,8 +160,7 @@ int jfs_umount_rw(struct super_block *sb) * mark the superblock clean before everything is flushed to * disk. */ - filemap_fdatawrite(sbi->direct_inode->i_mapping); - filemap_fdatawait(sbi->direct_inode->i_mapping); + filemap_write_and_wait(sbi->direct_inode->i_mapping); updateSuper(sb, FM_CLEAN); diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c index c6dc254d3253..45180361871c 100644 --- a/fs/jfs/resize.c +++ b/fs/jfs/resize.c @@ -376,8 +376,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) * by txCommit(); */ filemap_fdatawait(ipbmap->i_mapping); - filemap_fdatawrite(ipbmap->i_mapping); - filemap_fdatawait(ipbmap->i_mapping); + filemap_write_and_wait(ipbmap->i_mapping); diWriteSpecial(ipbmap, 0); newPage = nPages; /* first new page number */ diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 4226af3ea91b..8d31f1336431 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -502,8 +502,7 @@ out_no_rw: jfs_err("jfs_umount failed with return code %d", rc); } out_mount_failed: - filemap_fdatawrite(sbi->direct_inode->i_mapping); - filemap_fdatawait(sbi->direct_inode->i_mapping); + filemap_write_and_wait(sbi->direct_inode->i_mapping); truncate_inode_pages(sbi->direct_inode->i_mapping, 0); make_bad_inode(sbi->direct_inode); iput(sbi->direct_inode); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e7bd0d92600f..3e4ba9cb7f80 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -644,10 +644,7 @@ int nfs_sync_mapping(struct address_space *mapping) if (mapping->nrpages == 0) return 0; unmap_mapping_range(mapping, 0, 0, 0); - ret = filemap_fdatawrite(mapping); - if (ret != 0) - goto out; - ret = filemap_fdatawait(mapping); + ret = filemap_write_and_wait(mapping); if (ret != 0) goto out; ret = nfs_wb_all(mapping->host); @@ -864,8 +861,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) nfs_begin_data_update(inode); /* Write all dirty data if we're changing file permissions or size */ if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) { - if (filemap_fdatawrite(inode->i_mapping) == 0) - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); nfs_wb_all(inode); } /* diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index b4fcfa8b55a1..3c6eb3ba718e 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -374,8 +374,7 @@ smb_file_release(struct inode *inode, struct file * file) /* We must flush any dirty pages now as we won't be able to write anything after close. mmap can trigger this. "openers" should perhaps include mmap'ers ... */ - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); smb_close(inode); } unlock_kernel(); diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 10b994428fef..6ec88bf59b2d 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -697,8 +697,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr) DENTRY_PATH(dentry), (long) inode->i_size, (long) attr->ia_size); - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); error = smb_open(dentry, O_WRONLY); if (error) diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index f89340c61bf2..4fa4b1a5187e 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c @@ -79,8 +79,7 @@ fs_flushinval_pages( struct inode *ip = LINVFS_GET_IP(vp); if (VN_CACHED(vp)) { - filemap_fdatawrite(ip->i_mapping); - filemap_fdatawait(ip->i_mapping); + filemap_write_and_wait(ip->i_mapping); truncate_inode_pages(ip->i_mapping, first); } diff --git a/mm/filemap.c b/mm/filemap.c index 8fdf36508023..478f4c74cc31 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -343,30 +343,44 @@ EXPORT_SYMBOL(filemap_fdatawait); int filemap_write_and_wait(struct address_space *mapping) { - int retval = 0; + int err = 0; if (mapping->nrpages) { - retval = filemap_fdatawrite(mapping); - if (retval == 0) - retval = filemap_fdatawait(mapping); + err = filemap_fdatawrite(mapping); + /* + * Even if the above returned error, the pages may be + * written partially (e.g. -ENOSPC), so we wait for it. + * But the -EIO is special case, it may indicate the worst + * thing (e.g. bug) happened, so we avoid waiting for it. + */ + if (err != -EIO) { + int err2 = filemap_fdatawait(mapping); + if (!err) + err = err2; + } } - return retval; + return err; } +EXPORT_SYMBOL(filemap_write_and_wait); int filemap_write_and_wait_range(struct address_space *mapping, loff_t lstart, loff_t lend) { - int retval = 0; + int err = 0; if (mapping->nrpages) { - retval = __filemap_fdatawrite_range(mapping, lstart, lend, - WB_SYNC_ALL); - if (retval == 0) - retval = wait_on_page_writeback_range(mapping, - lstart >> PAGE_CACHE_SHIFT, - lend >> PAGE_CACHE_SHIFT); + err = __filemap_fdatawrite_range(mapping, lstart, lend, + WB_SYNC_ALL); + /* See comment of filemap_write_and_wait() */ + if (err != -EIO) { + int err2 = wait_on_page_writeback_range(mapping, + lstart >> PAGE_CACHE_SHIFT, + lend >> PAGE_CACHE_SHIFT); + if (!err) + err = err2; + } } - return retval; + return err; } /* -- cgit v1.2.3 From 2a10e0b28b196051ae71829e5b989cba00513289 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:02:15 -0800 Subject: [PATCH] move rtc_interrupt() prototype to rtc.h This patch moves the rtc_interrupt() prototype to rtc.h and removes the prototypes from C files. It also renames static rtc_interrupt() functions in arch/arm/mach-integrator/time.c and arch/sh64/kernel/time.c to avoid compile problems. Signed-off-by: Adrian Bunk Signed-off-by: Paul Gortmaker Acked-by: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/mach-integrator/time.c | 5 +++-- arch/i386/kernel/time_hpet.c | 2 -- arch/sh64/kernel/time.c | 7 ++++--- arch/x86_64/kernel/time.c | 2 -- include/linux/rtc.h | 3 +++ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index 9f46aaef8968..3c22c16b38bf 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c @@ -96,7 +96,8 @@ static struct rtc_ops rtc_ops = { .set_alarm = rtc_set_alarm, }; -static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { writel(0, rtc_base + RTC_EOI); return IRQ_HANDLED; @@ -124,7 +125,7 @@ static int rtc_probe(struct amba_device *dev, void *id) xtime.tv_sec = __raw_readl(rtc_base + RTC_DR); - ret = request_irq(dev->irq[0], rtc_interrupt, SA_INTERRUPT, + ret = request_irq(dev->irq[0], arm_rtc_interrupt, SA_INTERRUPT, "rtc-pl030", dev); if (ret) goto map_out; diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 9caeaa315cd7..a529f0cdce17 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -259,8 +259,6 @@ __setup("hpet=", hpet_setup); #include #include -extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); - #define DEFAULT_RTC_INT_FREQ 64 #define RTC_NUM_INTS 1 diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index 870fe5327e09..1195af37ee5a 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -417,7 +417,7 @@ static __init unsigned int get_cpu_hz(void) /* ** Regardless the toolchain, force the compiler to use the ** arbitrary register r3 as a clock tick counter. - ** NOTE: r3 must be in accordance with rtc_interrupt() + ** NOTE: r3 must be in accordance with sh64_rtc_interrupt() */ register unsigned long long __rtc_irq_flag __asm__ ("r3"); @@ -482,7 +482,8 @@ static __init unsigned int get_cpu_hz(void) #endif } -static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { ctrl_outb(0, RCR1); /* Disable Carry Interrupts */ regs->regs[3] = 1; /* Using r3 */ @@ -491,7 +492,7 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) } static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL}; -static struct irqaction irq1 = { rtc_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "rtc", NULL, NULL}; +static struct irqaction irq1 = { sh64_rtc_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "rtc", NULL, NULL}; void __init time_init(void) { diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 74102796e5c0..43c9fa0f8d5f 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -1075,8 +1075,6 @@ device_initcall(time_init_device); */ #include -extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); - #define DEFAULT_RTC_INT_FREQ 64 #define RTC_NUM_INTS 1 diff --git a/include/linux/rtc.h b/include/linux/rtc.h index e1aaf1fac8e0..0b2ba67ff13c 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -11,6 +11,8 @@ #ifndef _LINUX_RTC_H_ #define _LINUX_RTC_H_ +#include + /* * The struct used to pass data via the following ioctl. Similar to the * struct tm in , but it needs to be here so that the kernel @@ -102,6 +104,7 @@ int rtc_register(rtc_task_t *task); int rtc_unregister(rtc_task_t *task); int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); void rtc_get_rtc_time(struct rtc_time *rtc_tm); +irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs); #endif /* __KERNEL__ */ -- cgit v1.2.3 From b7b4d7a4666454b40b45a853bd1d296af37a85f0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:02:16 -0800 Subject: [PATCH] drivers/isdn/: "extern inline" -> "static inline" "extern inline" -> "static inline" Since there's no pullphone() function this patch removes the dead prototype. Signed-off-by: Adrian Bunk Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/act2000/act2000.h | 6 +++--- drivers/isdn/act2000/capi.h | 2 +- drivers/isdn/sc/command.c | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h index b091d1a54125..d4c50512a1ff 100644 --- a/drivers/isdn/act2000/act2000.h +++ b/drivers/isdn/act2000/act2000.h @@ -181,17 +181,17 @@ typedef struct act2000_card { char regname[35]; /* Name used for request_region */ } act2000_card; -extern __inline__ void act2000_schedule_tx(act2000_card *card) +static inline void act2000_schedule_tx(act2000_card *card) { schedule_work(&card->snd_tq); } -extern __inline__ void act2000_schedule_rx(act2000_card *card) +static inline void act2000_schedule_rx(act2000_card *card) { schedule_work(&card->rcv_tq); } -extern __inline__ void act2000_schedule_poll(act2000_card *card) +static inline void act2000_schedule_poll(act2000_card *card) { schedule_work(&card->poll_tq); } diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index f6d5f530b86b..e82a9289ad96 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -330,7 +330,7 @@ typedef struct actcapi_msg { } msg; } actcapi_msg; -extern __inline__ unsigned short +static inline unsigned short actcapi_nextsmsg(act2000_card *card) { unsigned long flags; diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c index 19f2fcf0ae4a..b4b24335f716 100644 --- a/drivers/isdn/sc/command.c +++ b/drivers/isdn/sc/command.c @@ -43,7 +43,6 @@ extern int send_and_receive(int, unsigned int, unsigned char, unsigned char, RspMessage *, int); extern int sendmessage(int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); -extern inline void pullphone(char *, char *); #ifdef DEBUG /* -- cgit v1.2.3 From 97a41e26124330e41aa10ef88cd1711bc3d17460 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:02:17 -0800 Subject: [PATCH] kernel/: small cleanups This patch contains the following cleanups: - make needlessly global functions static - every file should include the headers containing the prototypes for it's global functions Signed-off-by: Adrian Bunk Acked-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/audit.c | 2 +- kernel/irq/proc.c | 2 ++ kernel/rcutorture.c | 2 +- kernel/timer.c | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/audit.c b/kernel/audit.c index 32fa03ad1984..d13ab7d2d899 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -267,7 +267,7 @@ static int audit_set_failure(int state, uid_t loginuid) return old; } -int kauditd_thread(void *dummy) +static int kauditd_thread(void *dummy) { struct sk_buff *skb; diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 8a64a4844cde..d03b5eef8ce0 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -10,6 +10,8 @@ #include #include +#include "internals.h" + static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS]; #ifdef CONFIG_SMP diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 49fbbeff201c..36efe088ad81 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -103,7 +103,7 @@ atomic_t n_rcu_torture_error; /* * Allocate an element from the rcu_tortures pool. */ -struct rcu_torture * +static struct rcu_torture * rcu_torture_alloc(void) { struct list_head *p; diff --git a/kernel/timer.c b/kernel/timer.c index fd74268d8663..074b4bd5cfd8 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 8382bf2e72d16d0532e351299121ccd3bca0fdd8 Mon Sep 17 00:00:00 2001 From: Peter Osterlund Date: Sun, 8 Jan 2006 01:02:17 -0800 Subject: [PATCH] pktcdvd: Use bd_claim to get exclusive access Use bd_claim() when opening the cdrom device to prevent user space programs such as cdrecord, hald and kded from interfering with the burning process. Signed-off-by: Peter Osterlund Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index c0233efabeba..51b7a5c5b77a 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1955,9 +1955,12 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY))) goto out; + if ((ret = bd_claim(pd->bdev, pd))) + goto out_putdev; + if ((ret = pkt_get_last_written(pd, &lba))) { printk("pktcdvd: pkt_get_last_written failed\n"); - goto out_putdev; + goto out_unclaim; } set_capacity(pd->disk, lba << 2); @@ -1967,7 +1970,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) q = bdev_get_queue(pd->bdev); if (write) { if ((ret = pkt_open_write(pd))) - goto out_putdev; + goto out_unclaim; /* * Some CDRW drives can not handle writes larger than one packet, * even if the size is a multiple of the packet size. @@ -1982,13 +1985,15 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) } if ((ret = pkt_set_segment_merging(pd, q))) - goto out_putdev; + goto out_unclaim; if (write) printk("pktcdvd: %lukB available on disc\n", lba << 1); return 0; +out_unclaim: + bd_release(pd->bdev); out_putdev: blkdev_put(pd->bdev); out: @@ -2007,6 +2012,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush) pkt_lock_door(pd, 0); pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); + bd_release(pd->bdev); blkdev_put(pd->bdev); } -- cgit v1.2.3 From a57004e1afb6ee03c509f1b1ec74a000682ab93b Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:02:19 -0800 Subject: [PATCH] atomic: dec_and_lock use atomic primitives Convert atomic_dec_and_lock to use new atomic primitives. Signed-off-by: Nick Piggin Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/dec_and_lock.c | 49 ++++++------------------------------------------- 1 file changed, 6 insertions(+), 43 deletions(-) diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index 305a9663aee3..a65c31455541 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -1,47 +1,11 @@ #include #include #include -#include -#ifdef __HAVE_ARCH_CMPXCHG /* * This is an implementation of the notion of "decrement a * reference count, and return locked if it decremented to zero". * - * This implementation can be used on any architecture that - * has a cmpxchg, and where atomic->value is an int holding - * the value of the atomic (i.e. the high bits aren't used - * for a lock or anything like that). - */ -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - - for (;;) { - counter = atomic_read(atomic); - newcount = counter - 1; - if (!newcount) - break; /* do it the slow way */ - - newcount = cmpxchg(&atomic->counter, counter, newcount); - if (newcount == counter) - return 0; - } - - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} -#else -/* - * This is an architecture-neutral, but slow, - * implementation of the notion of "decrement - * a reference count, and return locked if it - * decremented to zero". - * * NOTE NOTE NOTE! This is _not_ equivalent to * * if (atomic_dec_and_test(&atomic)) { @@ -52,21 +16,20 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) * * because the spin-lock and the decrement must be * "atomic". - * - * This slow version gets the spinlock unconditionally, - * and releases it if it isn't needed. Architectures - * are encouraged to come up with better approaches, - * this is trivially done efficiently using a load-locked - * store-conditional approach, for example. */ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { +#ifdef CONFIG_SMP + /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ + if (atomic_add_unless(atomic, -1, 1)) + return 0; +#endif + /* Otherwise do it the slow way */ spin_lock(lock); if (atomic_dec_and_test(atomic)) return 1; spin_unlock(lock); return 0; } -#endif EXPORT_SYMBOL(_atomic_dec_and_lock); -- cgit v1.2.3 From 095975da26dba21698582e91e96be10f7417333f Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Sun, 8 Jan 2006 01:02:19 -0800 Subject: [PATCH] rcu file: use atomic primitives Use atomic_inc_not_zero for rcu files instead of special case rcuref. Signed-off-by: Nick Piggin Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/rcuref.txt | 87 ++++++++--------- fs/aio.c | 3 +- fs/file_table.c | 8 +- include/linux/fs.h | 3 +- include/linux/radix-tree.h | 1 + include/linux/rcuref.h | 220 ------------------------------------------- kernel/rcupdate.c | 14 --- kernel/rcutorture.c | 1 - security/selinux/hooks.c | 2 +- 9 files changed, 48 insertions(+), 291 deletions(-) delete mode 100644 include/linux/rcuref.h diff --git a/Documentation/RCU/rcuref.txt b/Documentation/RCU/rcuref.txt index a23fee66064d..3f60db41b2f0 100644 --- a/Documentation/RCU/rcuref.txt +++ b/Documentation/RCU/rcuref.txt @@ -1,74 +1,67 @@ -Refcounter framework for elements of lists/arrays protected by -RCU. +Refcounter design for elements of lists/arrays protected by RCU. Refcounting on elements of lists which are protected by traditional reader/writer spinlocks or semaphores are straight forward as in: -1. 2. -add() search_and_reference() -{ { - alloc_object read_lock(&list_lock); - ... search_for_element - atomic_set(&el->rc, 1); atomic_inc(&el->rc); - write_lock(&list_lock); ... - add_element read_unlock(&list_lock); - ... ... - write_unlock(&list_lock); } +1. 2. +add() search_and_reference() +{ { + alloc_object read_lock(&list_lock); + ... search_for_element + atomic_set(&el->rc, 1); atomic_inc(&el->rc); + write_lock(&list_lock); ... + add_element read_unlock(&list_lock); + ... ... + write_unlock(&list_lock); } } 3. 4. release_referenced() delete() { { - ... write_lock(&list_lock); - atomic_dec(&el->rc, relfunc) ... - ... delete_element -} write_unlock(&list_lock); - ... - if (atomic_dec_and_test(&el->rc)) - kfree(el); - ... + ... write_lock(&list_lock); + atomic_dec(&el->rc, relfunc) ... + ... delete_element +} write_unlock(&list_lock); + ... + if (atomic_dec_and_test(&el->rc)) + kfree(el); + ... } If this list/array is made lock free using rcu as in changing the write_lock in add() and delete() to spin_lock and changing read_lock -in search_and_reference to rcu_read_lock(), the rcuref_get in +in search_and_reference to rcu_read_lock(), the atomic_get in search_and_reference could potentially hold reference to an element which -has already been deleted from the list/array. rcuref_lf_get_rcu takes +has already been deleted from the list/array. atomic_inc_not_zero takes care of this scenario. search_and_reference should look as; 1. 2. add() search_and_reference() { { - alloc_object rcu_read_lock(); - ... search_for_element - atomic_set(&el->rc, 1); if (rcuref_inc_lf(&el->rc)) { - write_lock(&list_lock); rcu_read_unlock(); - return FAIL; - add_element } - ... ... - write_unlock(&list_lock); rcu_read_unlock(); + alloc_object rcu_read_lock(); + ... search_for_element + atomic_set(&el->rc, 1); if (atomic_inc_not_zero(&el->rc)) { + write_lock(&list_lock); rcu_read_unlock(); + return FAIL; + add_element } + ... ... + write_unlock(&list_lock); rcu_read_unlock(); } } 3. 4. release_referenced() delete() { { - ... write_lock(&list_lock); - rcuref_dec(&el->rc, relfunc) ... - ... delete_element -} write_unlock(&list_lock); - ... - if (rcuref_dec_and_test(&el->rc)) - call_rcu(&el->head, el_free); - ... + ... write_lock(&list_lock); + atomic_dec(&el->rc, relfunc) ... + ... delete_element +} write_unlock(&list_lock); + ... + if (atomic_dec_and_test(&el->rc)) + call_rcu(&el->head, el_free); + ... } Sometimes, reference to the element need to be obtained in the -update (write) stream. In such cases, rcuref_inc_lf might be an overkill -since the spinlock serialising list updates are held. rcuref_inc +update (write) stream. In such cases, atomic_inc_not_zero might be an +overkill since the spinlock serialising list updates are held. atomic_inc is to be used in such cases. -For arches which do not have cmpxchg rcuref_inc_lf -api uses a hashed spinlock implementation and the same hashed spinlock -is acquired in all rcuref_xxx primitives to preserve atomicity. -Note: Use rcuref_inc api only if you need to use rcuref_inc_lf on the -refcounter atleast at one place. Mixing rcuref_inc and atomic_xxx api -might lead to races. rcuref_inc_lf() must be used in lockfree -RCU critical sections only. + diff --git a/fs/aio.c b/fs/aio.c index 5a28b69ad223..aec2b1916d1b 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -514,7 +513,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) /* Must be done under the lock to serialise against cancellation. * Call this aio_fput as it duplicates fput via the fput_work. */ - if (unlikely(rcuref_dec_and_test(&req->ki_filp->f_count))) { + if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) { get_ioctx(ctx); spin_lock(&fput_lock); list_add(&req->ki_list, &fput_head); diff --git a/fs/file_table.c b/fs/file_table.c index c3a5e2fd663b..6142250104a6 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -117,7 +117,7 @@ EXPORT_SYMBOL(get_empty_filp); void fastcall fput(struct file *file) { - if (rcuref_dec_and_test(&file->f_count)) + if (atomic_dec_and_test(&file->f_count)) __fput(file); } @@ -166,7 +166,7 @@ struct file fastcall *fget(unsigned int fd) rcu_read_lock(); file = fcheck_files(files, fd); if (file) { - if (!rcuref_inc_lf(&file->f_count)) { + if (!atomic_inc_not_zero(&file->f_count)) { /* File object ref couldn't be taken */ rcu_read_unlock(); return NULL; @@ -198,7 +198,7 @@ struct file fastcall *fget_light(unsigned int fd, int *fput_needed) rcu_read_lock(); file = fcheck_files(files, fd); if (file) { - if (rcuref_inc_lf(&file->f_count)) + if (atomic_inc_not_zero(&file->f_count)) *fput_needed = 1; else /* Didn't get the reference, someone's freed */ @@ -213,7 +213,7 @@ struct file fastcall *fget_light(unsigned int fd, int *fput_needed) void put_filp(struct file *file) { - if (rcuref_dec_and_test(&file->f_count)) { + if (atomic_dec_and_test(&file->f_count)) { security_file_free(file); file_kill(file); file_free(file); diff --git a/include/linux/fs.h b/include/linux/fs.h index 2c9c48d65630..ef29500b5df8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -9,7 +9,6 @@ #include #include #include -#include /* * It's silly to have NR_OPEN bigger than NR_FILE, but you can change @@ -653,7 +652,7 @@ extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); #define file_list_unlock() spin_unlock(&files_lock); -#define get_file(x) rcuref_inc(&(x)->f_count) +#define get_file(x) atomic_inc(&(x)->f_count) #define file_count(x) atomic_read(&(x)->f_count) #define MAX_NON_LFS ((1UL<<31) - 1) diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 36e5d269612f..c57ff2fcb30a 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -19,6 +19,7 @@ #ifndef _LINUX_RADIX_TREE_H #define _LINUX_RADIX_TREE_H +#include #include #include diff --git a/include/linux/rcuref.h b/include/linux/rcuref.h deleted file mode 100644 index e1adbba14b67..000000000000 --- a/include/linux/rcuref.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * rcuref.h - * - * Reference counting for elements of lists/arrays protected by - * RCU. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2005 - * - * Author: Dipankar Sarma - * Ravikiran Thirumalai - * - * See Documentation/RCU/rcuref.txt for detailed user guide. - * - */ - -#ifndef _RCUREF_H_ -#define _RCUREF_H_ - -#ifdef __KERNEL__ - -#include -#include -#include -#include - -/* - * These APIs work on traditional atomic_t counters used in the - * kernel for reference counting. Under special circumstances - * where a lock-free get() operation races with a put() operation - * these APIs can be used. See Documentation/RCU/rcuref.txt. - */ - -#ifdef __HAVE_ARCH_CMPXCHG - -/** - * rcuref_inc - increment refcount for object. - * @rcuref: reference counter in the object in question. - * - * This should be used only for objects where we use RCU and - * use the rcuref_inc_lf() api to acquire a reference - * in a lock-free reader-side critical section. - */ -static inline void rcuref_inc(atomic_t *rcuref) -{ - atomic_inc(rcuref); -} - -/** - * rcuref_dec - decrement refcount for object. - * @rcuref: reference counter in the object in question. - * - * This should be used only for objects where we use RCU and - * use the rcuref_inc_lf() api to acquire a reference - * in a lock-free reader-side critical section. - */ -static inline void rcuref_dec(atomic_t *rcuref) -{ - atomic_dec(rcuref); -} - -/** - * rcuref_dec_and_test - decrement refcount for object and test - * @rcuref: reference counter in the object. - * @release: pointer to the function that will clean up the object - * when the last reference to the object is released. - * This pointer is required. - * - * Decrement the refcount, and if 0, return 1. Else return 0. - * - * This should be used only for objects where we use RCU and - * use the rcuref_inc_lf() api to acquire a reference - * in a lock-free reader-side critical section. - */ -static inline int rcuref_dec_and_test(atomic_t *rcuref) -{ - return atomic_dec_and_test(rcuref); -} - -/* - * cmpxchg is needed on UP too, if deletions to the list/array can happen - * in interrupt context. - */ - -/** - * rcuref_inc_lf - Take reference to an object in a read-side - * critical section protected by RCU. - * @rcuref: reference counter in the object in question. - * - * Try and increment the refcount by 1. The increment might fail if - * the reference counter has been through a 1 to 0 transition and - * is no longer part of the lock-free list. - * Returns non-zero on successful increment and zero otherwise. - */ -static inline int rcuref_inc_lf(atomic_t *rcuref) -{ - int c, old; - c = atomic_read(rcuref); - while (c && (old = cmpxchg(&rcuref->counter, c, c + 1)) != c) - c = old; - return c; -} - -#else /* !__HAVE_ARCH_CMPXCHG */ - -extern spinlock_t __rcuref_hash[]; - -/* - * Use a hash table of locks to protect the reference count - * since cmpxchg is not available in this arch. - */ -#ifdef CONFIG_SMP -#define RCUREF_HASH_SIZE 4 -#define RCUREF_HASH(k) \ - (&__rcuref_hash[(((unsigned long)k)>>8) & (RCUREF_HASH_SIZE-1)]) -#else -#define RCUREF_HASH_SIZE 1 -#define RCUREF_HASH(k) &__rcuref_hash[0] -#endif /* CONFIG_SMP */ - -/** - * rcuref_inc - increment refcount for object. - * @rcuref: reference counter in the object in question. - * - * This should be used only for objects where we use RCU and - * use the rcuref_inc_lf() api to acquire a reference in a lock-free - * reader-side critical section. - */ -static inline void rcuref_inc(atomic_t *rcuref) -{ - unsigned long flags; - spin_lock_irqsave(RCUREF_HASH(rcuref), flags); - rcuref->counter += 1; - spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); -} - -/** - * rcuref_dec - decrement refcount for object. - * @rcuref: reference counter in the object in question. - * - * This should be used only for objects where we use RCU and - * use the rcuref_inc_lf() api to acquire a reference in a lock-free - * reader-side critical section. - */ -static inline void rcuref_dec(atomic_t *rcuref) -{ - unsigned long flags; - spin_lock_irqsave(RCUREF_HASH(rcuref), flags); - rcuref->counter -= 1; - spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); -} - -/** - * rcuref_dec_and_test - decrement refcount for object and test - * @rcuref: reference counter in the object. - * @release: pointer to the function that will clean up the object - * when the last reference to the object is released. - * This pointer is required. - * - * Decrement the refcount, and if 0, return 1. Else return 0. - * - * This should be used only for objects where we use RCU and - * use the rcuref_inc_lf() api to acquire a reference in a lock-free - * reader-side critical section. - */ -static inline int rcuref_dec_and_test(atomic_t *rcuref) -{ - unsigned long flags; - spin_lock_irqsave(RCUREF_HASH(rcuref), flags); - rcuref->counter--; - if (!rcuref->counter) { - spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); - return 1; - } else { - spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); - return 0; - } -} - -/** - * rcuref_inc_lf - Take reference to an object of a lock-free collection - * by traversing a lock-free list/array. - * @rcuref: reference counter in the object in question. - * - * Try and increment the refcount by 1. The increment might fail if - * the reference counter has been through a 1 to 0 transition and - * object is no longer part of the lock-free list. - * Returns non-zero on successful increment and zero otherwise. - */ -static inline int rcuref_inc_lf(atomic_t *rcuref) -{ - int ret; - unsigned long flags; - spin_lock_irqsave(RCUREF_HASH(rcuref), flags); - if (rcuref->counter) - ret = rcuref->counter++; - else - ret = 0; - spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); - return ret; -} - - -#endif /* !__HAVE_ARCH_CMPXCHG */ - -#endif /* __KERNEL__ */ -#endif /* _RCUREF_H_ */ diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 0a669bd2f6d1..30b0bba03859 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -46,7 +46,6 @@ #include #include #include -#include #include /* Definition for rcupdate control block. */ @@ -74,19 +73,6 @@ DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L }; static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL}; static int maxbatch = 10000; -#ifndef __HAVE_ARCH_CMPXCHG -/* - * We use an array of spinlocks for the rcurefs -- similar to ones in sparc - * 32 bit atomic_t implementations, and a hash function similar to that - * for our refcounting needs. - * Can't help multiprocessors which donot have cmpxchg :( - */ - -spinlock_t __rcuref_hash[RCUREF_HASH_SIZE] = { - [0 ... (RCUREF_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED -}; -#endif - /** * call_rcu - Queue an RCU callback for invocation after a grace period. * @head: structure to be used for queueing the RCU updates. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 36efe088ad81..75174c81529a 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3d496eae1b47..6647204e4636 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1663,7 +1663,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) continue; } if (devnull) { - rcuref_inc(&devnull->f_count); + get_file(devnull); } else { devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR); if (!devnull) { -- cgit v1.2.3 From b3f3d6141f8636f627bf19fd44eaf59a52637ac8 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Sun, 8 Jan 2006 01:02:20 -0800 Subject: [PATCH] ELF: symbol table type additions Needed for the Novell kernel debugger and perhaps some per-cpu data on x86_64 in the future. Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/elf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/elf.h b/include/linux/elf.h index ff955dbf510d..d3bfacb24496 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -151,6 +151,8 @@ typedef __s64 Elf64_Sxword; #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 #define ELF_ST_BIND(x) ((x) >> 4) #define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) -- cgit v1.2.3 From b33291c0bcecfa44baa905964eec4b8815dcbcdf Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:02:21 -0800 Subject: [PATCH] ipc: expand shm_flags Unobfsucate this struct member Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/shm.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index 0ef4a1cf3e27..0b92e874fc06 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -34,8 +34,6 @@ #include "util.h" -#define shm_flags shm_perm.mode - static struct file_operations shm_file_operations; static struct vm_operations_struct shm_vm_ops; @@ -148,7 +146,7 @@ static void shm_close (struct vm_area_struct *shmd) shp->shm_dtim = get_seconds(); shp->shm_nattch--; if(shp->shm_nattch == 0 && - shp->shm_flags & SHM_DEST) + shp->shm_perm.mode & SHM_DEST) shm_destroy (shp); else shm_unlock(shp); @@ -205,7 +203,7 @@ static int newseg (key_t key, int shmflg, size_t size) return -ENOMEM; shp->shm_perm.key = key; - shp->shm_flags = (shmflg & S_IRWXUGO); + shp->shm_perm.mode = (shmflg & S_IRWXUGO); shp->mlock_user = NULL; shp->shm_perm.security = NULL; @@ -345,7 +343,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __ out->uid = tbuf.shm_perm.uid; out->gid = tbuf.shm_perm.gid; - out->mode = tbuf.shm_flags; + out->mode = tbuf.shm_perm.mode; return 0; } @@ -358,7 +356,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __ out->uid = tbuf_old.shm_perm.uid; out->gid = tbuf_old.shm_perm.gid; - out->mode = tbuf_old.shm_flags; + out->mode = tbuf_old.shm_perm.mode; return 0; } @@ -560,13 +558,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if (!is_file_hugepages(shp->shm_file)) { err = shmem_lock(shp->shm_file, 1, user); if (!err) { - shp->shm_flags |= SHM_LOCKED; + shp->shm_perm.mode |= SHM_LOCKED; shp->mlock_user = user; } } } else if (!is_file_hugepages(shp->shm_file)) { shmem_lock(shp->shm_file, 0, shp->mlock_user); - shp->shm_flags &= ~SHM_LOCKED; + shp->shm_perm.mode &= ~SHM_LOCKED; shp->mlock_user = NULL; } shm_unlock(shp); @@ -605,7 +603,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) goto out_unlock_up; if (shp->shm_nattch){ - shp->shm_flags |= SHM_DEST; + shp->shm_perm.mode |= SHM_DEST; /* Do not find it any more */ shp->shm_perm.key = IPC_PRIVATE; shm_unlock(shp); @@ -644,7 +642,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) shp->shm_perm.uid = setbuf.uid; shp->shm_perm.gid = setbuf.gid; - shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO) + shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO) | (setbuf.mode & S_IRWXUGO); shp->shm_ctim = get_seconds(); break; @@ -777,7 +775,7 @@ invalid: BUG(); shp->shm_nattch--; if(shp->shm_nattch == 0 && - shp->shm_flags & SHM_DEST) + shp->shm_perm.mode & SHM_DEST) shm_destroy (shp); else shm_unlock(shp); @@ -902,7 +900,7 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it) return seq_printf(s, format, shp->shm_perm.key, shp->id, - shp->shm_flags, + shp->shm_perm.mode, shp->shm_segsz, shp->shm_cprid, shp->shm_lprid, -- cgit v1.2.3 From 6625b861f8f0e429902b8671b3e70792cd99074e Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:23 -0800 Subject: [PATCH] relayfs: decouple buffer creation from inode creation The patch series implementa or fixes 3 things that were specifically requested or suggested by relayfs users: - support for non-relay files (patches 1-6) Currently, the relayfs API only supports the creation of directories (relayfs_create_dir()) and relay files (relay_open()). These patches adds support for non-relay files (relayfs_create_file()). This is so relayfs applications can create 'control files' in relayfs itself rather than in /proc or via a netlink channel, as is currently done in the relay-app examples. Basically what this amounts to is exporting relayfs_create_file() with an additional file_ops param that clients can use to supply file operations for their own special-purpose files in relayfs. - make exported relay file ops useful (patches 7-8) The relayfs relay_file_operations have always been exported, the intent being to make it possible to create relay files in other filesystems such as debugfs. The problem, though, is that currently the file operations are too tightly coupled to relayfs to actually be used for this purpose. This patch fixes that by adding a couple of callback functions that allow a client to hook into relay_open()/close() and supply the files that will be used to represent the channel buffers; the default implementation if no callbacks are defined is to create the files in relayfs. - add an option to create global relay buffer (patches 9-10) The file creation callback also supplies an optional param, is_global, that can be used by clients to create a single global relayfs buffer instead of the default per-cpu buffers. This was suggested as being useful for certain debugging applications where it's more convenient to be able to get all the data from a single channel without having to go to the bother of dealing with per-cpu files. - cleanup, some renaming and Documentation updates (patches 11-12) There were several comments that the use of netlink in the example code was non-intuitive and in fact the whole relay-app business was needlessly confusing. Based on that feedback, the example code has been completely converted over to relayfs control files as supported by this patch, and have also been made completely self-contained. The converted examples along with a couple of new examples that demonstrate using exported relay files can be found in relay-apps tarball: http://prdownloads.sourceforge.net/relayfs/relay-apps-0.9.tar.gz?download This patch: Separate buffer create/destroy from inode create/destroy. We want to be able to associate other data and not just relay buffers with inodes. Buffer create/destroy is moved out of inode.c and into relayfs core code. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/buffers.c | 1 + fs/relayfs/inode.c | 31 +++++++++---------------------- fs/relayfs/relay.c | 11 ++++++++--- fs/relayfs/relay.h | 2 +- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/fs/relayfs/buffers.c b/fs/relayfs/buffers.c index 84e21ffa5ca8..667b529944c5 100644 --- a/fs/relayfs/buffers.c +++ b/fs/relayfs/buffers.c @@ -186,4 +186,5 @@ void relay_remove_buf(struct kref *kref) { struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref); relayfs_remove(buf->dentry); + relay_destroy_buf(buf); } diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c index 0f7f88d067ad..379e07cd2b34 100644 --- a/fs/relayfs/inode.c +++ b/fs/relayfs/inode.c @@ -34,23 +34,13 @@ static struct backing_dev_info relayfs_backing_dev_info = { }; static struct inode *relayfs_get_inode(struct super_block *sb, int mode, - struct rchan *chan) + void *data) { - struct rchan_buf *buf = NULL; struct inode *inode; - if (S_ISREG(mode)) { - BUG_ON(!chan); - buf = relay_create_buf(chan); - if (!buf) - return NULL; - } - inode = new_inode(sb); - if (!inode) { - relay_destroy_buf(buf); + if (!inode) return NULL; - } inode->i_mode = mode; inode->i_uid = 0; @@ -62,7 +52,7 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode, switch (mode & S_IFMT) { case S_IFREG: inode->i_fop = &relayfs_file_operations; - RELAYFS_I(inode)->buf = buf; + RELAYFS_I(inode)->buf = data; break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; @@ -83,7 +73,7 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode, * @name: the name of the file to create * @parent: parent directory * @mode: mode - * @chan: relay channel associated with the file + * @data: user-associated data for this file * * Returns the new dentry, NULL on failure * @@ -92,7 +82,7 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode, static struct dentry *relayfs_create_entry(const char *name, struct dentry *parent, int mode, - struct rchan *chan) + void *data) { struct dentry *d; struct inode *inode; @@ -127,7 +117,7 @@ static struct dentry *relayfs_create_entry(const char *name, goto release_mount; } - inode = relayfs_get_inode(parent->d_inode->i_sb, mode, chan); + inode = relayfs_get_inode(parent->d_inode->i_sb, mode, data); if (!inode) { d = NULL; goto release_mount; @@ -155,20 +145,20 @@ exit: * @name: the name of the file to create * @parent: parent directory * @mode: mode, if not specied the default perms are used - * @chan: channel associated with the file + * @data: user-associated data for this file * * Returns file dentry if successful, NULL otherwise. * * The file will be created user r on behalf of current user. */ struct dentry *relayfs_create_file(const char *name, struct dentry *parent, - int mode, struct rchan *chan) + int mode, void *data) { if (!mode) mode = S_IRUSR; mode = (mode & S_IALLUGO) | S_IFREG; - return relayfs_create_entry(name, parent, mode, chan); + return relayfs_create_entry(name, parent, mode, data); } /** @@ -505,9 +495,6 @@ static struct inode *relayfs_alloc_inode(struct super_block *sb) */ static void relayfs_destroy_inode(struct inode *inode) { - if (RELAYFS_I(inode)->buf) - relay_destroy_buf(RELAYFS_I(inode)->buf); - kmem_cache_free(relayfs_inode_cachep, RELAYFS_I(inode)); } diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index 2a6f7f12b7f9..7fbda177ad8f 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -171,12 +171,17 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, struct rchan_buf *buf; struct dentry *dentry; + buf = relay_create_buf(chan); + if (!buf) + return NULL; + /* Create file in fs */ - dentry = relayfs_create_file(filename, parent, S_IRUSR, chan); - if (!dentry) + dentry = relayfs_create_file(filename, parent, S_IRUSR, buf); + if (!dentry) { + relay_destroy_buf(buf); return NULL; + } - buf = RELAYFS_I(dentry->d_inode)->buf; buf->dentry = dentry; __relay_reset(buf, 1); diff --git a/fs/relayfs/relay.h b/fs/relayfs/relay.h index 703503fa22b6..c325bb243549 100644 --- a/fs/relayfs/relay.h +++ b/fs/relayfs/relay.h @@ -4,7 +4,7 @@ struct dentry *relayfs_create_file(const char *name, struct dentry *parent, int mode, - struct rchan *chan); + void *data); extern int relayfs_remove(struct dentry *dentry); extern int relay_buf_empty(struct rchan_buf *buf); extern void relay_destroy_channel(struct kref *kref); -- cgit v1.2.3 From 907f2c77d1653ce235e8e1fd6ce5c46005814e78 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:24 -0800 Subject: [PATCH] relayfs: export relayfs_create_file() with fileops param This patch adds a mandatory fileops param to relayfs_create_file() and exports that function so that clients can use it to create files defined by their own set of file operations, in relayfs. The purpose is to allow relayfs applications to create their own set of 'control' files alongside their relay files in relayfs rather than having to create them in /proc or debugfs for instance. relayfs_create_file() is also used by relay_open_buf() to create the relay files for a channel. In this case, a pointer to relayfs_file_operations is passed in, along with a pointer to the buffer associated with the file. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/inode.c | 41 ++++++++++++++++++++++++++--------------- fs/relayfs/relay.c | 3 ++- fs/relayfs/relay.h | 4 ---- include/linux/relayfs_fs.h | 7 ++++++- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c index 379e07cd2b34..a5e6d4f2efb9 100644 --- a/fs/relayfs/inode.c +++ b/fs/relayfs/inode.c @@ -33,7 +33,9 @@ static struct backing_dev_info relayfs_backing_dev_info = { .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, }; -static struct inode *relayfs_get_inode(struct super_block *sb, int mode, +static struct inode *relayfs_get_inode(struct super_block *sb, + int mode, + struct file_operations *fops, void *data) { struct inode *inode; @@ -51,8 +53,8 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode, inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { case S_IFREG: - inode->i_fop = &relayfs_file_operations; - RELAYFS_I(inode)->buf = data; + inode->i_fop = fops; + RELAYFS_I(inode)->data = data; break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; @@ -73,6 +75,7 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode, * @name: the name of the file to create * @parent: parent directory * @mode: mode + * @fops: file operations to use for the file * @data: user-associated data for this file * * Returns the new dentry, NULL on failure @@ -82,6 +85,7 @@ static struct inode *relayfs_get_inode(struct super_block *sb, int mode, static struct dentry *relayfs_create_entry(const char *name, struct dentry *parent, int mode, + struct file_operations *fops, void *data) { struct dentry *d; @@ -117,7 +121,7 @@ static struct dentry *relayfs_create_entry(const char *name, goto release_mount; } - inode = relayfs_get_inode(parent->d_inode->i_sb, mode, data); + inode = relayfs_get_inode(parent->d_inode->i_sb, mode, fops, data); if (!inode) { d = NULL; goto release_mount; @@ -145,20 +149,26 @@ exit: * @name: the name of the file to create * @parent: parent directory * @mode: mode, if not specied the default perms are used + * @fops: file operations to use for the file * @data: user-associated data for this file * * Returns file dentry if successful, NULL otherwise. * * The file will be created user r on behalf of current user. */ -struct dentry *relayfs_create_file(const char *name, struct dentry *parent, - int mode, void *data) +struct dentry *relayfs_create_file(const char *name, + struct dentry *parent, + int mode, + struct file_operations *fops, + void *data) { + BUG_ON(!fops); + if (!mode) mode = S_IRUSR; mode = (mode & S_IALLUGO) | S_IFREG; - return relayfs_create_entry(name, parent, mode, data); + return relayfs_create_entry(name, parent, mode, fops, data); } /** @@ -173,7 +183,7 @@ struct dentry *relayfs_create_file(const char *name, struct dentry *parent, struct dentry *relayfs_create_dir(const char *name, struct dentry *parent) { int mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; - return relayfs_create_entry(name, parent, mode, NULL); + return relayfs_create_entry(name, parent, mode, NULL, NULL); } /** @@ -234,7 +244,7 @@ int relayfs_remove_dir(struct dentry *dentry) */ static int relayfs_open(struct inode *inode, struct file *filp) { - struct rchan_buf *buf = RELAYFS_I(inode)->buf; + struct rchan_buf *buf = RELAYFS_I(inode)->data; kref_get(&buf->kref); return 0; @@ -250,7 +260,7 @@ static int relayfs_open(struct inode *inode, struct file *filp) static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma) { struct inode *inode = filp->f_dentry->d_inode; - return relay_mmap_buf(RELAYFS_I(inode)->buf, vma); + return relay_mmap_buf(RELAYFS_I(inode)->data, vma); } /** @@ -264,7 +274,7 @@ static unsigned int relayfs_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0; struct inode *inode = filp->f_dentry->d_inode; - struct rchan_buf *buf = RELAYFS_I(inode)->buf; + struct rchan_buf *buf = RELAYFS_I(inode)->data; if (buf->finalized) return POLLERR; @@ -288,7 +298,7 @@ static unsigned int relayfs_poll(struct file *filp, poll_table *wait) */ static int relayfs_release(struct inode *inode, struct file *filp) { - struct rchan_buf *buf = RELAYFS_I(inode)->buf; + struct rchan_buf *buf = RELAYFS_I(inode)->data; kref_put(&buf->kref, relay_remove_buf); return 0; @@ -450,7 +460,7 @@ static ssize_t relayfs_read(struct file *filp, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; - struct rchan_buf *buf = RELAYFS_I(inode)->buf; + struct rchan_buf *buf = RELAYFS_I(inode)->data; size_t read_start, avail; ssize_t ret = 0; void *from; @@ -485,7 +495,7 @@ static struct inode *relayfs_alloc_inode(struct super_block *sb) struct relayfs_inode_info *p = kmem_cache_alloc(relayfs_inode_cachep, SLAB_KERNEL); if (!p) return NULL; - p->buf = NULL; + p->data = NULL; return &p->vfs_inode; } @@ -531,7 +541,7 @@ static int relayfs_fill_super(struct super_block * sb, void * data, int silent) sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RELAYFS_MAGIC; sb->s_op = &relayfs_ops; - inode = relayfs_get_inode(sb, mode, NULL); + inode = relayfs_get_inode(sb, mode, NULL, NULL); if (!inode) return -ENOMEM; @@ -589,6 +599,7 @@ module_exit(exit_relayfs_fs) EXPORT_SYMBOL_GPL(relayfs_file_operations); EXPORT_SYMBOL_GPL(relayfs_create_dir); EXPORT_SYMBOL_GPL(relayfs_remove_dir); +EXPORT_SYMBOL_GPL(relayfs_create_file); MODULE_AUTHOR("Tom Zanussi and Karim Yaghmour "); MODULE_DESCRIPTION("Relay Filesystem"); diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index 7fbda177ad8f..a9cd5585c45c 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -176,7 +176,8 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, return NULL; /* Create file in fs */ - dentry = relayfs_create_file(filename, parent, S_IRUSR, buf); + dentry = relayfs_create_file(filename, parent, S_IRUSR, + &relayfs_file_operations, buf); if (!dentry) { relay_destroy_buf(buf); return NULL; diff --git a/fs/relayfs/relay.h b/fs/relayfs/relay.h index c325bb243549..0993d3e5753b 100644 --- a/fs/relayfs/relay.h +++ b/fs/relayfs/relay.h @@ -1,10 +1,6 @@ #ifndef _RELAY_H #define _RELAY_H -struct dentry *relayfs_create_file(const char *name, - struct dentry *parent, - int mode, - void *data); extern int relayfs_remove(struct dentry *dentry); extern int relay_buf_empty(struct rchan_buf *buf); extern void relay_destroy_channel(struct kref *kref); diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index fb7e80737325..a122df2d9880 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -70,7 +70,7 @@ struct rchan struct relayfs_inode_info { struct inode vfs_inode; - struct rchan_buf *buf; + void *data; }; static inline struct relayfs_inode_info *RELAYFS_I(struct inode *inode) @@ -148,6 +148,11 @@ extern size_t relay_switch_subbuf(struct rchan_buf *buf, extern struct dentry *relayfs_create_dir(const char *name, struct dentry *parent); extern int relayfs_remove_dir(struct dentry *dentry); +extern struct dentry *relayfs_create_file(const char *name, + struct dentry *parent, + int mode, + struct file_operations *fops, + void *data); /** * relay_write - write data into the channel -- cgit v1.2.3 From 7431733791feb0b19453d8047b0723c744667040 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:25 -0800 Subject: [PATCH] relayfs: add relayfs_remove_file() This patch adds and exports relayfs_remove_file(), for API symmetry (with relayfs_create_file()). Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/inode.c | 12 ++++++++++++ include/linux/relayfs_fs.h | 1 + 2 files changed, 13 insertions(+) diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c index a5e6d4f2efb9..b2f50655736b 100644 --- a/fs/relayfs/inode.c +++ b/fs/relayfs/inode.c @@ -224,6 +224,17 @@ int relayfs_remove(struct dentry *dentry) return error; } +/** + * relayfs_remove_file - remove a file from relay filesystem + * @dentry: directory dentry + * + * Returns 0 if successful, negative otherwise. + */ +int relayfs_remove_file(struct dentry *dentry) +{ + return relayfs_remove(dentry); +} + /** * relayfs_remove_dir - remove a directory in the relay filesystem * @dentry: directory dentry @@ -600,6 +611,7 @@ EXPORT_SYMBOL_GPL(relayfs_file_operations); EXPORT_SYMBOL_GPL(relayfs_create_dir); EXPORT_SYMBOL_GPL(relayfs_remove_dir); EXPORT_SYMBOL_GPL(relayfs_create_file); +EXPORT_SYMBOL_GPL(relayfs_remove_file); MODULE_AUTHOR("Tom Zanussi and Karim Yaghmour "); MODULE_DESCRIPTION("Relay Filesystem"); diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index a122df2d9880..921540b1cdf8 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -153,6 +153,7 @@ extern struct dentry *relayfs_create_file(const char *name, int mode, struct file_operations *fops, void *data); +extern int relayfs_remove_file(struct dentry *dentry); /** * relay_write - write data into the channel -- cgit v1.2.3 From 51008f9f95a4c3158151a75f88fb03fb0f646aba Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:26 -0800 Subject: [PATCH] relayfs: use generic_ip for private data Use inode->u.generic_ip instead of relayfs_inode_info to store pointer to user data. Clients using relayfs_file_create() to create their own files would probably more expect their data to be stored in generic_ip; we also intend in the next set of patches to get rid of relayfs-specific stuff in the file operations, so we might as well do it here. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/inode.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c index b2f50655736b..7f6d2c8e91c2 100644 --- a/fs/relayfs/inode.c +++ b/fs/relayfs/inode.c @@ -54,7 +54,8 @@ static struct inode *relayfs_get_inode(struct super_block *sb, switch (mode & S_IFMT) { case S_IFREG: inode->i_fop = fops; - RELAYFS_I(inode)->data = data; + if (data) + inode->u.generic_ip = data; break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; @@ -255,8 +256,9 @@ int relayfs_remove_dir(struct dentry *dentry) */ static int relayfs_open(struct inode *inode, struct file *filp) { - struct rchan_buf *buf = RELAYFS_I(inode)->data; + struct rchan_buf *buf = inode->u.generic_ip; kref_get(&buf->kref); + filp->private_data = buf; return 0; } @@ -270,8 +272,8 @@ static int relayfs_open(struct inode *inode, struct file *filp) */ static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma) { - struct inode *inode = filp->f_dentry->d_inode; - return relay_mmap_buf(RELAYFS_I(inode)->data, vma); + struct rchan_buf *buf = filp->private_data; + return relay_mmap_buf(buf, vma); } /** @@ -284,8 +286,7 @@ static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma) static unsigned int relayfs_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0; - struct inode *inode = filp->f_dentry->d_inode; - struct rchan_buf *buf = RELAYFS_I(inode)->data; + struct rchan_buf *buf = filp->private_data; if (buf->finalized) return POLLERR; @@ -309,7 +310,7 @@ static unsigned int relayfs_poll(struct file *filp, poll_table *wait) */ static int relayfs_release(struct inode *inode, struct file *filp) { - struct rchan_buf *buf = RELAYFS_I(inode)->data; + struct rchan_buf *buf = filp->private_data; kref_put(&buf->kref, relay_remove_buf); return 0; @@ -470,8 +471,8 @@ static ssize_t relayfs_read(struct file *filp, size_t count, loff_t *ppos) { + struct rchan_buf *buf = filp->private_data; struct inode *inode = filp->f_dentry->d_inode; - struct rchan_buf *buf = RELAYFS_I(inode)->data; size_t read_start, avail; ssize_t ret = 0; void *from; -- cgit v1.2.3 From aaea25d7a68a7f72e167dc1698b66a15edc71883 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:26 -0800 Subject: [PATCH] relayfs: remove unused alloc/destroy_inode() Since we're no longer using relayfs_inode_info, remove relayfs_alloc_inode() and relayfs_destroy_inode() along with the relayfs inode cache. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/inode.c | 46 +--------------------------------------------- include/linux/relayfs_fs.h | 14 -------------- 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c index 7f6d2c8e91c2..b4c3e0466e98 100644 --- a/fs/relayfs/inode.c +++ b/fs/relayfs/inode.c @@ -26,7 +26,6 @@ static struct vfsmount * relayfs_mount; static int relayfs_mount_count; -static kmem_cache_t * relayfs_inode_cachep; static struct backing_dev_info relayfs_backing_dev_info = { .ra_pages = 0, /* No readahead */ @@ -499,34 +498,6 @@ out: return ret; } -/** - * relayfs alloc_inode() implementation - */ -static struct inode *relayfs_alloc_inode(struct super_block *sb) -{ - struct relayfs_inode_info *p = kmem_cache_alloc(relayfs_inode_cachep, SLAB_KERNEL); - if (!p) - return NULL; - p->data = NULL; - - return &p->vfs_inode; -} - -/** - * relayfs destroy_inode() implementation - */ -static void relayfs_destroy_inode(struct inode *inode) -{ - kmem_cache_free(relayfs_inode_cachep, RELAYFS_I(inode)); -} - -static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags) -{ - struct relayfs_inode_info *i = p; - if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) - inode_init_once(&i->vfs_inode); -} - struct file_operations relayfs_file_operations = { .open = relayfs_open, .poll = relayfs_poll, @@ -539,8 +510,6 @@ struct file_operations relayfs_file_operations = { static struct super_operations relayfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, - .alloc_inode = relayfs_alloc_inode, - .destroy_inode = relayfs_destroy_inode, }; static int relayfs_fill_super(struct super_block * sb, void * data, int silent) @@ -584,25 +553,12 @@ static struct file_system_type relayfs_fs_type = { static int __init init_relayfs_fs(void) { - int err; - - relayfs_inode_cachep = kmem_cache_create("relayfs_inode_cache", - sizeof(struct relayfs_inode_info), 0, - 0, init_once, NULL); - if (!relayfs_inode_cachep) - return -ENOMEM; - - err = register_filesystem(&relayfs_fs_type); - if (err) - kmem_cache_destroy(relayfs_inode_cachep); - - return err; + return register_filesystem(&relayfs_fs_type); } static void __exit exit_relayfs_fs(void) { unregister_filesystem(&relayfs_fs_type); - kmem_cache_destroy(relayfs_inode_cachep); } module_init(init_relayfs_fs) diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index 921540b1cdf8..8200ecbe6e0f 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -64,20 +64,6 @@ struct rchan struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */ }; -/* - * Relayfs inode - */ -struct relayfs_inode_info -{ - struct inode vfs_inode; - void *data; -}; - -static inline struct relayfs_inode_info *RELAYFS_I(struct inode *inode) -{ - return container_of(inode, struct relayfs_inode_info, vfs_inode); -} - /* * Relay channel client callbacks */ -- cgit v1.2.3 From 925ac8a2b637466ba0ad8dfaf7b49aa9a362502f Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:27 -0800 Subject: [PATCH] relayfs: add Documention for non-relay files Documentation update for non-relay files. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/relayfs.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt index d803abed29f0..0720a049d0b8 100644 --- a/Documentation/filesystems/relayfs.txt +++ b/Documentation/filesystems/relayfs.txt @@ -125,6 +125,8 @@ Here's a summary of the API relayfs provides to in-kernel clients: relay_reset(chan) relayfs_create_dir(name, parent) relayfs_remove_dir(dentry) + relayfs_create_file(name, parent, mode, fops, data) + relayfs_remove_file(dentry) channel management typically called on instigation of userspace: @@ -320,6 +322,27 @@ forces a sub-buffer switch on all the channel buffers, and can be used to finalize and process the last sub-buffers before the channel is closed. +Creating non-relay files +------------------------ + +relay_open() automatically creates files in the relayfs filesystem to +represent the per-cpu kernel buffers; it's often useful for +applications to be able to create their own files alongside the relay +files in the relayfs filesystem as well e.g. 'control' files much like +those created in /proc or debugfs for similar purposes, used to +communicate control information between the kernel and user sides of a +relayfs application. For this purpose the relayfs_create_file() and +relayfs_remove_file() API functions exist. For relayfs_create_file(), +the caller passes in a set of user-defined file operations to be used +for the file and an optional void * to a user-specified data item, +which will be accessible via inode->u.generic_ip (see the relay-apps +tarball for examples). The file_operations are a required parameter +to relayfs_create_file() and thus the semantics of these files are +completely defined by the caller. + +See the relay-apps tarball at http://relayfs.sourceforge.net for +examples of how these non-relay files are meant to be used. + Misc ---- -- cgit v1.2.3 From 08c541a7ade230883c48225f4ea406a0117e7c2f Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:28 -0800 Subject: [PATCH] relayfs: add support for relay files in other filesystems This patch adds a couple of callback functions that allow a client to hook into relay_open()/close() and supply the files that will be used to represent the channel buffers; the default implementation if no callbacks are defined is to create the files in relayfs. This is to support the creation and use of relay files in other filesystems such as debugfs, as implied by the fact that relayfs_file_operations are exported. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/buffers.c | 2 +- fs/relayfs/relay.c | 30 ++++++++++++++++++++++++++++-- include/linux/relayfs_fs.h | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/fs/relayfs/buffers.c b/fs/relayfs/buffers.c index 667b529944c5..10187812771e 100644 --- a/fs/relayfs/buffers.c +++ b/fs/relayfs/buffers.c @@ -185,6 +185,6 @@ void relay_destroy_buf(struct rchan_buf *buf) void relay_remove_buf(struct kref *kref) { struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref); - relayfs_remove(buf->dentry); + buf->chan->cb->remove_buf_file(buf->dentry); relay_destroy_buf(buf); } diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index a9cd5585c45c..b9bb56903272 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -80,11 +80,33 @@ static void buf_unmapped_default_callback(struct rchan_buf *buf, { } +/* + * create_buf_file_create() default callback. Creates file to represent buf. + */ +static struct dentry *create_buf_file_default_callback(const char *filename, + struct dentry *parent, + int mode, + struct rchan_buf *buf) +{ + return relayfs_create_file(filename, parent, mode, + &relayfs_file_operations, buf); +} + +/* + * remove_buf_file() default callback. Removes file representing relay buffer. + */ +static int remove_buf_file_default_callback(struct dentry *dentry) +{ + return relayfs_remove(dentry); +} + /* relay channel default callbacks */ static struct rchan_callbacks default_channel_callbacks = { .subbuf_start = subbuf_start_default_callback, .buf_mapped = buf_mapped_default_callback, .buf_unmapped = buf_unmapped_default_callback, + .create_buf_file = create_buf_file_default_callback, + .remove_buf_file = remove_buf_file_default_callback, }; /** @@ -176,8 +198,8 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, return NULL; /* Create file in fs */ - dentry = relayfs_create_file(filename, parent, S_IRUSR, - &relayfs_file_operations, buf); + dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR, + buf); if (!dentry) { relay_destroy_buf(buf); return NULL; @@ -220,6 +242,10 @@ static inline void setup_callbacks(struct rchan *chan, cb->buf_mapped = buf_mapped_default_callback; if (!cb->buf_unmapped) cb->buf_unmapped = buf_unmapped_default_callback; + if (!cb->create_buf_file) + cb->create_buf_file = create_buf_file_default_callback; + if (!cb->remove_buf_file) + cb->remove_buf_file = remove_buf_file_default_callback; chan->cb = cb; } diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index 8200ecbe6e0f..8c2177105857 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -110,6 +110,40 @@ struct rchan_callbacks */ void (*buf_unmapped)(struct rchan_buf *buf, struct file *filp); + /* + * create_buf_file - create file to represent a relayfs channel buffer + * @filename: the name of the file to create + * @parent: the parent of the file to create + * @mode: the mode of the file to create + * @buf: the channel buffer + * + * Called during relay_open(), once for each per-cpu buffer, + * to allow the client to create a file to be used to + * represent the corresponding channel buffer. If the file is + * created outside of relayfs, the parent must also exist in + * that filesystem. + * + * The callback should return the dentry of the file created + * to represent the relay buffer. + * + * See Documentation/filesystems/relayfs.txt for more info. + */ + struct dentry *(*create_buf_file)(const char *filename, + struct dentry *parent, + int mode, + struct rchan_buf *buf); + + /* + * remove_buf_file - remove file representing a relayfs channel buffer + * @dentry: the dentry of the file to remove + * + * Called during relay_close(), once for each per-cpu buffer, + * to allow the client to remove a file used to represent a + * channel buffer. + * + * The callback should return 0 if successful, negative if not. + */ + int (*remove_buf_file)(struct dentry *dentry); }; /* -- cgit v1.2.3 From 03d78d11d92b5ed688bb18167b05d9d01493e175 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:29 -0800 Subject: [PATCH] relayfs: add Documentation on relay files in other filesystems Documentation update for creating relay files in other filesystems. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/relayfs.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt index 0720a049d0b8..4221b3a52e25 100644 --- a/Documentation/filesystems/relayfs.txt +++ b/Documentation/filesystems/relayfs.txt @@ -143,6 +143,8 @@ Here's a summary of the API relayfs provides to in-kernel clients: subbuf_start(buf, subbuf, prev_subbuf, prev_padding) buf_mapped(buf, filp) buf_unmapped(buf, filp) + create_buf_file(filename, parent, mode, buf) + remove_buf_file(dentry) helper functions: @@ -343,6 +345,31 @@ completely defined by the caller. See the relay-apps tarball at http://relayfs.sourceforge.net for examples of how these non-relay files are meant to be used. +Creating relay files in other filesystems +----------------------------------------- + +By default of course, relay_open() creates relay files in the relayfs +filesystem. Because relay_file_operations is exported, however, it's +also possible to create and use relay files in other pseudo-filesytems +such as debugfs. + +For this purpose, two callback functions are provided, +create_buf_file() and remove_buf_file(). create_buf_file() is called +once for each per-cpu buffer from relay_open() to allow the client to +create a file to be used to represent the corresponding buffer; if +this callback is not defined, the default implementation will create +and return a file in the relayfs filesystem to represent the buffer. +The callback should return the dentry of the file created to represent +the relay buffer. Note that the parent directory passed to +relay_open() (and passed along to the callback), if specified, must +exist in the same filesystem the new relay file is created in. If +create_buf_file() is defined, remove_buf_file() must also be defined; +it's responsible for deleting the file(s) created in create_buf_file() +and is called during relay_close(). + +See the 'exported-relayfile' examples in the relay-apps tarball for +examples of creating and using relay files in debugfs. + Misc ---- -- cgit v1.2.3 From e6c08367b8fc6dce6dfd1106f53f6ef28215b313 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:29 -0800 Subject: [PATCH] relayfs: add support for global relay buffers This patch adds the optional is_global outparam to the create_buf_file() callback. This can be used by clients to create a single global relayfs buffer instead of the default per-cpu buffers. This was suggested as being useful for certain debugging applications where it's more convenient to be able to get all the data from a single channel without having to go to the bother of dealing with per-cpu files. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/relay.c | 35 +++++++++++++++++++++++++---------- include/linux/relayfs_fs.h | 8 +++++++- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index b9bb56903272..2935a6ab8ffa 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -86,7 +86,8 @@ static void buf_unmapped_default_callback(struct rchan_buf *buf, static struct dentry *create_buf_file_default_callback(const char *filename, struct dentry *parent, int mode, - struct rchan_buf *buf) + struct rchan_buf *buf, + int *is_global) { return relayfs_create_file(filename, parent, mode, &relayfs_file_operations, buf); @@ -170,14 +171,16 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init) void relay_reset(struct rchan *chan) { unsigned int i; + struct rchan_buf *prev = NULL; if (!chan) return; for (i = 0; i < NR_CPUS; i++) { - if (!chan->buf[i]) - continue; + if (!chan->buf[i] || chan->buf[i] == prev) + break; __relay_reset(chan->buf[i], 0); + prev = chan->buf[i]; } } @@ -188,18 +191,22 @@ void relay_reset(struct rchan *chan) */ static struct rchan_buf *relay_open_buf(struct rchan *chan, const char *filename, - struct dentry *parent) + struct dentry *parent, + int *is_global) { struct rchan_buf *buf; struct dentry *dentry; + if (*is_global) + return chan->buf[0]; + buf = relay_create_buf(chan); if (!buf) return NULL; /* Create file in fs */ dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR, - buf); + buf, is_global); if (!dentry) { relay_destroy_buf(buf); return NULL; @@ -273,6 +280,7 @@ struct rchan *relay_open(const char *base_filename, unsigned int i; struct rchan *chan; char *tmpname; + int is_global = 0; if (!base_filename) return NULL; @@ -297,7 +305,8 @@ struct rchan *relay_open(const char *base_filename, for_each_online_cpu(i) { sprintf(tmpname, "%s%d", base_filename, i); - chan->buf[i] = relay_open_buf(chan, tmpname, parent); + chan->buf[i] = relay_open_buf(chan, tmpname, parent, + &is_global); chan->buf[i]->cpu = i; if (!chan->buf[i]) goto free_bufs; @@ -311,6 +320,8 @@ free_bufs: if (!chan->buf[i]) break; relay_close_buf(chan->buf[i]); + if (is_global) + break; } kfree(tmpname); @@ -420,14 +431,16 @@ void relay_destroy_channel(struct kref *kref) void relay_close(struct rchan *chan) { unsigned int i; + struct rchan_buf *prev = NULL; if (!chan) return; for (i = 0; i < NR_CPUS; i++) { - if (!chan->buf[i]) - continue; + if (!chan->buf[i] || chan->buf[i] == prev) + break; relay_close_buf(chan->buf[i]); + prev = chan->buf[i]; } if (chan->last_toobig) @@ -447,14 +460,16 @@ void relay_close(struct rchan *chan) void relay_flush(struct rchan *chan) { unsigned int i; + struct rchan_buf *prev = NULL; if (!chan) return; for (i = 0; i < NR_CPUS; i++) { - if (!chan->buf[i]) - continue; + if (!chan->buf[i] || chan->buf[i] == prev) + break; relay_switch_subbuf(chan->buf[i], 0); + prev = chan->buf[i]; } } diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index 8c2177105857..30f45511b40d 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -116,6 +116,7 @@ struct rchan_callbacks * @parent: the parent of the file to create * @mode: the mode of the file to create * @buf: the channel buffer + * @is_global: outparam - set non-zero if the buffer should be global * * Called during relay_open(), once for each per-cpu buffer, * to allow the client to create a file to be used to @@ -126,12 +127,17 @@ struct rchan_callbacks * The callback should return the dentry of the file created * to represent the relay buffer. * + * Setting the is_global outparam to a non-zero value will + * cause relay_open() to create a single global buffer rather + * than the default set of per-cpu buffers. + * * See Documentation/filesystems/relayfs.txt for more info. */ struct dentry *(*create_buf_file)(const char *filename, struct dentry *parent, int mode, - struct rchan_buf *buf); + struct rchan_buf *buf, + int *is_global); /* * remove_buf_file - remove file representing a relayfs channel buffer -- cgit v1.2.3 From df49af8f3392e96ddbc9cf6dd81fbdc0496e1b44 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:30 -0800 Subject: [PATCH] relayfs: add Documentation on global relay buffers Documentation update for creating global buffers. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/relayfs.txt | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt index 4221b3a52e25..d9693cb8602e 100644 --- a/Documentation/filesystems/relayfs.txt +++ b/Documentation/filesystems/relayfs.txt @@ -143,7 +143,7 @@ Here's a summary of the API relayfs provides to in-kernel clients: subbuf_start(buf, subbuf, prev_subbuf, prev_padding) buf_mapped(buf, filp) buf_unmapped(buf, filp) - create_buf_file(filename, parent, mode, buf) + create_buf_file(filename, parent, mode, buf, is_global) remove_buf_file(dentry) helper functions: @@ -367,6 +367,25 @@ create_buf_file() is defined, remove_buf_file() must also be defined; it's responsible for deleting the file(s) created in create_buf_file() and is called during relay_close(). +The create_buf_file() implementation can also be defined in such a way +as to allow the creation of a single 'global' buffer instead of the +default per-cpu set. This can be useful for applications interested +mainly in seeing the relative ordering of system-wide events without +the need to bother with saving explicit timestamps for the purpose of +merging/sorting per-cpu files in a postprocessing step. + +To have relay_open() create a global buffer, the create_buf_file() +implementation should set the value of the is_global outparam to a +non-zero value in addition to creating the file that will be used to +represent the single buffer. In the case of a global buffer, +create_buf_file() and remove_buf_file() will be called only once. The +normal channel-writing functions e.g. relay_write() can still be used +- writes from any cpu will transparently end up in the global buffer - +but since it is a global buffer, callers should make sure they use the +proper locking for such a buffer, either by wrapping writes in a +spinlock, or by copying a write function from relayfs_fs.h and +creating a local version that internally does the proper locking. + See the 'exported-relayfile' examples in the relay-apps tarball for examples of creating and using relay files in debugfs. -- cgit v1.2.3 From 761da5c88aca34586e5b7295bd8b9be2438906f2 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:31 -0800 Subject: [PATCH] relayfs: cleanup, change relayfs_file_* to relay_file_* This patch renames relayfs_file_operations to relay_file_operations, and the file operations themselves from relayfs_XXX to relay_file_XXX, to make it more clear that they refer to relay files. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/relayfs/inode.c | 89 ++++++++++++++++++++++++---------------------- fs/relayfs/relay.c | 2 +- include/linux/relayfs_fs.h | 5 ++- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/fs/relayfs/inode.c b/fs/relayfs/inode.c index b4c3e0466e98..7b7f2cb5f0e1 100644 --- a/fs/relayfs/inode.c +++ b/fs/relayfs/inode.c @@ -247,13 +247,13 @@ int relayfs_remove_dir(struct dentry *dentry) } /** - * relayfs_open - open file op for relayfs files + * relay_file_open - open file op for relay files * @inode: the inode * @filp: the file * * Increments the channel buffer refcount. */ -static int relayfs_open(struct inode *inode, struct file *filp) +static int relay_file_open(struct inode *inode, struct file *filp) { struct rchan_buf *buf = inode->u.generic_ip; kref_get(&buf->kref); @@ -263,26 +263,26 @@ static int relayfs_open(struct inode *inode, struct file *filp) } /** - * relayfs_mmap - mmap file op for relayfs files + * relay_file_mmap - mmap file op for relay files * @filp: the file * @vma: the vma describing what to map * * Calls upon relay_mmap_buf to map the file into user space. */ -static int relayfs_mmap(struct file *filp, struct vm_area_struct *vma) +static int relay_file_mmap(struct file *filp, struct vm_area_struct *vma) { struct rchan_buf *buf = filp->private_data; return relay_mmap_buf(buf, vma); } /** - * relayfs_poll - poll file op for relayfs files + * relay_file_poll - poll file op for relay files * @filp: the file * @wait: poll table * * Poll implemention. */ -static unsigned int relayfs_poll(struct file *filp, poll_table *wait) +static unsigned int relay_file_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0; struct rchan_buf *buf = filp->private_data; @@ -300,14 +300,14 @@ static unsigned int relayfs_poll(struct file *filp, poll_table *wait) } /** - * relayfs_release - release file op for relayfs files + * relay_file_release - release file op for relay files * @inode: the inode * @filp: the file * * Decrements the channel refcount, as the filesystem is * no longer using it. */ -static int relayfs_release(struct inode *inode, struct file *filp) +static int relay_file_release(struct inode *inode, struct file *filp) { struct rchan_buf *buf = filp->private_data; kref_put(&buf->kref, relay_remove_buf); @@ -316,11 +316,11 @@ static int relayfs_release(struct inode *inode, struct file *filp) } /** - * relayfs_read_consume - update the consumed count for the buffer + * relay_file_read_consume - update the consumed count for the buffer */ -static void relayfs_read_consume(struct rchan_buf *buf, - size_t read_pos, - size_t bytes_consumed) +static void relay_file_read_consume(struct rchan_buf *buf, + size_t read_pos, + size_t bytes_consumed) { size_t subbuf_size = buf->chan->subbuf_size; size_t n_subbufs = buf->chan->n_subbufs; @@ -343,9 +343,9 @@ static void relayfs_read_consume(struct rchan_buf *buf, } /** - * relayfs_read_avail - boolean, are there unconsumed bytes available? + * relay_file_read_avail - boolean, are there unconsumed bytes available? */ -static int relayfs_read_avail(struct rchan_buf *buf, size_t read_pos) +static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos) { size_t bytes_produced, bytes_consumed, write_offset; size_t subbuf_size = buf->chan->subbuf_size; @@ -376,16 +376,16 @@ static int relayfs_read_avail(struct rchan_buf *buf, size_t read_pos) if (bytes_produced == bytes_consumed) return 0; - relayfs_read_consume(buf, read_pos, 0); + relay_file_read_consume(buf, read_pos, 0); return 1; } /** - * relayfs_read_subbuf_avail - return bytes available in sub-buffer + * relay_file_read_subbuf_avail - return bytes available in sub-buffer */ -static size_t relayfs_read_subbuf_avail(size_t read_pos, - struct rchan_buf *buf) +static size_t relay_file_read_subbuf_avail(size_t read_pos, + struct rchan_buf *buf) { size_t padding, avail = 0; size_t read_subbuf, read_offset, write_subbuf, write_offset; @@ -407,14 +407,14 @@ static size_t relayfs_read_subbuf_avail(size_t read_pos, } /** - * relayfs_read_start_pos - find the first available byte to read + * relay_file_read_start_pos - find the first available byte to read * * If the read_pos is in the middle of padding, return the * position of the first actually available byte, otherwise * return the original value. */ -static size_t relayfs_read_start_pos(size_t read_pos, - struct rchan_buf *buf) +static size_t relay_file_read_start_pos(size_t read_pos, + struct rchan_buf *buf) { size_t read_subbuf, padding, padding_start, padding_end; size_t subbuf_size = buf->chan->subbuf_size; @@ -433,11 +433,11 @@ static size_t relayfs_read_start_pos(size_t read_pos, } /** - * relayfs_read_end_pos - return the new read position + * relay_file_read_end_pos - return the new read position */ -static size_t relayfs_read_end_pos(struct rchan_buf *buf, - size_t read_pos, - size_t count) +static size_t relay_file_read_end_pos(struct rchan_buf *buf, + size_t read_pos, + size_t count) { size_t read_subbuf, padding, end_pos; size_t subbuf_size = buf->chan->subbuf_size; @@ -456,7 +456,7 @@ static size_t relayfs_read_end_pos(struct rchan_buf *buf, } /** - * relayfs_read - read file op for relayfs files + * relay_file_read - read file op for relay files * @filp: the file * @buffer: the userspace buffer * @count: number of bytes to read @@ -465,10 +465,10 @@ static size_t relayfs_read_end_pos(struct rchan_buf *buf, * Reads count bytes or the number of bytes available in the * current sub-buffer being read, whichever is smaller. */ -static ssize_t relayfs_read(struct file *filp, - char __user *buffer, - size_t count, - loff_t *ppos) +static ssize_t relay_file_read(struct file *filp, + char __user *buffer, + size_t count, + loff_t *ppos) { struct rchan_buf *buf = filp->private_data; struct inode *inode = filp->f_dentry->d_inode; @@ -477,11 +477,11 @@ static ssize_t relayfs_read(struct file *filp, void *from; down(&inode->i_sem); - if(!relayfs_read_avail(buf, *ppos)) + if(!relay_file_read_avail(buf, *ppos)) goto out; - read_start = relayfs_read_start_pos(*ppos, buf); - avail = relayfs_read_subbuf_avail(read_start, buf); + read_start = relay_file_read_start_pos(*ppos, buf); + avail = relay_file_read_subbuf_avail(read_start, buf); if (!avail) goto out; @@ -491,20 +491,20 @@ static ssize_t relayfs_read(struct file *filp, ret = -EFAULT; goto out; } - relayfs_read_consume(buf, read_start, count); - *ppos = relayfs_read_end_pos(buf, read_start, count); + relay_file_read_consume(buf, read_start, count); + *ppos = relay_file_read_end_pos(buf, read_start, count); out: up(&inode->i_sem); return ret; } -struct file_operations relayfs_file_operations = { - .open = relayfs_open, - .poll = relayfs_poll, - .mmap = relayfs_mmap, - .read = relayfs_read, +struct file_operations relay_file_operations = { + .open = relay_file_open, + .poll = relay_file_poll, + .mmap = relay_file_mmap, + .read = relay_file_read, .llseek = no_llseek, - .release = relayfs_release, + .release = relay_file_release, }; static struct super_operations relayfs_ops = { @@ -558,13 +558,18 @@ static int __init init_relayfs_fs(void) static void __exit exit_relayfs_fs(void) { + + + + + unregister_filesystem(&relayfs_fs_type); } module_init(init_relayfs_fs) module_exit(exit_relayfs_fs) -EXPORT_SYMBOL_GPL(relayfs_file_operations); +EXPORT_SYMBOL_GPL(relay_file_operations); EXPORT_SYMBOL_GPL(relayfs_create_dir); EXPORT_SYMBOL_GPL(relayfs_remove_dir); EXPORT_SYMBOL_GPL(relayfs_create_file); diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index 2935a6ab8ffa..abf3ceaace49 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -90,7 +90,7 @@ static struct dentry *create_buf_file_default_callback(const char *filename, int *is_global) { return relayfs_create_file(filename, parent, mode, - &relayfs_file_operations, buf); + &relay_file_operations, buf); } /* diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h index 30f45511b40d..7342e66247fb 100644 --- a/include/linux/relayfs_fs.h +++ b/include/linux/relayfs_fs.h @@ -279,10 +279,9 @@ static inline void subbuf_start_reserve(struct rchan_buf *buf, } /* - * exported relayfs file operations, fs/relayfs/inode.c + * exported relay file operations, fs/relayfs/inode.c */ - -extern struct file_operations relayfs_file_operations; +extern struct file_operations relay_file_operations; #endif /* _LINUX_RELAYFS_FS_H */ -- cgit v1.2.3 From 6b34350f490b2c8508717541ec1fd2bbaadded94 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Sun, 8 Jan 2006 01:02:32 -0800 Subject: [PATCH] relayfs: Documentation cleanup, remove obsolete info librelay and relay-app.h have been retired - update Documentation to reflect that. Signed-off-by: Tom Zanussi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/relayfs.txt | 57 +++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt index d9693cb8602e..5832377b7340 100644 --- a/Documentation/filesystems/relayfs.txt +++ b/Documentation/filesystems/relayfs.txt @@ -44,30 +44,41 @@ relayfs can operate in a mode where it will overwrite data not yet collected by userspace, and not wait for it to consume it. relayfs itself does not provide for communication of such data between -userspace and kernel, allowing the kernel side to remain simple and not -impose a single interface on userspace. It does provide a separate -helper though, described below. +userspace and kernel, allowing the kernel side to remain simple and +not impose a single interface on userspace. It does provide a set of +examples and a separate helper though, described below. + +klog and relay-apps example code +================================ + +relayfs itself is ready to use, but to make things easier, a couple +simple utility functions and a set of examples are provided. + +The relay-apps example tarball, available on the relayfs sourceforge +site, contains a set of self-contained examples, each consisting of a +pair of .c files containing boilerplate code for each of the user and +kernel sides of a relayfs application; combined these two sets of +boilerplate code provide glue to easily stream data to disk, without +having to bother with mundane housekeeping chores. + +The 'klog debugging functions' patch (klog.patch in the relay-apps +tarball) provides a couple of high-level logging functions to the +kernel which allow writing formatted text or raw data to a channel, +regardless of whether a channel to write into exists or not, or +whether relayfs is compiled into the kernel or is configured as a +module. These functions allow you to put unconditional 'trace' +statements anywhere in the kernel or kernel modules; only when there +is a 'klog handler' registered will data actually be logged (see the +klog and kleak examples for details). + +It is of course possible to use relayfs from scratch i.e. without +using any of the relay-apps example code or klog, but you'll have to +implement communication between userspace and kernel, allowing both to +convey the state of buffers (full, empty, amount of padding). + +klog and the relay-apps examples can be found in the relay-apps +tarball on http://relayfs.sourceforge.net -klog, relay-app & librelay -========================== - -relayfs itself is ready to use, but to make things easier, two -additional systems are provided. klog is a simple wrapper to make -writing formatted text or raw data to a channel simpler, regardless of -whether a channel to write into exists or not, or whether relayfs is -compiled into the kernel or is configured as a module. relay-app is -the kernel counterpart of userspace librelay.c, combined these two -files provide glue to easily stream data to disk, without having to -bother with housekeeping. klog and relay-app can be used together, -with klog providing high-level logging functions to the kernel and -relay-app taking care of kernel-user control and disk-logging chores. - -It is possible to use relayfs without relay-app & librelay, but you'll -have to implement communication between userspace and kernel, allowing -both to convey the state of buffers (full, empty, amount of padding). - -klog, relay-app and librelay can be found in the relay-apps tarball on -http://relayfs.sourceforge.net The relayfs user space API ========================== -- cgit v1.2.3 From 6b9c7ed84837753a436415097063232422e29a35 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jan 2006 01:02:33 -0800 Subject: [PATCH] use ptrace_get_task_struct in various places The ptrace_get_task_struct() helper that I added as part of the ptrace consolidation is useful in variety of places that currently opencode it. Switch them to the common helpers. Add a ptrace_traceme() helper that needs to be explicitly called, and simplify the ptrace_get_task_struct() interface. We don't need the request argument now, and we return the task_struct directly, using ERR_PTR() for error returns. It's a bit more code in the callers, but we have two sane routines that do one thing well now. Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/ptrace.c | 24 +++---------- arch/ia64/ia32/sys_ia32.c | 16 +++------ arch/ia64/kernel/ptrace.c | 9 +---- arch/m32r/kernel/ptrace.c | 22 +++--------- arch/mips/kernel/ptrace32.c | 26 ++++---------- arch/powerpc/kernel/ptrace32.c | 28 ++++----------- arch/s390/kernel/ptrace.c | 29 ++++------------ arch/sparc/kernel/ptrace.c | 35 ++++--------------- arch/sparc64/kernel/ptrace.c | 34 +++---------------- arch/x86_64/ia32/ptrace32.c | 44 ++++++------------------ include/linux/ptrace.h | 2 ++ kernel/ptrace.c | 77 +++++++++++++++++++++++++----------------- 12 files changed, 105 insertions(+), 241 deletions(-) diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index bbd37536d14e..9969d212e94d 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -265,30 +265,16 @@ do_sys_ptrace(long request, long pid, long addr, long data, lock_kernel(); DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n", request, pid, addr, data)); - ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out_notsk; - ret = security_ptrace(current->parent, current); - if (ret) - goto out_notsk; - /* set the ptrace bit in the process ptrace flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); goto out_notsk; } - if (pid == 1) /* you may not mess with init */ - goto out_notsk; - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out_notsk; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index dc282710421a..9f8e8d558873 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -1761,21 +1761,15 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data) lock_kernel(); if (request == PTRACE_TRACEME) { - ret = sys_ptrace(request, pid, addr, data); + ret = ptrace_traceme(); goto out; } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; - ret = -EPERM; - if (pid == 1) /* no messing around with init! */ - goto out_tsk; + } if (request == PTRACE_ATTACH) { ret = sys_ptrace(request, pid, addr, data); diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 4b19d0410632..8d88eeea02d1 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1422,14 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) lock_kernel(); ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); goto out; } diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 078d2a0e71c2..9b75caaf5cec 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -762,28 +762,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) int ret; lock_kernel(); - ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); goto out; } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 9a9b04972132..7e55457a491f 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -57,30 +57,16 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) (unsigned long) data); #endif lock_kernel(); - ret = -EPERM; if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - if ((ret = security_ptrace(current->parent, current))) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); goto out; } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 61762640b877..826ee3d056de 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -45,33 +45,19 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, unsigned long data) { struct task_struct *child; - int ret = -EPERM; + int ret; lock_kernel(); if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; + ret = ptrace_traceme(); goto out; } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 8ecda6d66de4..cc02232aa96e 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -712,35 +712,18 @@ sys_ptrace(long request, long pid, long addr, long data) int ret; lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - ret = -EPERM; - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - goto out; + ret = ptrace_traceme(); + goto out; } - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out; - - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; + } ret = do_ptrace(child, request, addr, data); - put_task_struct(child); out: unlock_kernel(); diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 475c4c13462c..fc470c0e9dc6 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -286,40 +286,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) s, (int) request, (int) pid, addr, data, addr2); } #endif - if (request == PTRACE_TRACEME) { - int my_ret; - - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) { - pt_error_return(regs, EPERM); - goto out; - } - my_ret = security_ptrace(current->parent, current); - if (my_ret) { - pt_error_return(regs, -my_ret); - goto out; - } - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); pt_succ_return(regs, 0); goto out; } -#ifndef ALLOW_INIT_TRACING - if (pid == 1) { - /* Can't dork with init. */ - pt_error_return(regs, EPERM); - goto out; - } -#endif - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) { - pt_error_return(regs, ESRCH); + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + pt_error_return(regs, -ret); goto out; } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 774ecbb8a031..84d3df2264cb 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -198,39 +198,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } #endif if (request == PTRACE_TRACEME) { - int ret; - - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) { - pt_error_return(regs, EPERM); - goto out; - } - ret = security_ptrace(current->parent, current); - if (ret) { - pt_error_return(regs, -ret); - goto out; - } - - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; + ret = ptrace_traceme(); pt_succ_return(regs, 0); goto out; } -#ifndef ALLOW_INIT_TRACING - if (pid == 1) { - /* Can't dork with init. */ - pt_error_return(regs, EPERM); - goto out; - } -#endif - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) { - pt_error_return(regs, ESRCH); + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + pt_error_return(regs, -ret); goto out; } diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index 2a925e2af390..5f4cdfa56901 100644 --- a/arch/x86_64/ia32/ptrace32.c +++ b/arch/x86_64/ia32/ptrace32.c @@ -196,36 +196,6 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val) #undef R32 -static struct task_struct *find_target(int request, int pid, int *err) -{ - struct task_struct *child; - - *err = -EPERM; - if (pid == 1) - return NULL; - - *err = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (child) { - *err = -EPERM; - if (child->pid == 1) - goto out; - *err = ptrace_check_attach(child, request == PTRACE_KILL); - if (*err < 0) - goto out; - return child; - } - out: - if (child) - put_task_struct(child); - return NULL; - -} - asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) { struct task_struct *child; @@ -254,9 +224,16 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) break; } - child = find_target(request, pid, &ret); - if (!child) - return ret; + if (request == PTRACE_TRACEME) + return ptrace_traceme(); + + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) + return PTR_ERR(child); + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out; childregs = (struct pt_regs *)(child->thread.rsp0 - sizeof(struct pt_regs)); @@ -373,6 +350,7 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) break; } + out: put_task_struct(child); return ret; } diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index b2b3dba1298d..864791996b5f 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -80,6 +80,8 @@ extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); +extern struct task_struct *ptrace_get_task_struct(pid_t pid); +extern int ptrace_traceme(void); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); extern int ptrace_attach(struct task_struct *tsk); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 656476eedb1b..cceaf09ac413 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -408,54 +408,62 @@ int ptrace_request(struct task_struct *child, long request, return ret; } -#ifndef __ARCH_SYS_PTRACE -static int ptrace_get_task_struct(long request, long pid, - struct task_struct **childp) +/** + * ptrace_traceme -- helper for PTRACE_TRACEME + * + * Performs checks and sets PT_PTRACED. + * Should be used by all ptrace implementations for PTRACE_TRACEME. + */ +int ptrace_traceme(void) { - struct task_struct *child; int ret; /* - * Callers use child == NULL as an indication to exit early even - * when the return value is 0, so make sure it is non-NULL here. + * Are we already being traced? + */ + if (current->ptrace & PT_PTRACED) + return -EPERM; + ret = security_ptrace(current->parent, current); + if (ret) + return -EPERM; + /* + * Set the ptrace bit in the process ptrace flags. */ - *childp = NULL; + current->ptrace |= PT_PTRACED; + return 0; +} - if (request == PTRACE_TRACEME) { - /* - * Are we already being traced? - */ - if (current->ptrace & PT_PTRACED) - return -EPERM; - ret = security_ptrace(current->parent, current); - if (ret) - return -EPERM; - /* - * Set the ptrace bit in the process ptrace flags. - */ - current->ptrace |= PT_PTRACED; - return 0; - } +/** + * ptrace_get_task_struct -- grab a task struct reference for ptrace + * @pid: process id to grab a task_struct reference of + * + * This function is a helper for ptrace implementations. It checks + * permissions and then grabs a task struct for use of the actual + * ptrace implementation. + * + * Returns the task_struct for @pid or an ERR_PTR() on failure. + */ +struct task_struct *ptrace_get_task_struct(pid_t pid) +{ + struct task_struct *child; /* - * You may not mess with init + * Tracing init is not allowed. */ if (pid == 1) - return -EPERM; + return ERR_PTR(-EPERM); - ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); if (child) get_task_struct(child); read_unlock(&tasklist_lock); if (!child) - return -ESRCH; - - *childp = child; - return 0; + return ERR_PTR(-ESRCH); + return child; } +#ifndef __ARCH_SYS_PTRACE asmlinkage long sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -465,9 +473,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) * This lock_kernel fixes a subtle race with suid exec */ lock_kernel(); - ret = ptrace_get_task_struct(request, pid, &child); - if (!child) + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); goto out; + } + + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); -- cgit v1.2.3 From b8b0af24353eafadf58a0889999700e43f135aad Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jan 2006 01:02:33 -0800 Subject: [PATCH] udf: remove bogus inode == NULL check in inode_bmap inode can never be NULL when calling this function. Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/inode.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 4014f17d382e..395e582ee542 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1957,11 +1957,6 @@ int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t printk(KERN_ERR "udf: inode_bmap: block < 0\n"); return -1; } - if (!inode) - { - printk(KERN_ERR "udf: inode_bmap: NULL inode\n"); - return -1; - } *extoffset = 0; *elen = 0; -- cgit v1.2.3 From 954de9141e75cf2f1ce69ccdbedc83ec827a01ec Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 8 Jan 2006 01:02:34 -0800 Subject: [PATCH] vgacon: fix doublescan mode When doublescan mode is in use, scanlines must be doubled. Thanks to Jason Dravet for reporting and testing. Signed-off-by: Samuel Thibault Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/vgacon.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 167de397e4b4..f4e1c4b4191e 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -503,10 +503,16 @@ static int vgacon_doresize(struct vc_data *c, { unsigned long flags; unsigned int scanlines = height * c->vc_font.height; - u8 scanlines_lo, r7, vsync_end, mode; + u8 scanlines_lo, r7, vsync_end, mode, max_scan; spin_lock_irqsave(&vga_lock, flags); + outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg); + max_scan = inb_p(vga_video_port_val); + + if (max_scan & 0x80) + scanlines <<= 1; + outb_p(VGA_CRTC_MODE, vga_video_port_reg); mode = inb_p(vga_video_port_val); -- cgit v1.2.3 From 53dbb26dbcf0d844967677633d7587c1d34740d5 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Sun, 8 Jan 2006 01:02:36 -0800 Subject: [PATCH] vgacon: Workaround for resize bug in some chipsets Reported from Redhat Bugzilla Bug 170450 "I updated to the development kernel and now during boot only the top of the text is visable. For example the monitor screen the is the lines and I can only see text in the asterisk area. --- drivers/video/console/vgacon.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f4e1c4b4191e..12d9329d1408 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -56,6 +56,8 @@ static DEFINE_SPINLOCK(vga_lock); static int cursor_size_lastfrom; static int cursor_size_lastto; +static u32 vgacon_xres; +static u32 vgacon_yres; static struct vgastate state; #define BLANK 0x0020 @@ -69,7 +71,7 @@ static struct vgastate state; * appear. */ #undef TRIDENT_GLITCH - +#define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */ /* * Interface used by the world */ @@ -325,6 +327,10 @@ static const char __init *vgacon_startup(void) vga_scan_lines = vga_video_font_height * vga_video_num_lines; } + + vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; + vgacon_yres = vga_scan_lines; + return display_desc; } @@ -513,6 +519,8 @@ static int vgacon_doresize(struct vc_data *c, if (max_scan & 0x80) scanlines <<= 1; + vgacon_xres = width * VGA_FONTWIDTH; + vgacon_yres = height * c->vc_font.height; outb_p(VGA_CRTC_MODE, vga_video_port_reg); mode = inb_p(vga_video_port_val); @@ -557,6 +565,10 @@ static int vgacon_doresize(struct vc_data *c, static int vgacon_switch(struct vc_data *c) { + int x = c->vc_cols * VGA_FONTWIDTH; + int y = c->vc_rows * c->vc_font.height; + int rows = ORIG_VIDEO_LINES * vga_default_font_height/ + c->vc_font.height; /* * We need to save screen size here as it's the only way * we can spot the screen has been resized and we need to @@ -572,10 +584,11 @@ static int vgacon_switch(struct vc_data *c) scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); - if (!(vga_video_num_columns % 2) && - vga_video_num_columns <= ORIG_VIDEO_COLS && - vga_video_num_lines <= (ORIG_VIDEO_LINES * - vga_default_font_height) / c->vc_font.height) + + if ((vgacon_xres != x || vgacon_yres != y) && + (!(vga_video_num_columns % 2) && + vga_video_num_columns <= ORIG_VIDEO_COLS && + vga_video_num_lines <= rows)) vgacon_doresize(c, c->vc_cols, c->vc_rows); } @@ -999,7 +1012,8 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigne if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; - if (font->width != 8 || (charcount != 256 && charcount != 512)) + if (font->width != VGA_FONTWIDTH || + (charcount != 256 && charcount != 512)) return -EINVAL; rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512); @@ -1016,7 +1030,7 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; - font->width = 8; + font->width = VGA_FONTWIDTH; font->height = c->vc_font.height; font->charcount = vga_512_chars ? 512 : 256; if (!font->data) -- cgit v1.2.3 From 788540141f4549637e89aadca6e25cf25eb53383 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:02:37 -0800 Subject: [PATCH] Permit multiple inclusion of linux/pagevec.h Make it possible to include linux/pagevec.h multiple times without incurring errors due to duplicate definitions. Signed-off-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pagevec.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/pagevec.h b/include/linux/pagevec.h index def32c5715be..8eb7fa76c1d0 100644 --- a/include/linux/pagevec.h +++ b/include/linux/pagevec.h @@ -5,6 +5,9 @@ * pages. A pagevec is a multipage container which is used for that. */ +#ifndef _LINUX_PAGEVEC_H +#define _LINUX_PAGEVEC_H + /* 14 pointers + two long's align the pagevec structure to a power of two */ #define PAGEVEC_SIZE 14 @@ -83,3 +86,5 @@ static inline void pagevec_lru_add(struct pagevec *pvec) if (pagevec_count(pvec)) __pagevec_lru_add(pvec); } + +#endif /* _LINUX_PAGEVEC_H */ -- cgit v1.2.3 From 4a30131e7dbb17e5fec6958bfac9da9aff1fa29b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 8 Jan 2006 01:02:39 -0800 Subject: [PATCH] Fix some problems with truncate and mtime semantics. SUS requires that when truncating a file to the size that it currently is: truncate and ftruncate should NOT modify ctime or mtime O_TRUNC SHOULD modify ctime and mtime. Currently mtime and ctime are always modified on most local filesystems (side effect of ->truncate) or never modified (on NFS). With this patch: ATTR_CTIME|ATTR_MTIME are sent with ATTR_SIZE precisely when an update of these times is required whether size changes or not (via a new argument to do_truncate). This allows NFS to do the right thing for O_TRUNC. inode_setattr nolonger forces ATTR_MTIME|ATTR_CTIME when the ATTR_SIZE sets the size to it's current value. This allows local filesystems to do the right thing for f?truncate. Also, the logic in inode_setattr is changed a bit so there are two return points. One returns the error from vmtruncate if it failed, the other returns 0 (there can be no other failure). Finally, if vmtruncate succeeds, and ATTR_SIZE is the only change requested, we now fall-through and mark_inode_dirty. If a filesystem did not have a ->truncate function, then vmtruncate will have changed i_size, without marking the inode as 'dirty', and I think this is wrong. Signed-off-by: Neil Brown Cc: Christoph Hellwig Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/attr.c | 24 ++++++++---------------- fs/exec.c | 2 +- fs/namei.c | 2 +- fs/open.c | 9 +++++---- include/linux/fs.h | 3 ++- 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 67bcd9b14ea5..b34732506f1d 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -67,20 +67,12 @@ EXPORT_SYMBOL(inode_change_ok); int inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; - int error = 0; - - if (ia_valid & ATTR_SIZE) { - if (attr->ia_size != i_size_read(inode)) { - error = vmtruncate(inode, attr->ia_size); - if (error || (ia_valid == ATTR_SIZE)) - goto out; - } else { - /* - * We skipped the truncate but must still update - * timestamps - */ - ia_valid |= ATTR_MTIME|ATTR_CTIME; - } + + if (ia_valid & ATTR_SIZE && + attr->ia_size != i_size_read(inode)) { + int error = vmtruncate(inode, attr->ia_size); + if (error) + return error; } if (ia_valid & ATTR_UID) @@ -104,8 +96,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr) inode->i_mode = mode; } mark_inode_dirty(inode); -out: - return error; + + return 0; } EXPORT_SYMBOL(inode_setattr); diff --git a/fs/exec.c b/fs/exec.c index e9650cd22a3b..2075b674d85e 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1505,7 +1505,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) goto close_fail; if (!file->f_op->write) goto close_fail; - if (do_truncate(file->f_dentry, 0, file) != 0) + if (do_truncate(file->f_dentry, 0, 0, file) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file); diff --git a/fs/namei.c b/fs/namei.c index 6dbbd42d8b95..300eae088d5f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1491,7 +1491,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) if (!error) { DQUOT_INIT(inode); - error = do_truncate(dentry, 0, NULL); + error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL); } put_write_access(inode); if (error) diff --git a/fs/open.c b/fs/open.c index f53a5b9ffb7d..94968cb3afca 100644 --- a/fs/open.c +++ b/fs/open.c @@ -194,7 +194,8 @@ out: return error; } -int do_truncate(struct dentry *dentry, loff_t length, struct file *filp) +int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + struct file *filp) { int err; struct iattr newattrs; @@ -204,7 +205,7 @@ int do_truncate(struct dentry *dentry, loff_t length, struct file *filp) return -EINVAL; newattrs.ia_size = length; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + newattrs.ia_valid = ATTR_SIZE | time_attrs; if (filp) { newattrs.ia_file = filp; newattrs.ia_valid |= ATTR_FILE; @@ -266,7 +267,7 @@ static inline long do_sys_truncate(const char __user * path, loff_t length) error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(nd.dentry, length, NULL); + error = do_truncate(nd.dentry, length, 0, NULL); } put_write_access(inode); @@ -318,7 +319,7 @@ static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small) error = locks_verify_truncate(inode, file, length); if (!error) - error = do_truncate(dentry, length, file); + error = do_truncate(dentry, length, 0, file); out_putf: fput(file); out: diff --git a/include/linux/fs.h b/include/linux/fs.h index ef29500b5df8..74c01aabd4ab 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1344,7 +1344,8 @@ static inline int break_lease(struct inode *inode, unsigned int mode) /* fs/open.c */ -extern int do_truncate(struct dentry *, loff_t start, struct file *filp); +extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, + struct file *filp); extern long do_sys_open(const char __user *filename, int flags, int mode); extern struct file *filp_open(const char *, int, int); extern struct file * dentry_open(struct dentry *, struct vfsmount *, int); -- cgit v1.2.3 From 2520f14ca85e38f575eed6acc6e586df246abea6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 8 Jan 2006 01:02:40 -0800 Subject: [PATCH] Fix overflow tests for compat_sys_fcntl64 locking When making an fctl locking call through compat_sys_fcntl64 (i.e. a 32bit app on a 64bit kernel), the syscall can return a locking range that is in conflict with the queried lock. If some aspect of this range does not fit in the 32bit structure, something needs to be done. The current code is wrong in several respects: - It returns data to userspace even if no conflict was found i.e. it should check l_type for F_UNLCK - It returns -EOVERFLOW too agressively. A lock range covering the last possible byte of the file (start = COMPAT_OFF_T_MAX, len = 1) should be possible, but is rejected with the current test. - A extra-long 'len' should not be a problem. If only that part of the conflicting lock that would be visible to the 32bit app needs to be reported to the 32bit app anyway. This patch addresses those three issues and adds a comment to (hopefully) record it for posterity. Note: this patch mainly affects test-cases. Real applications rarely is ever see the problems. This patch has been tested (LSB test suite), and works. Signed-off-by: Neil Brown Cc: Arnd Bergmann Cc: Christoph Hellwig Cc: Matthew Wilcox Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/compat.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/fs/compat.c b/fs/compat.c index 55ac0324aaf1..271b75d1597f 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -494,9 +494,21 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs(old_fs); if (cmd == F_GETLK && ret == 0) { - if ((f.l_start >= COMPAT_OFF_T_MAX) || - ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX)) + /* GETLK was successfule and we need to return the data... + * but it needs to fit in the compat structure. + * l_start shouldn't be too big, unless the original + * start + end is greater than COMPAT_OFF_T_MAX, in which + * case the app was asking for trouble, so we return + * -EOVERFLOW in that case. + * l_len could be too big, in which case we just truncate it, + * and only allow the app to see that part of the conflicting + * lock that might make sense to it anyway + */ + + if (f.l_start > COMPAT_OFF_T_MAX) ret = -EOVERFLOW; + if (f.l_len > COMPAT_OFF_T_MAX) + f.l_len = COMPAT_OFF_T_MAX; if (ret == 0) ret = put_compat_flock(&f, compat_ptr(arg)); } @@ -515,9 +527,11 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, (unsigned long)&f); set_fs(old_fs); if (cmd == F_GETLK64 && ret == 0) { - if ((f.l_start >= COMPAT_LOFF_T_MAX) || - ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX)) + /* need to return lock information - see above for commentary */ + if (f.l_start > COMPAT_LOFF_T_MAX) ret = -EOVERFLOW; + if (f.l_len > COMPAT_LOFF_T_MAX) + f.l_len = COMPAT_LOFF_T_MAX; if (ret == 0) ret = put_compat_flock64(&f, compat_ptr(arg)); } -- cgit v1.2.3 From 025510cd20f4c35c3958bea133d96c9bd7c6ef9e Mon Sep 17 00:00:00 2001 From: Guillaume Chazarain Date: Sun, 8 Jan 2006 01:02:41 -0800 Subject: [PATCH] printk return value: fix it What's the true meaning of the printk return value? Should it include the priority prefix length of 3? and what about the timing information? In both cases it was broken: strace -e write echo 1 > /dev/kmsg => write(1, "1\n", 2) = 5 strace -e write echo "<1>1" > /dev/kmsg => write(1, "<1>1\n", 5) = 8 The returned length was "length of input string + 3", I made it "length of string output to the log buffer". Note that I couldn't find any printk caller in the kernel interested by its return value besides kmsg_write. Signed-off-by: Guillaume Chazarain Acked-By: Tim Bird Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/printk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/printk.c b/kernel/printk.c index 5287be83e3e7..2251be80cd22 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -569,7 +569,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) p[1] <= '7' && p[2] == '>') { loglev_char = p[1]; p += 3; - printed_len += 3; + printed_len -= 3; } else { loglev_char = default_message_loglevel + '0'; @@ -584,7 +584,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) for (tp = tbuf; tp < tbuf + tlen; tp++) emit_log_char(*tp); - printed_len += tlen - 3; + printed_len += tlen; } else { if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { @@ -592,8 +592,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) emit_log_char(default_message_loglevel + '0'); emit_log_char('>'); + printed_len += 3; } - printed_len += 3; } log_level_unknown = 0; if (!*p) -- cgit v1.2.3 From cd140a5c1f456f50897af4a2e9a23d228a5fe719 Mon Sep 17 00:00:00 2001 From: Guillaume Chazarain Date: Sun, 8 Jan 2006 01:02:43 -0800 Subject: [PATCH] kmsg_write: don't return printk return value kmsg_write returns with printk, so some programs may be confused by a successful write() with a return value different than the buffer length. # /bin/echo something > /dev/kmsg /bin/echo: write error: Inappropriate ioctl for device The drawbacks is that the printk return value can no more be quickly checked from userspace. Signed-off-by: Guillaume Chazarain Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 91dd669273e0..a85f3a361442 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -817,7 +817,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { char *tmp; - int ret; + ssize_t ret; tmp = kmalloc(count + 1, GFP_KERNEL); if (tmp == NULL) @@ -826,6 +826,9 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf, if (!copy_from_user(tmp, buf, count)) { tmp[count] = 0; ret = printk("%s", tmp); + if (ret > count) + /* printk can add a prefix */ + ret = count; } kfree(tmp); return ret; -- cgit v1.2.3 From 017679c4d45783158dba1dd6f79e712c22bb3d9a Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:02:43 -0800 Subject: [PATCH] keys: Permit key expiry time to be set Add a new keyctl function that allows the expiry time to be set on a key or removed from a key, provided the caller has attribute modification access. Signed-off-by: David Howells Cc: Trond Myklebust Cc: Alexander Zangerl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/keys.txt | 15 ++++++++++++++- include/linux/keyctl.h | 1 + security/keys/compat.c | 3 +++ security/keys/internal.h | 1 + security/keys/keyctl.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 6304db59bfe4..c17c4ca74302 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -498,7 +498,7 @@ The keyctl syscall functions are: keyring is full, error ENFILE will result. The link procedure checks the nesting of the keyrings, returning ELOOP if - it appears to deep or EDEADLK if the link would introduce a cycle. + it appears too deep or EDEADLK if the link would introduce a cycle. (*) Unlink a key or keyring from another keyring: @@ -628,6 +628,19 @@ The keyctl syscall functions are: there is one, otherwise the user default session keyring. + (*) Set the timeout on a key. + + long keyctl(KEYCTL_SET_TIMEOUT, key_serial_t key, unsigned timeout); + + This sets or clears the timeout on a key. The timeout can be 0 to clear + the timeout or a number of seconds to set the expiry time that far into + the future. + + The process must have attribute modification access on a key to set its + timeout. Timeouts may not be set with this function on negative, revoked + or expired keys. + + =============== KERNEL SERVICES =============== diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index 8d7c59a29e09..ec8f3d622a8d 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h @@ -46,5 +46,6 @@ #define KEYCTL_INSTANTIATE 12 /* instantiate a partially constructed key */ #define KEYCTL_NEGATE 13 /* negate a partially constructed key */ #define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */ +#define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ #endif /* _LINUX_KEYCTL_H */ diff --git a/security/keys/compat.c b/security/keys/compat.c index 3303673c636e..e8e7ef4a290c 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -74,6 +74,9 @@ asmlinkage long compat_sys_keyctl(u32 option, case KEYCTL_SET_REQKEY_KEYRING: return keyctl_set_reqkey_keyring(arg2); + case KEYCTL_SET_TIMEOUT: + return keyctl_set_timeout(arg2, arg3); + default: return -EOPNOTSUPP; } diff --git a/security/keys/internal.h b/security/keys/internal.h index 39cba97c5eb9..51f37c0bdb32 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -136,6 +136,7 @@ extern long keyctl_instantiate_key(key_serial_t, const void __user *, size_t, key_serial_t); extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); extern long keyctl_set_reqkey_keyring(int); +extern long keyctl_set_timeout(key_serial_t, unsigned); /* diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index b7a468fabdf9..299f0ae11cf0 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -965,6 +965,46 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) } /* end keyctl_set_reqkey_keyring() */ +/*****************************************************************************/ +/* + * set or clear the timeout for a key + */ +long keyctl_set_timeout(key_serial_t id, unsigned timeout) +{ + struct timespec now; + struct key *key; + key_ref_t key_ref; + time_t expiry; + long ret; + + key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); + goto error; + } + + key = key_ref_to_ptr(key_ref); + + /* make the changes with the locks held to prevent races */ + down_write(&key->sem); + + expiry = 0; + if (timeout > 0) { + now = current_kernel_time(); + expiry = now.tv_sec + timeout; + } + + key->expiry = expiry; + + up_write(&key->sem); + key_put(key); + + ret = 0; +error: + return ret; + +} /* end keyctl_set_timeout() */ + /*****************************************************************************/ /* * the key control system call @@ -1038,6 +1078,10 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, case KEYCTL_SET_REQKEY_KEYRING: return keyctl_set_reqkey_keyring(arg2); + case KEYCTL_SET_TIMEOUT: + return keyctl_set_timeout((key_serial_t) arg2, + (unsigned) arg3); + default: return -EOPNOTSUPP; } -- cgit v1.2.3 From cab8eb594e84b434d20412fc5a3985b0bee3ab9f Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:02:45 -0800 Subject: [PATCH] keys: Discard duplicate keys from a keyring on link Cause any links within a keyring to keys that match a key to be linked into that keyring to be discarded as a link to the new key is added. The match is contingent on the type and description strings being the same. This permits requests, adds and searches to displace negative, expired, revoked and dead keys easily. After some discussion it was concluded that duplicate valid keys should probably be discarded also as they would otherwise hide the new key. Since request_key() is intended to be the primary method by which keys are added to a keyring, duplicate valid keys wouldn't be an issue there as that function would return an existing match in preference to creating a new key. Signed-off-by: David Howells Cc: Trond Myklebust Cc: Alexander Zangerl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/keys.txt | 4 +++ security/keys/keyring.c | 87 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/Documentation/keys.txt b/Documentation/keys.txt index c17c4ca74302..eeda00f82d2c 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -500,6 +500,10 @@ The keyctl syscall functions are: The link procedure checks the nesting of the keyrings, returning ELOOP if it appears too deep or EDEADLK if the link would introduce a cycle. + Any links within the keyring to keys that match the new key in terms of + type and description will be discarded from the keyring as the new one is + added. + (*) Unlink a key or keyring from another keyring: diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 5d22c0388b32..09d92d52ef75 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -682,17 +682,33 @@ static void keyring_link_rcu_disposal(struct rcu_head *rcu) } /* end keyring_link_rcu_disposal() */ +/*****************************************************************************/ +/* + * dispose of a keyring list after the RCU grace period, freeing the unlinked + * key + */ +static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) +{ + struct keyring_list *klist = + container_of(rcu, struct keyring_list, rcu); + + key_put(klist->keys[klist->delkey]); + kfree(klist); + +} /* end keyring_unlink_rcu_disposal() */ + /*****************************************************************************/ /* * link a key into to a keyring * - must be called with the keyring's semaphore write-locked + * - discard already extant link to matching key if there is one */ int __key_link(struct key *keyring, struct key *key) { struct keyring_list *klist, *nklist; unsigned max; size_t size; - int ret; + int loop, ret; ret = -EKEYREVOKED; if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) @@ -714,6 +730,48 @@ int __key_link(struct key *keyring, struct key *key) goto error2; } + /* see if there's a matching key we can displace */ + klist = keyring->payload.subscriptions; + + if (klist && klist->nkeys > 0) { + struct key_type *type = key->type; + + for (loop = klist->nkeys - 1; loop >= 0; loop--) { + if (klist->keys[loop]->type == type && + strcmp(klist->keys[loop]->description, + key->description) == 0 + ) { + /* found a match - replace with new key */ + size = sizeof(struct key *) * klist->maxkeys; + size += sizeof(*klist); + BUG_ON(size > PAGE_SIZE); + + ret = -ENOMEM; + nklist = kmalloc(size, GFP_KERNEL); + if (!nklist) + goto error2; + + memcpy(nklist, klist, size); + + /* replace matched key */ + atomic_inc(&key->usage); + nklist->keys[loop] = key; + + rcu_assign_pointer( + keyring->payload.subscriptions, + nklist); + + /* dispose of the old keyring list and the + * displaced key */ + klist->delkey = loop; + call_rcu(&klist->rcu, + keyring_unlink_rcu_disposal); + + goto done; + } + } + } + /* check that we aren't going to overrun the user's quota */ ret = key_payload_reserve(keyring, keyring->datalen + KEYQUOTA_LINK_BYTES); @@ -730,8 +788,6 @@ int __key_link(struct key *keyring, struct key *key) smp_wmb(); klist->nkeys++; smp_wmb(); - - ret = 0; } else { /* grow the key list */ @@ -769,16 +825,16 @@ int __key_link(struct key *keyring, struct key *key) /* dispose of the old keyring list */ if (klist) call_rcu(&klist->rcu, keyring_link_rcu_disposal); - - ret = 0; } - error2: +done: + ret = 0; +error2: up_write(&keyring_serialise_link_sem); - error: +error: return ret; - error3: +error3: /* undo the quota changes */ key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES); @@ -807,21 +863,6 @@ int key_link(struct key *keyring, struct key *key) EXPORT_SYMBOL(key_link); -/*****************************************************************************/ -/* - * dispose of a keyring list after the RCU grace period, freeing the unlinked - * key - */ -static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) -{ - struct keyring_list *klist = - container_of(rcu, struct keyring_list, rcu); - - key_put(klist->keys[klist->delkey]); - kfree(klist); - -} /* end keyring_unlink_rcu_disposal() */ - /*****************************************************************************/ /* * unlink the first link to a key from a keyring -- cgit v1.2.3 From b5f545c880a2a47947ba2118b2509644ab7a2969 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 8 Jan 2006 01:02:47 -0800 Subject: [PATCH] keys: Permit running process to instantiate keys Make it possible for a running process (such as gssapid) to be able to instantiate a key, as was requested by Trond Myklebust for NFS4. The patch makes the following changes: (1) A new, optional key type method has been added. This permits a key type to intercept requests at the point /sbin/request-key is about to be spawned and do something else with them - passing them over the rpc_pipefs files or netlink sockets for instance. The uninstantiated key, the authorisation key and the intended operation name are passed to the method. (2) The callout_info is no longer passed as an argument to /sbin/request-key to prevent unauthorised viewing of this data using ps or by looking in /proc/pid/cmdline. This means that the old /sbin/request-key program will not work with the patched kernel as it will expect to see an extra argument that is no longer there. A revised keyutils package will be made available tomorrow. (3) The callout_info is now attached to the authorisation key. Reading this key will retrieve the information. (4) A new field has been added to the task_struct. This holds the authorisation key currently active for a thread. Searches now look here for the caller's set of keys rather than looking for an auth key in the lowest level of the session keyring. This permits a thread to be servicing multiple requests at once and to switch between them. Note that this is per-thread, not per-process, and so is usable in multithreaded programs. The setting of this field is inherited across fork and exec. (5) A new keyctl function (KEYCTL_ASSUME_AUTHORITY) has been added that permits a thread to assume the authority to deal with an uninstantiated key. Assumption is only permitted if the authorisation key associated with the uninstantiated key is somewhere in the thread's keyrings. This function can also clear the assumption. (6) A new magic key specifier has been added to refer to the currently assumed authorisation key (KEY_SPEC_REQKEY_AUTH_KEY). (7) Instantiation will only proceed if the appropriate authorisation key is assumed first. The assumed authorisation key is discarded if instantiation is successful. (8) key_validate() is moved from the file of request_key functions to the file of permissions functions. (9) The documentation is updated. From: Build fix. Signed-off-by: David Howells Cc: Trond Myklebust Cc: Alexander Zangerl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/keys-request-key.txt | 22 +++-- Documentation/keys.txt | 24 +++++ include/linux/key.h | 12 +++ include/linux/keyctl.h | 2 + include/linux/sched.h | 1 + security/keys/compat.c | 3 + security/keys/internal.h | 4 +- security/keys/keyctl.c | 107 ++++++++++++++++----- security/keys/keyring.c | 45 --------- security/keys/permission.c | 32 +++++++ security/keys/process_keys.c | 71 +++++++------- security/keys/request_key.c | 108 ++++++++++----------- security/keys/request_key_auth.c | 192 ++++++++++++++++++++++--------------- 13 files changed, 378 insertions(+), 245 deletions(-) diff --git a/Documentation/keys-request-key.txt b/Documentation/keys-request-key.txt index 5f2b9c5edbb5..22488d791168 100644 --- a/Documentation/keys-request-key.txt +++ b/Documentation/keys-request-key.txt @@ -56,10 +56,12 @@ A request proceeds in the following manner: (4) request_key() then forks and executes /sbin/request-key with a new session keyring that contains a link to auth key V. - (5) /sbin/request-key execs an appropriate program to perform the actual + (5) /sbin/request-key assumes the authority associated with key U. + + (6) /sbin/request-key execs an appropriate program to perform the actual instantiation. - (6) The program may want to access another key from A's context (say a + (7) The program may want to access another key from A's context (say a Kerberos TGT key). It just requests the appropriate key, and the keyring search notes that the session keyring has auth key V in its bottom level. @@ -67,19 +69,19 @@ A request proceeds in the following manner: UID, GID, groups and security info of process A as if it was process A, and come up with key W. - (7) The program then does what it must to get the data with which to + (8) The program then does what it must to get the data with which to instantiate key U, using key W as a reference (perhaps it contacts a Kerberos server using the TGT) and then instantiates key U. - (8) Upon instantiating key U, auth key V is automatically revoked so that it + (9) Upon instantiating key U, auth key V is automatically revoked so that it may not be used again. - (9) The program then exits 0 and request_key() deletes key V and returns key +(10) The program then exits 0 and request_key() deletes key V and returns key U to the caller. -This also extends further. If key W (step 5 above) didn't exist, key W would be -created uninstantiated, another auth key (X) would be created [as per step 3] -and another copy of /sbin/request-key spawned [as per step 4]; but the context +This also extends further. If key W (step 7 above) didn't exist, key W would be +created uninstantiated, another auth key (X) would be created (as per step 3) +and another copy of /sbin/request-key spawned (as per step 4); but the context specified by auth key X will still be process A, as it was in auth key V. This is because process A's keyrings can't simply be attached to @@ -138,8 +140,8 @@ until one succeeds: (3) The process's session keyring is searched. - (4) If the process has a request_key() authorisation key in its session - keyring then: + (4) If the process has assumed the authority associated with a request_key() + authorisation key then: (a) If extant, the calling process's thread keyring is searched. diff --git a/Documentation/keys.txt b/Documentation/keys.txt index eeda00f82d2c..aaa01b0e3ee9 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -308,6 +308,8 @@ process making the call: KEY_SPEC_USER_KEYRING -4 UID-specific keyring KEY_SPEC_USER_SESSION_KEYRING -5 UID-session keyring KEY_SPEC_GROUP_KEYRING -6 GID-specific keyring + KEY_SPEC_REQKEY_AUTH_KEY -7 assumed request_key() + authorisation key The main syscalls are: @@ -645,6 +647,28 @@ The keyctl syscall functions are: or expired keys. + (*) Assume the authority granted to instantiate a key + + long keyctl(KEYCTL_ASSUME_AUTHORITY, key_serial_t key); + + This assumes or divests the authority required to instantiate the + specified key. Authority can only be assumed if the thread has the + authorisation key associated with the specified key in its keyrings + somewhere. + + Once authority is assumed, searches for keys will also search the + requester's keyrings using the requester's security label, UID, GID and + groups. + + If the requested authority is unavailable, error EPERM will be returned, + likewise if the authority has been revoked because the target key is + already instantiated. + + If the specified key is 0, then any assumed authority will be divested. + + The assumed authorititive key is inherited across fork and exec. + + =============== KERNEL SERVICES =============== diff --git a/include/linux/key.h b/include/linux/key.h index 4d189e51bc6c..cbf464ad9589 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -177,6 +177,8 @@ struct key { /* * kernel managed key type definition */ +typedef int (*request_key_actor_t)(struct key *key, struct key *authkey, const char *op); + struct key_type { /* name of the type */ const char *name; @@ -218,6 +220,16 @@ struct key_type { */ long (*read)(const struct key *key, char __user *buffer, size_t buflen); + /* handle request_key() for this type instead of invoking + * /sbin/request-key (optional) + * - key is the key to instantiate + * - authkey is the authority to assume when instantiating this key + * - op is the operation to be done, usually "create" + * - the call must not return until the instantiation process has run + * its course + */ + request_key_actor_t request_key; + /* internal fields */ struct list_head link; /* link in types list */ }; diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index ec8f3d622a8d..3365945640c9 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h @@ -19,6 +19,7 @@ #define KEY_SPEC_USER_KEYRING -4 /* - key ID for UID-specific keyring */ #define KEY_SPEC_USER_SESSION_KEYRING -5 /* - key ID for UID-session keyring */ #define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */ +#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */ /* request-key default keyrings */ #define KEY_REQKEY_DEFL_NO_CHANGE -1 @@ -47,5 +48,6 @@ #define KEYCTL_NEGATE 13 /* negate a partially constructed key */ #define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */ #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ +#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ #endif /* _LINUX_KEYCTL_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 20bd70749104..78eb92ae4d94 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -771,6 +771,7 @@ struct task_struct { unsigned keep_capabilities:1; struct user_struct *user; #ifdef CONFIG_KEYS + struct key *request_key_auth; /* assumed request_key authority */ struct key *thread_keyring; /* keyring private to this thread */ unsigned char jit_keyring; /* default keyring to attach requested keys to */ #endif diff --git a/security/keys/compat.c b/security/keys/compat.c index e8e7ef4a290c..bcdb28533733 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -77,6 +77,9 @@ asmlinkage long compat_sys_keyctl(u32 option, case KEYCTL_SET_TIMEOUT: return keyctl_set_timeout(arg2, arg3); + case KEYCTL_ASSUME_AUTHORITY: + return keyctl_assume_authority(arg2); + default: return -EOPNOTSUPP; } diff --git a/security/keys/internal.h b/security/keys/internal.h index 51f37c0bdb32..e066e6057955 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -107,12 +107,13 @@ extern struct key *request_key_and_link(struct key_type *type, struct request_key_auth { struct key *target_key; struct task_struct *context; + const char *callout_info; pid_t pid; }; extern struct key_type key_type_request_key_auth; extern struct key *request_key_auth_new(struct key *target, - struct key **_rkakey); + const char *callout_info); extern struct key *key_get_instantiation_authkey(key_serial_t target_id); @@ -137,6 +138,7 @@ extern long keyctl_instantiate_key(key_serial_t, const void __user *, extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); extern long keyctl_set_reqkey_keyring(int); extern long keyctl_set_timeout(key_serial_t, unsigned); +extern long keyctl_assume_authority(key_serial_t); /* diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 299f0ae11cf0..3d2ebae029c1 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -834,6 +834,17 @@ long keyctl_instantiate_key(key_serial_t id, if (plen > 32767) goto error; + /* the appropriate instantiation authorisation key must have been + * assumed before calling this */ + ret = -EPERM; + instkey = current->request_key_auth; + if (!instkey) + goto error; + + rka = instkey->payload.data; + if (rka->target_key->serial != id) + goto error; + /* pull the payload in if one was supplied */ payload = NULL; @@ -848,15 +859,6 @@ long keyctl_instantiate_key(key_serial_t id, goto error2; } - /* find the instantiation authorisation key */ - instkey = key_get_instantiation_authkey(id); - if (IS_ERR(instkey)) { - ret = PTR_ERR(instkey); - goto error2; - } - - rka = instkey->payload.data; - /* find the destination keyring amongst those belonging to the * requesting task */ keyring_ref = NULL; @@ -865,7 +867,7 @@ long keyctl_instantiate_key(key_serial_t id, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); - goto error3; + goto error2; } } @@ -874,11 +876,17 @@ long keyctl_instantiate_key(key_serial_t id, key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); - error3: - key_put(instkey); - error2: + + /* discard the assumed authority if it's just been disabled by + * instantiation of the key */ + if (ret == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + } + +error2: kfree(payload); - error: +error: return ret; } /* end keyctl_instantiate_key() */ @@ -895,14 +903,16 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) key_ref_t keyring_ref; long ret; - /* find the instantiation authorisation key */ - instkey = key_get_instantiation_authkey(id); - if (IS_ERR(instkey)) { - ret = PTR_ERR(instkey); + /* the appropriate instantiation authorisation key must have been + * assumed before calling this */ + ret = -EPERM; + instkey = current->request_key_auth; + if (!instkey) goto error; - } rka = instkey->payload.data; + if (rka->target_key->serial != id) + goto error; /* find the destination keyring if present (which must also be * writable) */ @@ -911,7 +921,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); - goto error2; + goto error; } } @@ -920,9 +930,15 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); - error2: - key_put(instkey); - error: + + /* discard the assumed authority if it's just been disabled by + * instantiation of the key */ + if (ret == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + } + +error: return ret; } /* end keyctl_negate_key() */ @@ -1005,6 +1021,48 @@ error: } /* end keyctl_set_timeout() */ +/*****************************************************************************/ +/* + * assume the authority to instantiate the specified key + */ +long keyctl_assume_authority(key_serial_t id) +{ + struct key *authkey; + long ret; + + /* special key IDs aren't permitted */ + ret = -EINVAL; + if (id < 0) + goto error; + + /* we divest ourselves of authority if given an ID of 0 */ + if (id == 0) { + key_put(current->request_key_auth); + current->request_key_auth = NULL; + ret = 0; + goto error; + } + + /* attempt to assume the authority temporarily granted to us whilst we + * instantiate the specified key + * - the authorisation key must be in the current task's keyrings + * somewhere + */ + authkey = key_get_instantiation_authkey(id); + if (IS_ERR(authkey)) { + ret = PTR_ERR(authkey); + goto error; + } + + key_put(current->request_key_auth); + current->request_key_auth = authkey; + ret = authkey->serial; + +error: + return ret; + +} /* end keyctl_assume_authority() */ + /*****************************************************************************/ /* * the key control system call @@ -1082,6 +1140,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, return keyctl_set_timeout((key_serial_t) arg2, (unsigned) arg3); + case KEYCTL_ASSUME_AUTHORITY: + return keyctl_assume_authority((key_serial_t) arg2); + default: return -EOPNOTSUPP; } diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 09d92d52ef75..d65a180f888d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -479,51 +479,6 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, } /* end __keyring_search_one() */ -/*****************************************************************************/ -/* - * search for an instantiation authorisation key matching a target key - * - the RCU read lock must be held by the caller - * - a target_id of zero specifies any valid token - */ -struct key *keyring_search_instkey(struct key *keyring, - key_serial_t target_id) -{ - struct request_key_auth *rka; - struct keyring_list *klist; - struct key *instkey; - int loop; - - klist = rcu_dereference(keyring->payload.subscriptions); - if (klist) { - for (loop = 0; loop < klist->nkeys; loop++) { - instkey = klist->keys[loop]; - - if (instkey->type != &key_type_request_key_auth) - continue; - - rka = instkey->payload.data; - if (target_id && rka->target_key->serial != target_id) - continue; - - /* the auth key is revoked during instantiation */ - if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags)) - goto found; - - instkey = ERR_PTR(-EKEYREVOKED); - goto error; - } - } - - instkey = ERR_PTR(-EACCES); - goto error; - -found: - atomic_inc(&instkey->usage); -error: - return instkey; - -} /* end keyring_search_instkey() */ - /*****************************************************************************/ /* * find a keyring with the specified name diff --git a/security/keys/permission.c b/security/keys/permission.c index e7f579c0eaf5..3b41f9b52537 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c @@ -73,3 +73,35 @@ use_these_perms: } /* end key_task_permission() */ EXPORT_SYMBOL(key_task_permission); + +/*****************************************************************************/ +/* + * validate a key + */ +int key_validate(struct key *key) +{ + struct timespec now; + int ret = 0; + + if (key) { + /* check it's still accessible */ + ret = -EKEYREVOKED; + if (test_bit(KEY_FLAG_REVOKED, &key->flags) || + test_bit(KEY_FLAG_DEAD, &key->flags)) + goto error; + + /* check it hasn't expired */ + ret = 0; + if (key->expiry) { + now = current_kernel_time(); + if (now.tv_sec >= key->expiry) + ret = -EKEYEXPIRED; + } + } + + error: + return ret; + +} /* end key_validate() */ + +EXPORT_SYMBOL(key_validate); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 566b1cc0118a..74cb79eb917e 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -270,9 +270,14 @@ int copy_thread_group_keys(struct task_struct *tsk) int copy_keys(unsigned long clone_flags, struct task_struct *tsk) { key_check(tsk->thread_keyring); + key_check(tsk->request_key_auth); /* no thread keyring yet */ tsk->thread_keyring = NULL; + + /* copy the request_key() authorisation for this thread */ + key_get(tsk->request_key_auth); + return 0; } /* end copy_keys() */ @@ -290,11 +295,12 @@ void exit_thread_group_keys(struct signal_struct *tg) /*****************************************************************************/ /* - * dispose of keys upon thread exit + * dispose of per-thread keys upon thread exit */ void exit_keys(struct task_struct *tsk) { key_put(tsk->thread_keyring); + key_put(tsk->request_key_auth); } /* end exit_keys() */ @@ -382,7 +388,7 @@ key_ref_t search_process_keyrings(struct key_type *type, struct task_struct *context) { struct request_key_auth *rka; - key_ref_t key_ref, ret, err, instkey_ref; + key_ref_t key_ref, ret, err; /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were * searchable, but we failed to find a key or we found a negative key; @@ -461,30 +467,12 @@ key_ref_t search_process_keyrings(struct key_type *type, err = key_ref; break; } - - /* if this process has a session keyring and that has an - * instantiation authorisation key in the bottom level, then we - * also search the keyrings of the process mentioned there */ - if (context != current) - goto no_key; - - rcu_read_lock(); - instkey_ref = __keyring_search_one( - make_key_ref(rcu_dereference( - context->signal->session_keyring), - 1), - &key_type_request_key_auth, NULL, 0); - rcu_read_unlock(); - - if (IS_ERR(instkey_ref)) - goto no_key; - - rka = key_ref_to_ptr(instkey_ref)->payload.data; - - key_ref = search_process_keyrings(type, description, match, - rka->context); - key_ref_put(instkey_ref); - + } + /* or search the user-session keyring */ + else { + key_ref = keyring_search_aux( + make_key_ref(context->user->session_keyring, 1), + context, type, description, match); if (!IS_ERR(key_ref)) goto found; @@ -500,11 +488,21 @@ key_ref_t search_process_keyrings(struct key_type *type, break; } } - /* or search the user-session keyring */ - else { - key_ref = keyring_search_aux( - make_key_ref(context->user->session_keyring, 1), - context, type, description, match); + + /* if this process has an instantiation authorisation key, then we also + * search the keyrings of the process mentioned there + * - we don't permit access to request_key auth keys via this method + */ + if (context->request_key_auth && + context == current && + type != &key_type_request_key_auth && + key_validate(context->request_key_auth) == 0 + ) { + rka = context->request_key_auth->payload.data; + + key_ref = search_process_keyrings(type, description, match, + rka->context); + if (!IS_ERR(key_ref)) goto found; @@ -521,8 +519,6 @@ key_ref_t search_process_keyrings(struct key_type *type, } } - -no_key: /* no key - decide on the error we're going to go for */ key_ref = ret ? ret : err; @@ -628,6 +624,15 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, key = ERR_PTR(-EINVAL); goto error; + case KEY_SPEC_REQKEY_AUTH_KEY: + key = context->request_key_auth; + if (!key) + goto error; + + atomic_inc(&key->usage); + key_ref = make_key_ref(key, 1); + break; + default: key_ref = ERR_PTR(-EINVAL); if (id < 1) diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 5cc4bba70db6..f030a0ccbb93 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -29,28 +29,36 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); /*****************************************************************************/ /* * request userspace finish the construction of a key - * - execute "/sbin/request-key " + * - execute "/sbin/request-key " */ -static int call_request_key(struct key *key, - const char *op, - const char *callout_info) +static int call_sbin_request_key(struct key *key, + struct key *authkey, + const char *op) { struct task_struct *tsk = current; key_serial_t prkey, sskey; - struct key *session_keyring, *rkakey; - char *argv[10], *envp[3], uid_str[12], gid_str[12]; + struct key *keyring; + char *argv[9], *envp[3], uid_str[12], gid_str[12]; char key_str[12], keyring_str[3][12]; + char desc[20]; int ret, i; - kenter("{%d},%s,%s", key->serial, op, callout_info); + kenter("{%d},{%d},%s", key->serial, authkey->serial, op); - /* generate a new session keyring with an auth key in it */ - session_keyring = request_key_auth_new(key, &rkakey); - if (IS_ERR(session_keyring)) { - ret = PTR_ERR(session_keyring); - goto error; + /* allocate a new session keyring */ + sprintf(desc, "_req.%u", key->serial); + + keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); + if (IS_ERR(keyring)) { + ret = PTR_ERR(keyring); + goto error_alloc; } + /* attach the auth key to the session keyring */ + ret = __key_link(keyring, authkey); + if (ret < 0) + goto error_link; + /* record the UID and GID */ sprintf(uid_str, "%d", current->fsuid); sprintf(gid_str, "%d", current->fsgid); @@ -95,22 +103,19 @@ static int call_request_key(struct key *key, argv[i++] = keyring_str[0]; argv[i++] = keyring_str[1]; argv[i++] = keyring_str[2]; - argv[i++] = (char *) callout_info; argv[i] = NULL; /* do it */ - ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1); + ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1); - /* dispose of the special keys */ - key_revoke(rkakey); - key_put(rkakey); - key_put(session_keyring); +error_link: + key_put(keyring); - error: +error_alloc: kleave(" = %d", ret); return ret; -} /* end call_request_key() */ +} /* end call_sbin_request_key() */ /*****************************************************************************/ /* @@ -122,9 +127,10 @@ static struct key *__request_key_construction(struct key_type *type, const char *description, const char *callout_info) { + request_key_actor_t actor; struct key_construction cons; struct timespec now; - struct key *key; + struct key *key, *authkey; int ret, negated; kenter("%s,%s,%s", type->name, description, callout_info); @@ -143,8 +149,19 @@ static struct key *__request_key_construction(struct key_type *type, /* we drop the construction sem here on behalf of the caller */ up_write(&key_construction_sem); + /* allocate an authorisation key */ + authkey = request_key_auth_new(key, callout_info); + if (IS_ERR(authkey)) { + ret = PTR_ERR(authkey); + authkey = NULL; + goto alloc_authkey_failed; + } + /* make the call */ - ret = call_request_key(key, "create", callout_info); + actor = call_sbin_request_key; + if (type->request_key) + actor = type->request_key; + ret = actor(key, authkey, "create"); if (ret < 0) goto request_failed; @@ -153,22 +170,29 @@ static struct key *__request_key_construction(struct key_type *type, if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) goto request_failed; + key_revoke(authkey); + key_put(authkey); + down_write(&key_construction_sem); list_del(&cons.link); up_write(&key_construction_sem); /* also give an error if the key was negatively instantiated */ - check_not_negative: +check_not_negative: if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { key_put(key); key = ERR_PTR(-ENOKEY); } - out: +out: kleave(" = %p", key); return key; - request_failed: +request_failed: + key_revoke(authkey); + key_put(authkey); + +alloc_authkey_failed: /* it wasn't instantiated * - remove from construction queue * - mark the key as dead @@ -217,7 +241,7 @@ static struct key *__request_key_construction(struct key_type *type, key = ERR_PTR(ret); goto out; - alloc_failed: +alloc_failed: up_write(&key_construction_sem); goto out; @@ -464,35 +488,3 @@ struct key *request_key(struct key_type *type, } /* end request_key() */ EXPORT_SYMBOL(request_key); - -/*****************************************************************************/ -/* - * validate a key - */ -int key_validate(struct key *key) -{ - struct timespec now; - int ret = 0; - - if (key) { - /* check it's still accessible */ - ret = -EKEYREVOKED; - if (test_bit(KEY_FLAG_REVOKED, &key->flags) || - test_bit(KEY_FLAG_DEAD, &key->flags)) - goto error; - - /* check it hasn't expired */ - ret = 0; - if (key->expiry) { - now = current_kernel_time(); - if (now.tv_sec >= key->expiry) - ret = -EKEYEXPIRED; - } - } - - error: - return ret; - -} /* end key_validate() */ - -EXPORT_SYMBOL(key_validate); diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index a8e4069d48cb..cce6ba6b0323 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -15,11 +15,13 @@ #include #include #include +#include #include "internal.h" static int request_key_auth_instantiate(struct key *, const void *, size_t); static void request_key_auth_describe(const struct key *, struct seq_file *); static void request_key_auth_destroy(struct key *); +static long request_key_auth_read(const struct key *, char __user *, size_t); /* * the request-key authorisation key type definition @@ -30,51 +32,25 @@ struct key_type key_type_request_key_auth = { .instantiate = request_key_auth_instantiate, .describe = request_key_auth_describe, .destroy = request_key_auth_destroy, + .read = request_key_auth_read, }; /*****************************************************************************/ /* - * instantiate a request-key authorisation record + * instantiate a request-key authorisation key */ static int request_key_auth_instantiate(struct key *key, const void *data, size_t datalen) { - struct request_key_auth *rka, *irka; - struct key *instkey; - int ret; - - ret = -ENOMEM; - rka = kmalloc(sizeof(*rka), GFP_KERNEL); - if (rka) { - /* see if the calling process is already servicing the key - * request of another process */ - instkey = key_get_instantiation_authkey(0); - if (!IS_ERR(instkey)) { - /* it is - use that instantiation context here too */ - irka = instkey->payload.data; - rka->context = irka->context; - rka->pid = irka->pid; - key_put(instkey); - } - else { - /* it isn't - use this process as the context */ - rka->context = current; - rka->pid = current->pid; - } - - rka->target_key = key_get((struct key *) data); - key->payload.data = rka; - ret = 0; - } - - return ret; + key->payload.data = (struct request_key_auth *) data; + return 0; } /* end request_key_auth_instantiate() */ /*****************************************************************************/ /* - * + * reading a request-key authorisation key retrieves the callout information */ static void request_key_auth_describe(const struct key *key, struct seq_file *m) @@ -83,10 +59,38 @@ static void request_key_auth_describe(const struct key *key, seq_puts(m, "key:"); seq_puts(m, key->description); - seq_printf(m, " pid:%d", rka->pid); + seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info)); } /* end request_key_auth_describe() */ +/*****************************************************************************/ +/* + * read the callout_info data + * - the key's semaphore is read-locked + */ +static long request_key_auth_read(const struct key *key, + char __user *buffer, size_t buflen) +{ + struct request_key_auth *rka = key->payload.data; + size_t datalen; + long ret; + + datalen = strlen(rka->callout_info); + ret = datalen; + + /* we can return the data as is */ + if (buffer && buflen > 0) { + if (buflen > datalen) + buflen = datalen; + + if (copy_to_user(buffer, rka->callout_info, buflen) != 0) + ret = -EFAULT; + } + + return ret; + +} /* end request_key_auth_read() */ + /*****************************************************************************/ /* * destroy an instantiation authorisation token key @@ -104,54 +108,87 @@ static void request_key_auth_destroy(struct key *key) /*****************************************************************************/ /* - * create a session keyring to be for the invokation of /sbin/request-key and - * stick an authorisation token in it + * create an authorisation token for /sbin/request-key or whoever to gain + * access to the caller's security data */ -struct key *request_key_auth_new(struct key *target, struct key **_rkakey) +struct key *request_key_auth_new(struct key *target, const char *callout_info) { - struct key *keyring, *rkakey = NULL; + struct request_key_auth *rka, *irka; + struct key *authkey = NULL; char desc[20]; int ret; kenter("%d,", target->serial); - /* allocate a new session keyring */ - sprintf(desc, "_req.%u", target->serial); + /* allocate a auth record */ + rka = kmalloc(sizeof(*rka), GFP_KERNEL); + if (!rka) { + kleave(" = -ENOMEM"); + return ERR_PTR(-ENOMEM); + } - keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); - if (IS_ERR(keyring)) { - kleave("= %ld", PTR_ERR(keyring)); - return keyring; + /* see if the calling process is already servicing the key request of + * another process */ + if (current->request_key_auth) { + /* it is - use that instantiation context here too */ + irka = current->request_key_auth->payload.data; + rka->context = irka->context; + rka->pid = irka->pid; } + else { + /* it isn't - use this process as the context */ + rka->context = current; + rka->pid = current->pid; + } + + rka->target_key = key_get(target); + rka->callout_info = callout_info; /* allocate the auth key */ sprintf(desc, "%x", target->serial); - rkakey = key_alloc(&key_type_request_key_auth, desc, - current->fsuid, current->fsgid, - KEY_POS_VIEW | KEY_USR_VIEW, 1); - if (IS_ERR(rkakey)) { - key_put(keyring); - kleave("= %ld", PTR_ERR(rkakey)); - return rkakey; + authkey = key_alloc(&key_type_request_key_auth, desc, + current->fsuid, current->fsgid, + KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | + KEY_USR_VIEW, 1); + if (IS_ERR(authkey)) { + ret = PTR_ERR(authkey); + goto error_alloc; } /* construct and attach to the keyring */ - ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL); - if (ret < 0) { - key_revoke(rkakey); - key_put(rkakey); - key_put(keyring); - kleave("= %d", ret); - return ERR_PTR(ret); - } + ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); + if (ret < 0) + goto error_inst; - *_rkakey = rkakey; - kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial); - return keyring; + kleave(" = {%d})", authkey->serial); + return authkey; + +error_inst: + key_revoke(authkey); + key_put(authkey); +error_alloc: + key_put(rka->target_key); + kfree(rka); + kleave("= %d", ret); + return ERR_PTR(ret); } /* end request_key_auth_new() */ +/*****************************************************************************/ +/* + * see if an authorisation key is associated with a particular key + */ +static int key_get_instantiation_authkey_match(const struct key *key, + const void *_id) +{ + struct request_key_auth *rka = key->payload.data; + key_serial_t id = (key_serial_t)(unsigned long) _id; + + return rka->target_key->serial == id; + +} /* end key_get_instantiation_authkey_match() */ + /*****************************************************************************/ /* * get the authorisation key for instantiation of a specific key if attached to @@ -162,22 +199,27 @@ struct key *request_key_auth_new(struct key *target, struct key **_rkakey) */ struct key *key_get_instantiation_authkey(key_serial_t target_id) { - struct task_struct *tsk = current; - struct key *instkey; - - /* we must have our own personal session keyring */ - if (!tsk->signal->session_keyring) - return ERR_PTR(-EACCES); - - /* and it must contain a suitable request authorisation key - * - lock RCU against session keyring changing - */ - rcu_read_lock(); + struct key *authkey; + key_ref_t authkey_ref; + + authkey_ref = search_process_keyrings( + &key_type_request_key_auth, + (void *) (unsigned long) target_id, + key_get_instantiation_authkey_match, + current); + + if (IS_ERR(authkey_ref)) { + authkey = ERR_PTR(PTR_ERR(authkey_ref)); + goto error; + } - instkey = keyring_search_instkey( - rcu_dereference(tsk->signal->session_keyring), target_id); + authkey = key_ref_to_ptr(authkey_ref); + if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { + key_put(authkey); + authkey = ERR_PTR(-EKEYREVOKED); + } - rcu_read_unlock(); - return instkey; +error: + return authkey; } /* end key_get_instantiation_authkey() */ -- cgit v1.2.3 From 71fabd5e4835309b4feca6209122ce56c595c461 Mon Sep 17 00:00:00 2001 From: George Anzinger Date: Sun, 8 Jan 2006 01:02:48 -0800 Subject: [PATCH] sigaction should clear all signals on SIG_IGN, not just < 32 While rooting aroung in the signal code trying to understand how to fix the SIG_IGN ploy (set sig handler to SIG_IGN and flood system with high speed repeating timers) I came across what, I think, is a problem in sigaction() in that when processing a SIG_IGN request it flushes signals from 1 to SIGRTMIN and leaves the rest. Attempt to fix this. Signed-off-by: George Anzinger Cc: Roland McGrath Cc: Linus Torvalds Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/signal.h | 17 +++++++++++++++++ kernel/signal.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/include/linux/signal.h b/include/linux/signal.h index ea9eff16c4b7..b7d093520bb6 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -94,6 +94,23 @@ static inline int sigfindinword(unsigned long word) #endif /* __HAVE_ARCH_SIG_BITOPS */ +static inline int sigisemptyset(sigset_t *set) +{ + extern void _NSIG_WORDS_is_unsupported_size(void); + switch (_NSIG_WORDS) { + case 4: + return (set->sig[3] | set->sig[2] | + set->sig[1] | set->sig[0]) == 0; + case 2: + return (set->sig[1] | set->sig[0]) == 0; + case 1: + return set->sig[0] == 0; + default: + _NSIG_WORDS_is_unsupported_size(); + return 0; + } +} + #define sigmask(sig) (1UL << ((sig) - 1)) #ifndef __HAVE_ARCH_SIG_SETOPS diff --git a/kernel/signal.c b/kernel/signal.c index 9b6fda5e87f1..e20724af9b36 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -620,6 +620,33 @@ void signal_wake_up(struct task_struct *t, int resume) kick_process(t); } +/* + * Remove signals in mask from the pending set and queue. + * Returns 1 if any signals were found. + * + * All callers must be holding the siglock. + * + * This version takes a sigset mask and looks at all signals, + * not just those in the first mask word. + */ +static int rm_from_queue_full(sigset_t *mask, struct sigpending *s) +{ + struct sigqueue *q, *n; + sigset_t m; + + sigandsets(&m, mask, &s->signal); + if (sigisemptyset(&m)) + return 0; + + signandsets(&s->signal, &s->signal, mask); + list_for_each_entry_safe(q, n, &s->list, list) { + if (sigismember(mask, q->info.si_signo)) { + list_del_init(&q->list); + __sigqueue_free(q); + } + } + return 1; +} /* * Remove signals in mask from the pending set and queue. * Returns 1 if any signals were found. @@ -2408,6 +2435,7 @@ int do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) { struct k_sigaction *k; + sigset_t mask; if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) return -EINVAL; @@ -2455,9 +2483,11 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) *k = *act; sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); - rm_from_queue(sigmask(sig), &t->signal->shared_pending); + sigemptyset(&mask); + sigaddset(&mask, sig); + rm_from_queue_full(&mask, &t->signal->shared_pending); do { - rm_from_queue(sigmask(sig), &t->pending); + rm_from_queue_full(&mask, &t->pending); recalc_sigpending_tsk(t); t = next_thread(t); } while (t != current); -- cgit v1.2.3 From 5b0ed2c64d8fdafb5fcfb3baabdd288628b1ff9b Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sun, 8 Jan 2006 01:02:49 -0800 Subject: [PATCH] docs: updated some code docs Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/CodingStyle | 7 +++-- Documentation/SubmittingDrivers | 24 +++++++++++------ Documentation/SubmittingPatches | 60 ++++++++++++++++++++++++++++------------- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index eb7db3c19227..187e12077e19 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -444,10 +444,13 @@ ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/ GNU manuals - where in compliance with K&R and this text - for cpp, gcc, -gcc internals and indent, all available from http://www.gnu.org +gcc internals and indent, all available from http://www.gnu.org/manual/ WG14 is the international standardization working group for the programming -language C, URL: http://std.dkuug.dk/JTC1/SC22/WG14/ +language C, URL: http://www.open-std.org/JTC1/SC22/WG14/ + +Kernel CodingStyle, by greg@kroah.com at OLS 2002: +http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ -- Last updated on 16 February 2004 by a community effort on LKML. diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers index c3cca924e94b..dd311cff1cc3 100644 --- a/Documentation/SubmittingDrivers +++ b/Documentation/SubmittingDrivers @@ -27,18 +27,17 @@ Who To Submit Drivers To ------------------------ Linux 2.0: - No new drivers are accepted for this kernel tree + No new drivers are accepted for this kernel tree. Linux 2.2: + No new drivers are accepted for this kernel tree. + +Linux 2.4: If the code area has a general maintainer then please submit it to the maintainer listed in MAINTAINERS in the kernel file. If the maintainer does not respond or you cannot find the appropriate - maintainer then please contact the 2.2 kernel maintainer: - Marc-Christian Petersen . - -Linux 2.4: - The same rules apply as 2.2. The final contact point for Linux 2.4 - submissions is Marcelo Tosatti . + maintainer then please contact Marcelo Tosatti + . Linux 2.6: The same rules apply as 2.4 except that you should follow linux-kernel @@ -53,6 +52,7 @@ Licensing: The code must be released to us under the of exclusive GPL licensing, and if you wish the driver to be useful to other communities such as BSD you may well wish to release under multiple licenses. + See accepted licenses at include/linux/module.h Copyright: The copyright owner must agree to use of GPL. It's best if the submitter and copyright owner @@ -143,5 +143,13 @@ KernelNewbies: http://kernelnewbies.org/ Linux USB project: - http://sourceforge.net/projects/linux-usb/ + http://linux-usb.sourceforge.net/ + +How to NOT write kernel driver by arjanv@redhat.com + http://people.redhat.com/arjanv/olspaper.pdf + +Kernel Janitor: + http://janitor.kernelnewbies.org/ +-- +Last updated on 17 Nov 2005. diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 1d47e6c09dc6..3c12fc146940 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -78,7 +78,9 @@ Randy Dunlap's patch scripts: http://www.xenotime.net/linux/scripts/patching-scripts-002.tar.gz Andrew Morton's patch scripts: -http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.20 +http://www.zip.com.au/~akpm/linux/patches/ +Instead of these scripts, quilt is the recommended patch management +tool (see above). @@ -97,7 +99,7 @@ need to split up your patch. See #3, next. 3) Separate your changes. -Separate each logical change into its own patch. +Separate _logical changes_ into a single patch file. For example, if your changes include both bug fixes and performance enhancements for a single driver, separate those changes into two @@ -112,6 +114,10 @@ If one patch depends on another patch in order for a change to be complete, that is OK. Simply note "this patch depends on patch X" in your patch description. +If you cannot condense your patch set into a smaller set of patches, +then only post say 15 or so at a time and wait for review and integration. + + 4) Select e-mail destination. @@ -124,6 +130,10 @@ your patch to the primary Linux kernel developer's mailing list, linux-kernel@vger.kernel.org. Most kernel developers monitor this e-mail list, and can comment on your changes. + +Do not send more than 15 patches at once to the vger mailing lists!!! + + Linus Torvalds is the final arbiter of all changes accepted into the Linux kernel. His e-mail address is . He gets a lot of e-mail, so typically you should do your best to -avoid- sending @@ -149,6 +159,9 @@ USB, framebuffer devices, the VFS, the SCSI subsystem, etc. See the MAINTAINERS file for a mailing list that relates specifically to your change. +Majordomo lists of VGER.KERNEL.ORG at: + + If changes affect userland-kernel interfaces, please send the MAN-PAGES maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at least a notification of the change, @@ -378,22 +391,6 @@ See more details on the proper patch format in the following references. -13) More references for submitting patches - -Andrew Morton, "The perfect patch" (tpp). - - -Jeff Garzik, "Linux kernel patch submission format." - - -Greg KH, "How to piss off a kernel subsystem maintainer" - - -Kernel Documentation/CodingStyle - - -Linus Torvald's mail on the canonical patch format: - ----------------------------------- @@ -466,3 +463,30 @@ and 'extern __inline__'. Don't try to anticipate nebulous future cases which may or may not be useful: "Make it as simple as you can, and no simpler." + + +---------------------- +SECTION 3 - REFERENCES +---------------------- + +Andrew Morton, "The perfect patch" (tpp). + + +Jeff Garzik, "Linux kernel patch submission format." + + +Greg Kroah, "How to piss off a kernel subsystem maintainer". + + + + +NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!. + + +Kernel Documentation/CodingStyle + + +Linus Torvald's mail on the canonical patch format: + +-- +Last updated on 17 Nov 2005. -- cgit v1.2.3 From a885c8c4316e1c1d2d2c8755da3f3d14f852528d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jan 2006 01:02:50 -0800 Subject: [PATCH] Add block_device_operations.getgeo block device method HDIO_GETGEO is implemented in most block drivers, and all of them have to duplicate the code to copy the structure to userspace, as well as getting the start sector. This patch moves that to common code [1] and adds a ->getgeo method to fill out the raw kernel hd_geometry structure. For many drivers this means ->ioctl can go away now. [1] the s390 block drivers are odd in this respect. xpram sets ->start to 4 always which seems more than odd, and the dasd driver shifts the start offset around, probably because of it's non-standard sector size. Signed-off-by: Christoph Hellwig Cc: Jens Axboe Cc: Cc: Jeff Dike Cc: Paolo Giarrusso Cc: Bartlomiej Zolnierkiewicz Cc: Neil Brown Cc: Markus Lidel Cc: Russell King Cc: David Woodhouse Cc: Martin Schwidefsky Cc: James Bottomley Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/ubd_kern.c | 21 +++++++++-------- block/ioctl.c | 22 ++++++++++++++++++ drivers/acorn/block/mfmhd.c | 36 ++++++----------------------- drivers/block/DAC960.c | 35 ++++++++++++----------------- drivers/block/acsi.c | 26 +++++++++++---------- drivers/block/amiflop.c | 23 +++++++++---------- drivers/block/aoe/aoeblk.c | 26 ++++++--------------- drivers/block/cciss.c | 31 ++++++++++++------------- drivers/block/cpqarray.c | 36 +++++++++++++++-------------- drivers/block/floppy.c | 35 +++++++++++++++-------------- drivers/block/paride/pd.c | 34 +++++++++++++++------------- drivers/block/paride/pf.c | 50 +++++++++++++++++++++-------------------- drivers/block/ps2esdi.c | 25 +++++++-------------- drivers/block/sx8.c | 35 +++++++---------------------- drivers/block/umem.c | 41 +++++++++++++-------------------- drivers/block/viodasd.c | 44 ++++++++---------------------------- drivers/block/xd.c | 25 +++++++++++---------- drivers/ide/ide-disk.c | 12 ++++++++++ drivers/ide/ide-floppy.c | 12 ++++++++++ drivers/ide/ide.c | 13 ----------- drivers/ide/legacy/hd.c | 24 +++++++------------- drivers/md/md.c | 30 +++++++++---------------- drivers/message/i2o/i2o_block.c | 18 +++++++-------- drivers/mmc/mmc_block.c | 25 +++++---------------- drivers/mtd/mtd_blkdevs.c | 25 ++++++++------------- drivers/s390/block/dasd.c | 23 +++++++++++++++++++ drivers/s390/block/dasd_ioctl.c | 28 ----------------------- drivers/s390/block/xpram.c | 18 ++++++--------- drivers/scsi/sd.c | 21 +++++------------ include/linux/fs.h | 2 ++ 30 files changed, 340 insertions(+), 456 deletions(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 73f9652b2ee9..3a93c6f772fa 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -117,6 +117,7 @@ static int ubd_open(struct inode * inode, struct file * filp); static int ubd_release(struct inode * inode, struct file * file); static int ubd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); +static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo); #define MAX_DEV (8) @@ -125,6 +126,7 @@ static struct block_device_operations ubd_blops = { .open = ubd_open, .release = ubd_release, .ioctl = ubd_ioctl, + .getgeo = ubd_getgeo, }; /* Protected by the queue_lock */ @@ -1058,6 +1060,16 @@ static void do_ubd_request(request_queue_t *q) } } +static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ubd *dev = bdev->bd_disk->private_data; + + geo->heads = 128; + geo->sectors = 32; + geo->cylinders = dev->size / (128 * 32 * 512); + return 0; +} + static int ubd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { @@ -1070,16 +1082,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file, }; switch (cmd) { - struct hd_geometry g; struct cdrom_volctrl volume; - case HDIO_GETGEO: - if(!loc) return(-EINVAL); - g.heads = 128; - g.sectors = 32; - g.cylinders = dev->size / (128 * 32 * 512); - g.start = get_start_sect(inode->i_bdev); - return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); - case HDIO_GET_IDENTITY: ubd_id.cyls = dev->size / (128 * 32 * 512); if(copy_to_user((char __user *) arg, (char *) &ubd_id, diff --git a/block/ioctl.c b/block/ioctl.c index 6e278474f9a8..82030e1dfd63 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -1,6 +1,7 @@ #include /* for capable() */ #include #include +#include #include #include #include @@ -245,6 +246,27 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, set_device_ro(bdev, n); unlock_kernel(); return 0; + case HDIO_GETGEO: { + struct hd_geometry geo; + + if (!arg) + return -EINVAL; + if (!disk->fops->getgeo) + return -ENOTTY; + + /* + * We need to set the startsect first, the driver may + * want to override it. + */ + geo.start = get_start_sect(bdev); + ret = disk->fops->getgeo(bdev, &geo); + if (ret) + return ret; + if (copy_to_user((struct hd_geometry __user *)arg, &geo, + sizeof(geo))) + return -EFAULT; + return 0; + } } lock_kernel(); diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 4b65f74d66b1..ce074f6f3369 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -129,19 +129,6 @@ static DEFINE_SPINLOCK(mfm_lock); #define MAJOR_NR MFM_ACORN_MAJOR #define QUEUE (mfm_queue) #define CURRENT elv_next_request(mfm_queue) -/* - * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc - */ -#ifndef HDIO_GETGEO -#define HDIO_GETGEO 0x301 -struct hd_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; -#endif - /* * Configuration section @@ -1153,22 +1140,13 @@ static int mfm_initdrives(void) * The 'front' end of the mfm driver follows... */ -static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct mfm_info *p = inode->i_bdev->bd_disk->private_data; - struct hd_geometry *geo = (struct hd_geometry *) arg; - if (cmd != HDIO_GETGEO) - return -EINVAL; - if (!arg) - return -EINVAL; - if (put_user (p->heads, &geo->heads)) - return -EFAULT; - if (put_user (p->sectors, &geo->sectors)) - return -EFAULT; - if (put_user (p->cylinders, &geo->cylinders)) - return -EFAULT; - if (put_user (get_start_sect(inode->i_bdev), &geo->start)) - return -EFAULT; + struct mfm_info *p = bdev->bd_disk->private_data; + + geo->heads = p->heads; + geo->sectors = p->sectors; + geo->cylinders = p->cylinders; return 0; } @@ -1219,7 +1197,7 @@ void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack, static struct block_device_operations mfm_fops = { .owner = THIS_MODULE, - .ioctl = mfm_ioctl, + .getgeo = mfm_getgeo, }; /* diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 21097a39a057..179c68a3cef3 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -92,34 +92,28 @@ static int DAC960_open(struct inode *inode, struct file *file) return 0; } -static int DAC960_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; DAC960_Controller_T *p = disk->queue->queuedata; int drive_nr = (long)disk->private_data; - struct hd_geometry g; - struct hd_geometry __user *loc = (struct hd_geometry __user *)arg; - - if (cmd != HDIO_GETGEO || !loc) - return -EINVAL; if (p->FirmwareType == DAC960_V1_Controller) { - g.heads = p->V1.GeometryTranslationHeads; - g.sectors = p->V1.GeometryTranslationSectors; - g.cylinders = p->V1.LogicalDriveInformation[drive_nr]. - LogicalDriveSize / (g.heads * g.sectors); + geo->heads = p->V1.GeometryTranslationHeads; + geo->sectors = p->V1.GeometryTranslationSectors; + geo->cylinders = p->V1.LogicalDriveInformation[drive_nr]. + LogicalDriveSize / (geo->heads * geo->sectors); } else { DAC960_V2_LogicalDeviceInfo_T *i = p->V2.LogicalDeviceInformation[drive_nr]; switch (i->DriveGeometry) { case DAC960_V2_Geometry_128_32: - g.heads = 128; - g.sectors = 32; + geo->heads = 128; + geo->sectors = 32; break; case DAC960_V2_Geometry_255_63: - g.heads = 255; - g.sectors = 63; + geo->heads = 255; + geo->sectors = 63; break; default: DAC960_Error("Illegal Logical Device Geometry %d\n", @@ -127,12 +121,11 @@ static int DAC960_ioctl(struct inode *inode, struct file *file, return -EINVAL; } - g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors); + geo->cylinders = i->ConfigurableDeviceSize / + (geo->heads * geo->sectors); } - g.start = get_start_sect(inode->i_bdev); - - return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; + return 0; } static int DAC960_media_changed(struct gendisk *disk) @@ -157,7 +150,7 @@ static int DAC960_revalidate_disk(struct gendisk *disk) static struct block_device_operations DAC960_BlockDeviceOperations = { .owner = THIS_MODULE, .open = DAC960_open, - .ioctl = DAC960_ioctl, + .getgeo = DAC960_getgeo, .media_changed = DAC960_media_changed, .revalidate_disk = DAC960_revalidate_disk, }; diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 5d2d649f7e8d..196c0ec9cd54 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1079,6 +1079,19 @@ static void redo_acsi_request( void ) * ***********************************************************************/ +static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct acsi_info_struct *aip = bdev->bd_disk->private_data; + + /* + * Just fake some geometry here, it's nonsense anyway + * To make it easy, use Adaptec's usual 64/32 mapping + */ + geo->heads = 64; + geo->sectors = 32; + geo->cylinders = aip->size >> 11; + return 0; +} static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) @@ -1086,18 +1099,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file, struct gendisk *disk = inode->i_bdev->bd_disk; struct acsi_info_struct *aip = disk->private_data; switch (cmd) { - case HDIO_GETGEO: - /* HDIO_GETGEO is supported more for getting the partition's - * start sector... */ - { struct hd_geometry *geo = (struct hd_geometry *)arg; - /* just fake some geometry here, it's nonsense anyway; to make it - * easy, use Adaptec's usual 64/32 mapping */ - put_user( 64, &geo->heads ); - put_user( 32, &geo->sectors ); - put_user( aip->size >> 11, &geo->cylinders ); - put_user(get_start_sect(inode->i_bdev), &geo->start); - return 0; - } case SCSI_IOCTL_GET_IDLUN: /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ put_user( aip->target | (aip->lun << 8), @@ -1592,6 +1593,7 @@ static struct block_device_operations acsi_fops = { .open = acsi_open, .release = acsi_release, .ioctl = acsi_ioctl, + .getgeo = acsi_getgeo, .media_changed = acsi_media_change, .revalidate_disk= acsi_revalidate, }; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 0acbfff8ad28..cb2a545e57dc 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1424,6 +1424,16 @@ static void do_fd_request(request_queue_t * q) redo_fd_request(); } +static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + int drive = MINOR(bdev->bd_dev) & 3; + + geo->heads = unit[drive].type->heads; + geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; + geo->cylinders = unit[drive].type->tracks; + return 0; +} + static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { @@ -1431,18 +1441,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, static struct floppy_struct getprm; switch(cmd){ - case HDIO_GETGEO: - { - struct hd_geometry loc; - loc.heads = unit[drive].type->heads; - loc.sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; - loc.cylinders = unit[drive].type->tracks; - loc.start = 0; - if (copy_to_user((void *)param, (void *)&loc, - sizeof(struct hd_geometry))) - return -EFAULT; - break; - } case FDFMTBEG: get_fdc(drive); if (fd_ref[drive] > 1) { @@ -1652,6 +1650,7 @@ static struct block_device_operations floppy_fops = { .open = floppy_open, .release = floppy_release, .ioctl = fd_ioctl, + .getgeo = fd_getgeo, .media_changed = amiga_floppy_change, }; diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 0e97fcb9f3a1..c05ee8bffd97 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -169,38 +169,26 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) return 0; } -/* This ioctl implementation expects userland to have the device node - * permissions set so that only priviledged users can open an aoe - * block device directly. - */ static int -aoeblk_ioctl(struct inode *inode, struct file *filp, uint cmd, ulong arg) +aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct aoedev *d; - - if (!arg) - return -EINVAL; + struct aoedev *d = bdev->bd_disk->private_data; - d = inode->i_bdev->bd_disk->private_data; if ((d->flags & DEVFL_UP) == 0) { printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n"); return -ENODEV; } - if (cmd == HDIO_GETGEO) { - d->geo.start = get_start_sect(inode->i_bdev); - if (!copy_to_user((void __user *) arg, &d->geo, sizeof d->geo)) - return 0; - return -EFAULT; - } - printk(KERN_INFO "aoe: aoeblk_ioctl: unknown ioctl %d\n", cmd); - return -EINVAL; + geo->cylinders = d->geo.cylinders; + geo->heads = d->geo.heads; + geo->sectors = d->geo.sectors; + return 0; } static struct block_device_operations aoe_bdops = { .open = aoeblk_open, .release = aoeblk_release, - .ioctl = aoeblk_ioctl, + .getgeo = aoeblk_getgeo, .owner = THIS_MODULE, }; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d2815b7a9150..bdb9c2717d40 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -153,6 +153,7 @@ static int cciss_open(struct inode *inode, struct file *filep); static int cciss_release(struct inode *inode, struct file *filep); static int cciss_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int revalidate_allvol(ctlr_info_t *host); static int cciss_revalidate(struct gendisk *disk); @@ -194,6 +195,7 @@ static struct block_device_operations cciss_fops = { .open = cciss_open, .release = cciss_release, .ioctl = cciss_ioctl, + .getgeo = cciss_getgeo, #ifdef CONFIG_COMPAT .compat_ioctl = cciss_compat_ioctl, #endif @@ -633,6 +635,20 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned return err; } #endif + +static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + drive_info_struct *drv = get_drv(bdev->bd_disk); + + if (!drv->cylinders) + return -ENXIO; + + geo->heads = drv->heads; + geo->sectors = drv->sectors; + geo->cylinders = drv->cylinders; + return 0; +} + /* * ioctl */ @@ -651,21 +667,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, #endif /* CCISS_DEBUG */ switch(cmd) { - case HDIO_GETGEO: - { - struct hd_geometry driver_geo; - if (drv->cylinders) { - driver_geo.heads = drv->heads; - driver_geo.sectors = drv->sectors; - driver_geo.cylinders = drv->cylinders; - } else - return -ENXIO; - driver_geo.start= get_start_sect(inode->i_bdev); - if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry))) - return -EFAULT; - return(0); - } - case CCISS_GETPCIINFO: { cciss_pci_info_struct pciinfo; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 9bddb6874873..9f0664dd3800 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -160,6 +160,7 @@ static int sendcmd( static int ida_open(struct inode *inode, struct file *filep); static int ida_release(struct inode *inode, struct file *filep); static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io); static void do_ida_request(request_queue_t *q); @@ -199,6 +200,7 @@ static struct block_device_operations ida_fops = { .open = ida_open, .release = ida_release, .ioctl = ida_ioctl, + .getgeo = ida_getgeo, .revalidate_disk= ida_revalidate, }; @@ -1124,6 +1126,23 @@ static void ida_timer(unsigned long tdata) h->misc_tflags = 0; } +static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + drv_info_t *drv = get_drv(bdev->bd_disk); + + if (drv->cylinders) { + geo->heads = drv->heads; + geo->sectors = drv->sectors; + geo->cylinders = drv->cylinders; + } else { + geo->heads = 0xff; + geo->sectors = 0x3f; + geo->cylinders = drv->nr_blks / (0xff*0x3f); + } + + return 0; +} + /* * ida_ioctl does some miscellaneous stuff like reporting drive geometry, * setting readahead and submitting commands from userspace to the controller. @@ -1133,27 +1152,10 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, drv_info_t *drv = get_drv(inode->i_bdev->bd_disk); ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); int error; - int diskinfo[4]; - struct hd_geometry __user *geo = (struct hd_geometry __user *)arg; ida_ioctl_t __user *io = (ida_ioctl_t __user *)arg; ida_ioctl_t *my_io; switch(cmd) { - case HDIO_GETGEO: - if (drv->cylinders) { - diskinfo[0] = drv->heads; - diskinfo[1] = drv->sectors; - diskinfo[2] = drv->cylinders; - } else { - diskinfo[0] = 0xff; - diskinfo[1] = 0x3f; - diskinfo[2] = drv->nr_blks / (0xff*0x3f); - } - put_user(diskinfo[0], &geo->heads); - put_user(diskinfo[1], &geo->sectors); - put_user(diskinfo[2], &geo->cylinders); - put_user(get_start_sect(inode->i_bdev), &geo->start); - return 0; case IDAGETDRVINFO: if (copy_to_user(&io->c.drv, drv, sizeof(drv_info_t))) return -EFAULT; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a5b857c5c4b8..b86613b21cf1 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3445,6 +3445,23 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g) return 0; } +static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + int drive = (long)bdev->bd_disk->private_data; + int type = ITYPE(drive_state[drive].fd_device); + struct floppy_struct *g; + int ret; + + ret = get_floppy_geometry(drive, type, &g); + if (ret) + return ret; + + geo->heads = g->head; + geo->sectors = g->sect; + geo->cylinders = g->track; + return 0; +} + static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { @@ -3474,23 +3491,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, cmd = FDEJECT; } - /* generic block device ioctls */ - switch (cmd) { - /* the following have been inspired by the corresponding - * code for other block devices. */ - struct floppy_struct *g; - case HDIO_GETGEO: - { - struct hd_geometry loc; - ECALL(get_floppy_geometry(drive, type, &g)); - loc.heads = g->head; - loc.sectors = g->sect; - loc.cylinders = g->track; - loc.start = 0; - return _COPYOUT(loc); - } - } - /* convert the old style command into a new style command */ if ((cmd & 0xff00) == 0x0200) { ECALL(normalize_ioctl(&cmd, &size)); @@ -3938,6 +3938,7 @@ static struct block_device_operations floppy_fops = { .open = floppy_open, .release = floppy_release, .ioctl = fd_ioctl, + .getgeo = fd_getgeo, .media_changed = check_floppy_change, .revalidate_disk = floppy_revalidate, }; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index fa49d62626ba..62d2464c12f2 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -747,32 +747,33 @@ static int pd_open(struct inode *inode, struct file *file) return 0; } +static int pd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct pd_unit *disk = bdev->bd_disk->private_data; + + if (disk->alt_geom) { + geo->heads = PD_LOG_HEADS; + geo->sectors = PD_LOG_SECTS; + geo->cylinders = disk->capacity / (geo->heads * geo->sectors); + } else { + geo->heads = disk->heads; + geo->sectors = disk->sectors; + geo->cylinders = disk->cylinders; + } + + return 0; +} + static int pd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; - struct hd_geometry g; switch (cmd) { case CDROMEJECT: if (disk->access == 1) pd_special_command(disk, pd_eject); return 0; - case HDIO_GETGEO: - if (disk->alt_geom) { - g.heads = PD_LOG_HEADS; - g.sectors = PD_LOG_SECTS; - g.cylinders = disk->capacity / (g.heads * g.sectors); - } else { - g.heads = disk->heads; - g.sectors = disk->sectors; - g.cylinders = disk->cylinders; - } - g.start = get_start_sect(inode->i_bdev); - if (copy_to_user(geo, &g, sizeof(struct hd_geometry))) - return -EFAULT; - return 0; default: return -EINVAL; } @@ -815,6 +816,7 @@ static struct block_device_operations pd_fops = { .open = pd_open, .release = pd_release, .ioctl = pd_ioctl, + .getgeo = pd_getgeo, .media_changed = pd_check_media, .revalidate_disk= pd_revalidate }; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index e9746af29b9f..852b564e903a 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -205,6 +205,7 @@ static int pf_open(struct inode *inode, struct file *file); static void do_pf_request(request_queue_t * q); static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int pf_release(struct inode *inode, struct file *file); @@ -266,6 +267,7 @@ static struct block_device_operations pf_fops = { .open = pf_open, .release = pf_release, .ioctl = pf_ioctl, + .getgeo = pf_getgeo, .media_changed = pf_check_media, }; @@ -313,34 +315,34 @@ static int pf_open(struct inode *inode, struct file *file) return 0; } -static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; - struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; - struct hd_geometry g; - sector_t capacity; - - if (cmd == CDROMEJECT) { - if (pf->access == 1) { - pf_eject(pf); - return 0; - } - return -EBUSY; - } - if (cmd != HDIO_GETGEO) - return -EINVAL; - capacity = get_capacity(pf->disk); + struct pf_unit *pf = bdev->bd_disk->private_data; + sector_t capacity = get_capacity(pf->disk); + if (capacity < PF_FD_MAX) { - g.cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); - g.heads = PF_FD_HDS; - g.sectors = PF_FD_SPT; + geo->cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); + geo->heads = PF_FD_HDS; + geo->sectors = PF_FD_SPT; } else { - g.cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); - g.heads = PF_HD_HDS; - g.sectors = PF_HD_SPT; + geo->cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); + geo->heads = PF_HD_HDS; + geo->sectors = PF_HD_SPT; } - if (copy_to_user(geo, &g, sizeof(g))) - return -EFAULT; + + return 0; +} + +static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; + + if (cmd != CDROMEJECT) + return -EINVAL; + + if (pf->access != 1) + return -EBUSY; + pf_eject(pf); return 0; } diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 29d1518be72a..43415f69839f 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -81,8 +81,7 @@ static void (*current_int_handler) (u_int) = NULL; static void ps2esdi_normal_interrupt_handler(u_int); static void ps2esdi_initial_reset_int_handler(u_int); static void ps2esdi_geometry_int_handler(u_int); -static int ps2esdi_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg); +static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer); @@ -132,7 +131,7 @@ static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = static struct block_device_operations ps2esdi_fops = { .owner = THIS_MODULE, - .ioctl = ps2esdi_ioctl, + .getgeo = ps2esdi_getgeo, }; static struct gendisk *ps2esdi_gendisk[2]; @@ -1058,21 +1057,13 @@ static void dump_cmd_complete_status(u_int int_ret_code) } -static int ps2esdi_ioctl(struct inode *inode, - struct file *file, u_int cmd, u_long arg) +static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data; - struct ps2esdi_geometry geom; - - if (cmd != HDIO_GETGEO) - return -EINVAL; - memset(&geom, 0, sizeof(geom)); - geom.heads = p->head; - geom.sectors = p->sect; - geom.cylinders = p->cyl; - geom.start = get_start_sect(inode->i_bdev); - if (copy_to_user((void __user *)arg, &geom, sizeof(geom))) - return -EFAULT; + struct ps2esdi_i_struct *p = bdev->bd_disk->private_data; + + geo->heads = p->head; + geo->sectors = p->sect; + geo->cylinders = p->cyl; return 0; } diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 9251f4131b53..c0cdc182a8b0 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -407,8 +407,7 @@ struct carm_array_info { static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void carm_remove_one (struct pci_dev *pdev); -static int carm_bdev_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg); +static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo); static struct pci_device_id carm_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, @@ -426,7 +425,7 @@ static struct pci_driver carm_driver = { static struct block_device_operations carm_bd_ops = { .owner = THIS_MODULE, - .ioctl = carm_bdev_ioctl, + .getgeo = carm_bdev_getgeo, }; static unsigned int carm_host_id; @@ -434,32 +433,14 @@ static unsigned long carm_major_alloc; -static int carm_bdev_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg) +static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - void __user *usermem = (void __user *) arg; - struct carm_port *port = ino->i_bdev->bd_disk->private_data; - struct hd_geometry geom; + struct carm_port *port = bdev->bd_disk->private_data; - switch (cmd) { - case HDIO_GETGEO: - if (!usermem) - return -EINVAL; - - geom.heads = (u8) port->dev_geom_head; - geom.sectors = (u8) port->dev_geom_sect; - geom.cylinders = port->dev_geom_cyl; - geom.start = get_start_sect(ino->i_bdev); - - if (copy_to_user(usermem, &geom, sizeof(geom))) - return -EFAULT; - return 0; - - default: - break; - } - - return -EOPNOTSUPP; + geo->heads = (u8) port->dev_geom_head; + geo->sectors = (u8) port->dev_geom_sect; + geo->cylinders = port->dev_geom_cyl; + return 0; } static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 0f48301342da..15299e7a1ade 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -809,34 +809,23 @@ static int mm_revalidate(struct gendisk *disk) set_capacity(disk, card->mm_size << 1); return 0; } -/* ------------------------------------------------------------------------------------ --- mm_ioctl ------------------------------------------------------------------------------------ -*/ -static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) + +static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - if (cmd == HDIO_GETGEO) { - struct cardinfo *card = i->i_bdev->bd_disk->private_data; - int size = card->mm_size * (1024 / MM_HARDSECT); - struct hd_geometry geo; - /* - * get geometry: we have to fake one... trim the size to a - * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, - * whatever cylinders. - */ - geo.heads = 64; - geo.sectors = 32; - geo.start = get_start_sect(i->i_bdev); - geo.cylinders = size / (geo.heads * geo.sectors); - - if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) - return -EFAULT; - return 0; - } + struct cardinfo *card = bdev->bd_disk->private_data; + int size = card->mm_size * (1024 / MM_HARDSECT); - return -EINVAL; + /* + * get geometry: we have to fake one... trim the size to a + * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, + * whatever cylinders. + */ + geo->heads = 64; + geo->sectors = 32; + geo->cylinders = size / (geo->heads * geo->sectors); + return 0; } + /* ----------------------------------------------------------------------------------- -- mm_check_change @@ -855,7 +844,7 @@ static int mm_check_change(struct gendisk *disk) */ static struct block_device_operations mm_fops = { .owner = THIS_MODULE, - .ioctl = mm_ioctl, + .getgeo = mm_getgeo, .revalidate_disk= mm_revalidate, .media_changed = mm_check_change, }; diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 063f0304a163..d1aaf31bd97e 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -247,43 +247,17 @@ static int viodasd_release(struct inode *ino, struct file *fil) /* External ioctl entry point. */ -static int viodasd_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg) +static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - unsigned char sectors; - unsigned char heads; - unsigned short cylinders; - struct hd_geometry *geo; - struct gendisk *gendisk; - struct viodasd_device *d; + struct gendisk *disk = bdev->bd_disk; + struct viodasd_device *d = disk->private_data; - switch (cmd) { - case HDIO_GETGEO: - geo = (struct hd_geometry *)arg; - if (geo == NULL) - return -EINVAL; - if (!access_ok(VERIFY_WRITE, geo, sizeof(*geo))) - return -EFAULT; - gendisk = ino->i_bdev->bd_disk; - d = gendisk->private_data; - sectors = d->sectors; - if (sectors == 0) - sectors = 32; - heads = d->tracks; - if (heads == 0) - heads = 64; - cylinders = d->cylinders; - if (cylinders == 0) - cylinders = get_capacity(gendisk) / (sectors * heads); - if (__put_user(sectors, &geo->sectors) || - __put_user(heads, &geo->heads) || - __put_user(cylinders, &geo->cylinders) || - __put_user(get_start_sect(ino->i_bdev), &geo->start)) - return -EFAULT; - return 0; - } + geo->sectors = d->sectors ? d->sectors : 0; + geo->heads = d->tracks ? d->tracks : 64; + geo->cylinders = d->cylinders ? d->cylinders : + get_capacity(disk) / (geo->cylinders * geo->heads); - return -EINVAL; + return 0; } /* @@ -293,7 +267,7 @@ static struct block_device_operations viodasd_fops = { .owner = THIS_MODULE, .open = viodasd_open, .release = viodasd_release, - .ioctl = viodasd_ioctl, + .getgeo = viodasd_getgeo, }; /* diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 68b6d7b154cf..97f5dab24b5a 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -128,9 +128,12 @@ static DEFINE_SPINLOCK(xd_lock); static struct gendisk *xd_gendisk[2]; +static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo); + static struct block_device_operations xd_fops = { .owner = THIS_MODULE, .ioctl = xd_ioctl, + .getgeo = xd_getgeo, }; static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; @@ -330,22 +333,20 @@ static void do_xd_request (request_queue_t * q) } } +static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + XD_INFO *p = bdev->bd_disk->private_data; + + geo->heads = p->heads; + geo->sectors = p->sectors; + geo->cylinders = p->cylinders; + return 0; +} + /* xd_ioctl: handle device ioctl's */ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) { - XD_INFO *p = inode->i_bdev->bd_disk->private_data; - switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry g; - struct hd_geometry __user *geom= (void __user *)arg; - g.heads = p->heads; - g.sectors = p->sectors; - g.cylinders = p->cylinders; - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(geom, &g, sizeof(g)) ? -EFAULT : 0; - } case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 4b441720b6ba..cab362ea0336 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1130,6 +1130,17 @@ static int idedisk_release(struct inode *inode, struct file *filp) return 0; } +static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); + ide_drive_t *drive = idkp->drive; + + geo->heads = drive->bios_head; + geo->sectors = drive->bios_sect; + geo->cylinders = (u16)drive->bios_cyl; /* truncate */ + return 0; +} + static int idedisk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1164,6 +1175,7 @@ static struct block_device_operations idedisk_ops = { .open = idedisk_open, .release = idedisk_release, .ioctl = idedisk_ioctl, + .getgeo = idedisk_getgeo, .media_changed = idedisk_media_changed, .revalidate_disk= idedisk_revalidate_disk }; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index fba3fffc2d66..5945f551aaaa 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -2031,6 +2031,17 @@ static int idefloppy_release(struct inode *inode, struct file *filp) return 0; } +static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk); + ide_drive_t *drive = floppy->drive; + + geo->heads = drive->bios_head; + geo->sectors = drive->bios_sect; + geo->cylinders = (u16)drive->bios_cyl; /* truncate */ + return 0; +} + static int idefloppy_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2120,6 +2131,7 @@ static struct block_device_operations idefloppy_ops = { .open = idefloppy_open, .release = idefloppy_release, .ioctl = idefloppy_ioctl, + .getgeo = idefloppy_getgeo, .media_changed = idefloppy_media_changed, .revalidate_disk= idefloppy_revalidate_disk }; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 4b524f6b3ecd..b069b13b75a7 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1278,19 +1278,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device up(&ide_setting_sem); switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry geom; - if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; - geom.heads = drive->bios_head; - geom.sectors = drive->bios_sect; - geom.cylinders = (u16)drive->bios_cyl; /* truncate */ - geom.start = get_start_sect(bdev); - if (copy_to_user(p, &geom, sizeof(struct hd_geometry))) - return -EFAULT; - return 0; - } - case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (bdev != bdev->bd_contains) diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index 242029c9c0ca..6439dec66881 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -658,22 +658,14 @@ static void do_hd_request (request_queue_t * q) enable_irq(HD_IRQ); } -static int hd_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data; - struct hd_geometry __user *loc = (struct hd_geometry __user *) arg; - struct hd_geometry g; - - if (cmd != HDIO_GETGEO) - return -EINVAL; - if (!loc) - return -EINVAL; - g.heads = disk->head; - g.sectors = disk->sect; - g.cylinders = disk->cyl; - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; + struct hd_i_struct *disk = bdev->bd_disk->private_data; + + geo->heads = disk->head; + geo->sectors = disk->sect; + geo->cylinders = disk->cyl; + return 0; } /* @@ -695,7 +687,7 @@ static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) } static struct block_device_operations hd_fops = { - .ioctl = hd_ioctl, + .getgeo = hd_getgeo, }; /* diff --git a/drivers/md/md.c b/drivers/md/md.c index 1b76fb29fb70..e423a16ba3c9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3598,12 +3598,21 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev) return 0; } +static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + mddev_t *mddev = bdev->bd_disk->private_data; + + geo->heads = 2; + geo->sectors = 4; + geo->cylinders = get_capacity(mddev->gendisk) / 8; + return 0; +} + static int md_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; void __user *argp = (void __user *)arg; - struct hd_geometry __user *loc = argp; mddev_t *mddev = NULL; if (!capable(CAP_SYS_ADMIN)) @@ -3765,24 +3774,6 @@ static int md_ioctl(struct inode *inode, struct file *file, * 4 sectors (with a BIG number of cylinders...). This drives * dosfs just mad... ;-) */ - case HDIO_GETGEO: - if (!loc) { - err = -EINVAL; - goto abort_unlock; - } - err = put_user (2, (char __user *) &loc->heads); - if (err) - goto abort_unlock; - err = put_user (4, (char __user *) &loc->sectors); - if (err) - goto abort_unlock; - err = put_user(get_capacity(mddev->gendisk)/8, - (short __user *) &loc->cylinders); - if (err) - goto abort_unlock; - err = put_user (get_start_sect(inode->i_bdev), - (long __user *) &loc->start); - goto done_unlock; } /* @@ -3911,6 +3902,7 @@ static struct block_device_operations md_fops = .open = md_open, .release = md_release, .ioctl = md_ioctl, + .getgeo = md_getgeo, .media_changed = md_media_changed, .revalidate_disk= md_revalidate, }; diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 5b1febed3133..b09fb6307153 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -662,6 +662,13 @@ static int i2o_block_release(struct inode *inode, struct file *file) return 0; } +static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + i2o_block_biosparam(get_capacity(bdev->bd_disk), + &geo->cylinders, &geo->heads, &geo->sectors); + return 0; +} + /** * i2o_block_ioctl - Issue device specific ioctl calls. * @cmd: ioctl command @@ -676,7 +683,6 @@ static int i2o_block_ioctl(struct inode *inode, struct file *file, { struct gendisk *disk = inode->i_bdev->bd_disk; struct i2o_block_device *dev = disk->private_data; - void __user *argp = (void __user *)arg; /* Anyone capable of this syscall can do *real bad* things */ @@ -684,15 +690,6 @@ static int i2o_block_ioctl(struct inode *inode, struct file *file, return -EPERM; switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry g; - i2o_block_biosparam(get_capacity(disk), - &g.cylinders, &g.heads, &g.sectors); - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(argp, &g, sizeof(g)) ? -EFAULT : 0; - } - case BLKI2OGRSTRAT: return put_user(dev->rcache, (int __user *)arg); case BLKI2OGWSTRAT: @@ -962,6 +959,7 @@ static struct block_device_operations i2o_block_fops = { .open = i2o_block_open, .release = i2o_block_release, .ioctl = i2o_block_ioctl, + .getgeo = i2o_block_getgeo, .media_changed = i2o_block_media_changed }; diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 198561d21710..d5f28981596b 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -113,31 +113,18 @@ static int mmc_blk_release(struct inode *inode, struct file *filp) } static int -mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct block_device *bdev = inode->i_bdev; - - if (cmd == HDIO_GETGEO) { - struct hd_geometry geo; - - memset(&geo, 0, sizeof(struct hd_geometry)); - - geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16); - geo.heads = 4; - geo.sectors = 16; - geo.start = get_start_sect(bdev); - - return copy_to_user((void __user *)arg, &geo, sizeof(geo)) - ? -EFAULT : 0; - } - - return -ENOTTY; + geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16); + geo->heads = 4; + geo->sectors = 16; + return 0; } static struct block_device_operations mmc_bdops = { .open = mmc_blk_open, .release = mmc_blk_release, - .ioctl = mmc_blk_ioctl, + .getgeo = mmc_blk_getgeo, .owner = THIS_MODULE, }; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 339cb1218eaa..7f3ff500b68e 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -194,6 +194,14 @@ static int blktrans_release(struct inode *i, struct file *f) return ret; } +static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; + + if (dev->tr->getgeo) + return dev->tr->getgeo(dev, geo); + return -ENOTTY; +} static int blktrans_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -207,22 +215,6 @@ static int blktrans_ioctl(struct inode *inode, struct file *file, return tr->flush(dev); /* The core code did the work, we had nothing to do. */ return 0; - - case HDIO_GETGEO: - if (tr->getgeo) { - struct hd_geometry g; - int ret; - - memset(&g, 0, sizeof(g)); - ret = tr->getgeo(dev, &g); - if (ret) - return ret; - - g.start = get_start_sect(inode->i_bdev); - if (copy_to_user((void __user *)arg, &g, sizeof(g))) - return -EFAULT; - return 0; - } /* else */ default: return -ENOTTY; } @@ -233,6 +225,7 @@ struct block_device_operations mtd_blktrans_ops = { .open = blktrans_open, .release = blktrans_release, .ioctl = blktrans_ioctl, + .getgeo = blktrans_getgeo, }; int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f779f674dfa0..2472fa1a1be1 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1723,12 +1724,34 @@ dasd_release(struct inode *inp, struct file *filp) return 0; } +/* + * Return disk geometry. + */ +static int +dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct dasd_device *device; + + device = bdev->bd_disk->private_data; + if (!device) + return -ENODEV; + + if (!device->discipline || + !device->discipline->fill_geometry) + return -EINVAL; + + device->discipline->fill_geometry(device, geo); + geo->start = get_start_sect(bdev) >> device->s2b_shift; + return 0; +} + struct block_device_operations dasd_device_operations = { .owner = THIS_MODULE, .open = dasd_open, .release = dasd_release, .ioctl = dasd_ioctl, + .getgeo = dasd_getgeo, }; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 044b75371990..8e4dcd58599e 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -485,33 +485,6 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) return rc; } -/* - * Return disk geometry. - */ -static int -dasd_ioctl_getgeo(struct block_device *bdev, int no, long args) -{ - struct hd_geometry geo = { 0, }; - struct dasd_device *device; - - device = bdev->bd_disk->private_data; - if (device == NULL) - return -ENODEV; - - if (device == NULL || device->discipline == NULL || - device->discipline->fill_geometry == NULL) - return -EINVAL; - - geo = (struct hd_geometry) {}; - device->discipline->fill_geometry(device, &geo); - geo.start = get_start_sect(bdev) >> device->s2b_shift; - if (copy_to_user((struct hd_geometry __user *) args, &geo, - sizeof (struct hd_geometry))) - return -EFAULT; - - return 0; -} - /* * List of static ioctls. */ @@ -528,7 +501,6 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] = { BIODASDPRRST, dasd_ioctl_reset_profile }, { BLKROSET, dasd_ioctl_set_ro }, { DASDAPIVER, dasd_ioctl_api_version }, - { HDIO_GETGEO, dasd_ioctl_getgeo }, { -1, NULL } }; diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index bf3a67c3cc5e..54ecd548c318 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -328,31 +328,27 @@ fail: return 0; } -static int xpram_ioctl (struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct hd_geometry __user *geo; unsigned long size; - if (cmd != HDIO_GETGEO) - return -EINVAL; + /* * get geometry: we have to fake one... trim the size to a * multiple of 64 (32k): tell we have 16 sectors, 4 heads, * whatever cylinders. Tell also that data starts at sector. 4. */ - geo = (struct hd_geometry __user *) arg; size = (xpram_pages * 8) & ~0x3f; - put_user(size >> 6, &geo->cylinders); - put_user(4, &geo->heads); - put_user(16, &geo->sectors); - put_user(4, &geo->start); + geo->cylinders = size >> 6; + geo->heads = 4; + geo->sectors = 16; + geo->start = 4; return 0; } static struct block_device_operations xpram_devops = { .owner = THIS_MODULE, - .ioctl = xpram_ioctl, + .getgeo = xpram_getgeo, }; /* diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 32d4d8d7b9f3..4c5127ed379c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -527,7 +527,7 @@ static int sd_release(struct inode *inode, struct file *filp) return 0; } -static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *loc) +static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); struct scsi_device *sdp = sdkp->device; @@ -545,15 +545,9 @@ static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user * else scsicam_bios_param(bdev, sdkp->capacity, diskinfo); - if (put_user(diskinfo[0], &loc->heads)) - return -EFAULT; - if (put_user(diskinfo[1], &loc->sectors)) - return -EFAULT; - if (put_user(diskinfo[2], &loc->cylinders)) - return -EFAULT; - if (put_user((unsigned)get_start_sect(bdev), - (unsigned long __user *)&loc->start)) - return -EFAULT; + geo->heads = diskinfo[0]; + geo->sectors = diskinfo[1]; + geo->cylinders = diskinfo[2]; return 0; } @@ -593,12 +587,6 @@ static int sd_ioctl(struct inode * inode, struct file * filp, if (!scsi_block_when_processing_errors(sdp) || !error) return error; - if (cmd == HDIO_GETGEO) { - if (!arg) - return -EINVAL; - return sd_hdio_getgeo(bdev, p); - } - /* * Send SCSI addressing ioctls directly to mid level, send other * ioctls to block level and then onto mid level if they can't be @@ -800,6 +788,7 @@ static struct block_device_operations sd_fops = { .open = sd_open, .release = sd_release, .ioctl = sd_ioctl, + .getgeo = sd_getgeo, #ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl, #endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 74c01aabd4ab..7f140480c6a8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -224,6 +224,7 @@ extern int dir_notify_enable; #include #include +struct hd_geometry; struct iovec; struct nameidata; struct kiocb; @@ -962,6 +963,7 @@ struct block_device_operations { int (*direct_access) (struct block_device *, sector_t, unsigned long *); int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); + int (*getgeo)(struct block_device *, struct hd_geometry *); struct module *owner; }; -- cgit v1.2.3 From 9fa37fd1627ec804e57ae0388555719b03b39f20 Mon Sep 17 00:00:00 2001 From: "taneli.vahakangas@netsonic.fi" Date: Sun, 8 Jan 2006 01:03:02 -0800 Subject: [PATCH] nbd: remove duplicate assignment Sent by Paul Clements , who needs to read Documentation/SubmittingPatches.. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/nbd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 33d6f237b2ed..6997d8e6bfb5 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -174,7 +174,6 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_namelen = 0; msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (send) -- cgit v1.2.3 From 676121fcb66c861804e38d94214fd5670a1ef595 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Sun, 8 Jan 2006 01:03:04 -0800 Subject: [PATCH] Unchecked alloc_percpu() return in __create_workqueue() __create_workqueue() not checking return of alloc_percpu() NULL dereference was possible. Signed-off-by: Ben Collins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/workqueue.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 62d47220696a..e72fb6478da6 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -315,6 +315,11 @@ struct workqueue_struct *__create_workqueue(const char *name, return NULL; wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct); + if (!wq->cpu_wq) { + kfree(wq); + return NULL; + } + wq->name = name; /* We don't need the distraction of CPUs appearing and vanishing. */ lock_cpu_hotplug(); -- cgit v1.2.3 From 54b21a7992a31d30c9a91f7e0a00ffdb4bd0caee Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:03:05 -0800 Subject: [PATCH] fix possible PAGE_CACHE_SHIFT overflows We've had two instances recently of overflows when doing 64_bit_value = (32_bit_value << PAGE_CACHE_SHIFT) I did a tree-wide grep of `<<.*PAGE_CACHE_SHIFT' and this is the result. - afs_rxfs_fetch_descriptor.offset is of type off_t, which seems broken. - jfs and jffs are limited to 4GB anyway. - reiserfs map_block_for_writepage() takes an unsigned long for the block - it should take sector_t. (It'll fail for huge filesystems with blocksizepage_base) Cc: Oleg Drokin Cc: David Howells Cc: David Woodhouse Cc: Cc: Christoph Hellwig Cc: Anton Altaparmakov Cc: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Cc: Roman Zippel Cc: Cc: Miklos Szeredi Cc: Russell King Cc: Trond Myklebust Cc: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/dir.c | 2 +- fs/buffer.c | 6 +++--- fs/freevxfs/vxfs_immed.c | 4 ++-- fs/jffs/inode-v23.c | 4 ++-- fs/mpage.c | 4 ++-- fs/romfs/inode.c | 6 +++--- fs/smbfs/file.c | 4 ++-- fs/sysv/dir.c | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 6682d6d7f294..5c61c24dab2a 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -137,7 +137,7 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page) #endif /* determine how many magic numbers there should be in this page */ - latter = dir->i_size - (page->index << PAGE_CACHE_SHIFT); + latter = dir->i_size - page_offset(page); if (latter >= PAGE_SIZE) qty = PAGE_SIZE; else diff --git a/fs/buffer.c b/fs/buffer.c index 263df0f192aa..55f0975a9b15 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1762,7 +1762,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, * handle that here by just cleaning them. */ - block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); + block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); head = page_buffers(page); bh = head; @@ -2635,7 +2635,7 @@ int block_truncate_page(struct address_space *mapping, pgoff_t index = from >> PAGE_CACHE_SHIFT; unsigned offset = from & (PAGE_CACHE_SIZE-1); unsigned blocksize; - pgoff_t iblock; + sector_t iblock; unsigned length, pos; struct inode *inode = mapping->host; struct page *page; @@ -2651,7 +2651,7 @@ int block_truncate_page(struct address_space *mapping, return 0; length = blocksize - length; - iblock = index << (PAGE_CACHE_SHIFT - inode->i_blkbits); + iblock = (sector_t)index << (PAGE_CACHE_SHIFT - inode->i_blkbits); page = grab_cache_page(mapping, index); err = -ENOMEM; diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c index d0401dc68d41..6f5df1700e95 100644 --- a/fs/freevxfs/vxfs_immed.c +++ b/fs/freevxfs/vxfs_immed.c @@ -99,8 +99,8 @@ static int vxfs_immed_readpage(struct file *fp, struct page *pp) { struct vxfs_inode_info *vip = VXFS_INO(pp->mapping->host); - u_int64_t offset = pp->index << PAGE_CACHE_SHIFT; - caddr_t kaddr; + u_int64_t offset = (u_int64_t)pp->index << PAGE_CACHE_SHIFT; + caddr_t kaddr; kaddr = kmap(pp); memcpy(kaddr, vip->vii_immed.vi_immed + offset, PAGE_CACHE_SIZE); diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 3dcc6d2162cb..2559ee10beda 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -757,7 +757,7 @@ jffs_do_readpage_nolock(struct file *file, struct page *page) read_len = 0; result = 0; - offset = page->index << PAGE_CACHE_SHIFT; + offset = page_offset(page); kmap(page); buf = page_address(page); @@ -1545,7 +1545,7 @@ jffs_commit_write(struct file *filp, struct page *page, { void *addr = page_address(page) + from; /* XXX: PAGE_CACHE_SHIFT or PAGE_SHIFT */ - loff_t pos = (page->index<index << (PAGE_CACHE_SHIFT - blkbits); + block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits); last_block = (i_size_read(inode) + blocksize - 1) >> blkbits; bh.b_page = page; @@ -466,7 +466,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, * The page has no buffers: map it to disk */ BUG_ON(!PageUptodate(page)); - block_in_file = page->index << (PAGE_CACHE_SHIFT - blkbits); + block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits); last_block = (i_size - 1) >> blkbits; map_bh.b_page = page; for (page_block = 0; page_block < blocks_per_page; ) { diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index c74f382dabba..0a13859fd57b 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -418,7 +418,7 @@ static int romfs_readpage(struct file *file, struct page * page) { struct inode *inode = page->mapping->host; - unsigned long offset, avail, readlen; + loff_t offset, avail, readlen; void *buf; int result = -EIO; @@ -429,8 +429,8 @@ romfs_readpage(struct file *file, struct page * page) goto err_out; /* 32 bit warning -- but not for us :) */ - offset = page->index << PAGE_CACHE_SHIFT; - if (offset < inode->i_size) { + offset = page_offset(page); + if (offset < i_size_read(inode)) { avail = inode->i_size-offset; readlen = min_t(unsigned long, avail, PAGE_SIZE); if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) { diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 3c6eb3ba718e..7042e62726a4 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -209,8 +209,8 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset, { struct dentry *dentry = file->f_dentry; - DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry), - count, (page->index << PAGE_CACHE_SHIFT)+offset); + DEBUG1("(%s/%s %d@%lld)\n", DENTRY_PATH(dentry), count, + ((unsigned long long)page->index << PAGE_CACHE_SHIFT) + offset); return smb_writepage_sync(dentry->d_inode, page, offset, count); } diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 69a085abad6f..cce8b05cba5a 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -103,7 +103,7 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) offset = (char *)de - kaddr; over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN), - (n<inode), DT_UNKNOWN); if (over) { @@ -115,7 +115,7 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) } done: - filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; + filp->f_pos = ((loff_t)n << PAGE_CACHE_SHIFT) | offset; unlock_kernel(); return 0; } -- cgit v1.2.3 From 0811af28ce49fab963e3e6b8abcf8c460f971cd4 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:09 -0800 Subject: [PATCH] kill_proc_info_as_uid: don't use hardcoded constants Use symbolic names instead of hardcoded constants. Signed-off-by: Oleg Nesterov Acked-by: Harald Welte Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/signal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index e20724af9b36..114cf9209bcd 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1220,8 +1220,7 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, ret = -ESRCH; goto out_unlock; } - if ((!info || ((unsigned long)info != 1 && - (unsigned long)info != 2 && SI_FROMUSER(info))) + if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) && (euid != p->suid) && (euid != p->uid) && (uid != p->suid) && (uid != p->uid)) { ret = -EPERM; -- cgit v1.2.3 From bb6f6dbaa48c53525a7a4f9d4df719c3b0b582af Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:13 -0800 Subject: [PATCH] do_coredump() should reset group_stop_count earlier __group_complete_signal() sets ->group_stop_count in sig_kernel_coredump() path and marks the target thread as ->group_exit_task. So any thread except group_exit_task will go to handle_group_stop()->finish_stop(). However, when group_exit_task actually starts do_coredump(), it sets SIGNAL_GROUP_EXIT, but does not reset ->group_stop_count while killing other threads. If we have not yet stopped threads in the same thread group, they all will spin in kernel mode until group_exit_task sends them SIGKILL, because ->group_stop_count > 0 means: recalc_sigpending_tsk() never clears TIF_SIGPENDING get_signal_to_deliver() goes to handle_group_stop() handle_group_stop() returns when SIGNAL_GROUP_EXIT set syscall_exit/resume_userspace notice TIF_SIGPENDING, call get_signal_to_deliver() again. So we are wasting cpu cycles, and if one of these threads is rt_task() this may be a serious problem. NOTE: do_coredump() holds ->mmap_sem, so not stopped threads can't escape coredumping after clearing ->group_stop_count. See also this thread: http://marc.theaimsgroup.com/?t=112739139900002 Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/exec.c b/fs/exec.c index 2075b674d85e..fd02ea4a81e9 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1462,6 +1462,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { current->signal->flags = SIGNAL_GROUP_EXIT; current->signal->group_exit_code = exit_code; + current->signal->group_stop_count = 0; retval = 0; } spin_unlock_irq(¤t->sighand->siglock); @@ -1477,7 +1478,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) * Clear any false indication of pending signals that might * be seen by the filesystem code called to write the core file. */ - current->signal->group_stop_count = 0; clear_thread_flag(TIF_SIGPENDING); if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) -- cgit v1.2.3 From 485a6435abc3897934ce0dc530e31db93e9296a6 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:14 -0800 Subject: [PATCH] little do_group_exit() cleanup zap_other_threads() sets SIGNAL_GROUP_EXIT at the very start, do_group_exit() doesn't need to do it. Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/exit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/exit.c b/kernel/exit.c index c73a7eb26de3..a80824f6108b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -925,7 +925,6 @@ do_group_exit(int exit_code) /* Another thread got here before we took the lock. */ exit_code = sig->group_exit_code; else { - sig->flags = SIGNAL_GROUP_EXIT; sig->group_exit_code = exit_code; zap_other_threads(current); } -- cgit v1.2.3 From 55a82ab3181be039c6440d3f2f69260ad6fe2988 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sun, 8 Jan 2006 01:03:15 -0800 Subject: [PATCH] tpm: add bios measurement log According to the TCG specifications measurements or hashes of the BIOS code and data are extended into TPM PCRS and a log is kept in an ACPI table of these extensions for later validation if desired. This patch exports the values in the ACPI table through a security-fs seq_file. Signed-off-by: Seiji Munetoh Signed-off-by: Stefan Berger Signed-off-by: Reiner Sailer Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/osl.c | 2 + drivers/char/tpm/Makefile | 3 + drivers/char/tpm/tpm.c | 3 + drivers/char/tpm/tpm.h | 15 ++ drivers/char/tpm/tpm_bios.c | 508 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 531 insertions(+) create mode 100644 drivers/char/tpm/tpm_bios.c diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e3cd0b16031a..20c9a37643c7 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -204,11 +204,13 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size, return AE_OK; } +EXPORT_SYMBOL_GPL(acpi_os_map_memory); void acpi_os_unmap_memory(void __iomem * virt, acpi_size size) { iounmap(virt); } +EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); #ifdef ACPI_FUTURE_USAGE acpi_status diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 2392e404e8d1..ba4582d160fd 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,6 +2,9 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o +ifdef CONFIG_ACPI + obj-$(CONFIG_TCG_TPM) += tpm_bios.o +endif obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index a9be0e8eaea5..5a3870477ef1 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -466,6 +466,7 @@ void tpm_remove_hardware(struct device *dev) kfree(chip->vendor->miscdev.name); sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); + tpm_bios_log_teardown(chip->bios_dir); dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); @@ -593,6 +594,8 @@ dev_num_search_complete: sysfs_create_group(&dev->kobj, chip->vendor->attr_group); + chip->bios_dir = tpm_bios_log_setup(devname); + return 0; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 159882ca69dd..fd3a4beaa53d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -82,6 +82,8 @@ struct tpm_chip { struct tpm_vendor_specific *vendor; + struct dentry **bios_dir; + struct list_head list; }; @@ -107,3 +109,16 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); extern void tpm_remove_hardware(struct device *); extern int tpm_pm_suspend(struct device *, pm_message_t); extern int tpm_pm_resume(struct device *); + +#ifdef CONFIG_ACPI +extern struct dentry ** tpm_bios_log_setup(char *); +extern void tpm_bios_log_teardown(struct dentry **); +#else +static inline struct dentry* tpm_bios_log_setup(char *name) +{ + return NULL; +} +static inline void tpm_bios_log_teardown(struct dentry **dir) +{ +} +#endif diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c new file mode 100644 index 000000000000..5e1f4dfefa17 --- /dev/null +++ b/drivers/char/tpm/tpm_bios.c @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2005 IBM Corporation + * + * Authors: + * Seiji Munetoh + * Stefan Berger + * Reiner Sailer + * Kylene Hall + * + * Access to the eventlog extended by the TCG BIOS of PC platform + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "tpm.h" + +#define TCG_EVENT_NAME_LEN_MAX 255 +#define MAX_TEXT_EVENT 1000 /* Max event string length */ +#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ + +struct acpi_tcpa { + struct acpi_table_header hdr; + u16 reserved; + u32 log_max_len __attribute__ ((packed)); + u32 log_start_addr __attribute__ ((packed)); +}; + +struct tcpa_event { + u32 pcr_index; + u32 event_type; + u8 pcr_value[20]; /* SHA1 */ + u32 event_size; + u8 event_data[0]; +}; + +enum tcpa_event_types { + PREBOOT = 0, + POST_CODE, + UNUSED, + NO_ACTION, + SEPARATOR, + ACTION, + EVENT_TAG, + SCRTM_CONTENTS, + SCRTM_VERSION, + CPU_MICROCODE, + PLATFORM_CONFIG_FLAGS, + TABLE_OF_DEVICES, + COMPACT_HASH, + IPL, + IPL_PARTITION_DATA, + NONHOST_CODE, + NONHOST_CONFIG, + NONHOST_INFO, +}; + +static const char* tcpa_event_type_strings[] = { + "PREBOOT", + "POST CODE", + "", + "NO ACTION", + "SEPARATOR", + "ACTION", + "EVENT TAG", + "S-CRTM Contents", + "S-CRTM Version", + "CPU Microcode", + "Platform Config Flags", + "Table of Devices", + "Compact Hash", + "IPL", + "IPL Partition Data", + "Non-Host Code", + "Non-Host Config", + "Non-Host Info" +}; + +enum tcpa_pc_event_ids { + SMBIOS = 1, + BIS_CERT, + POST_BIOS_ROM, + ESCD, + CMOS, + NVRAM, + OPTION_ROM_EXEC, + OPTION_ROM_CONFIG, + OPTION_ROM_MICROCODE, + S_CRTM_VERSION, + S_CRTM_CONTENTS, + POST_CONTENTS, +}; + +static const char* tcpa_pc_event_id_strings[] = { + "" + "SMBIOS", + "BIS Certificate", + "POST BIOS ", + "ESCD ", + "CMOS", + "NVRAM", + "Option ROM", + "Option ROM config", + "Option ROM microcode", + "S-CRTM Version", + "S-CRTM Contents", + "S-CRTM POST Contents", +}; + +/* (Binary) bios measurement buffer */ +static void *tcg_eventlog; +static void *tcg_eventlog_addr_limit; /* MAX */ + +/* returns pointer to start of pos. entry of tcg log */ +static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + loff_t i; + void *addr = tcg_eventlog; + struct tcpa_event *event; + + /* read over *pos measurements */ + for (i = 0; i < *pos; i++) { + event = addr; + + if ((addr + sizeof(struct tcpa_event)) < + tcg_eventlog_addr_limit) { + if (event->event_type == 0 && event->event_size == 0) + return NULL; + addr += + sizeof(struct tcpa_event) + event->event_size; + } + } + + /* now check if current entry is valid */ + if ((addr + sizeof(struct tcpa_event)) >= tcg_eventlog_addr_limit) + return NULL; + + event = addr; + + if ((event->event_type == 0 && event->event_size == 0) || + ((addr + sizeof(struct tcpa_event) + event->event_size) >= + tcg_eventlog_addr_limit)) + return NULL; + + return addr; +} + +static void *tpm_bios_measurements_next(struct seq_file *m, void *v, + loff_t *pos) +{ + struct tcpa_event *event = v; + + v += sizeof(struct tcpa_event) + event->event_size; + + /* now check if current entry is valid */ + if ((v + sizeof(struct tcpa_event)) >= tcg_eventlog_addr_limit) + return NULL; + + event = v; + + if (event->event_type == 0 && event->event_size == 0) + return NULL; + + if ((event->event_type == 0 && event->event_size == 0) || + ((v + sizeof(struct tcpa_event) + event->event_size) >= + tcg_eventlog_addr_limit)) + return NULL; + + (*pos)++; + return v; +} + +static void tpm_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +static int get_event_name(char *dest, struct tcpa_event *event, + unsigned char * event_entry) +{ + const char *name = ""; + char data[40] = ""; + int i, n_len = 0, d_len = 0; + u32 event_id, event_data_size; + + switch(event->event_type) { + case PREBOOT: + case POST_CODE: + case UNUSED: + case NO_ACTION: + case SCRTM_CONTENTS: + case SCRTM_VERSION: + case CPU_MICROCODE: + case PLATFORM_CONFIG_FLAGS: + case TABLE_OF_DEVICES: + case COMPACT_HASH: + case IPL: + case IPL_PARTITION_DATA: + case NONHOST_CODE: + case NONHOST_CONFIG: + case NONHOST_INFO: + name = tcpa_event_type_strings[event->event_type]; + n_len = strlen(name); + break; + case SEPARATOR: + case ACTION: + if (MAX_TEXT_EVENT > event->event_size) { + name = event_entry; + n_len = event->event_size; + } + break; + case EVENT_TAG: + event_id = be32_to_cpu(event_entry); + event_data_size = be32_to_cpu(&event_entry[4]); + + /* ToDo Row data -> Base64 */ + + switch (event_id) { + case SMBIOS: + case BIS_CERT: + case CMOS: + case NVRAM: + case OPTION_ROM_EXEC: + case OPTION_ROM_CONFIG: + case OPTION_ROM_MICROCODE: + case S_CRTM_VERSION: + case S_CRTM_CONTENTS: + case POST_CONTENTS: + name = tcpa_pc_event_id_strings[event_id]; + n_len = strlen(name); + break; + case POST_BIOS_ROM: + case ESCD: + name = tcpa_pc_event_id_strings[event_id]; + n_len = strlen(name); + for (i = 0; i < 20; i++) + d_len += sprintf(data, "%02x", + event_entry[8 + i]); + break; + default: + break; + } + default: + break; + } + + return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]", + n_len, name, d_len, data); + +} + +static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) +{ + + char *eventname; + char data[4]; + u32 help; + int i, len; + struct tcpa_event *event = (struct tcpa_event *) v; + unsigned char *event_entry = + (unsigned char *) (v + sizeof(struct tcpa_event)); + + eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); + if (!eventname) { + printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", + __func__); + return -ENOMEM; + } + + /* 1st: PCR used is in little-endian format (4 bytes) */ + help = le32_to_cpu(event->pcr_index); + memcpy(data, &help, 4); + for (i = 0; i < 4; i++) + seq_putc(m, data[i]); + + /* 2nd: SHA1 (20 bytes) */ + for (i = 0; i < 20; i++) + seq_putc(m, event->pcr_value[i]); + + /* 3rd: event type identifier (4 bytes) */ + help = le32_to_cpu(event->event_type); + memcpy(data, &help, 4); + for (i = 0; i < 4; i++) + seq_putc(m, data[i]); + + len = 0; + + len += get_event_name(eventname, event, event_entry); + + /* 4th: filename <= 255 + \'0' delimiter */ + if (len > TCG_EVENT_NAME_LEN_MAX) + len = TCG_EVENT_NAME_LEN_MAX; + + for (i = 0; i < len; i++) + seq_putc(m, eventname[i]); + + /* 5th: delimiter */ + seq_putc(m, '\0'); + + return 0; +} + +static int tpm_bios_measurements_release(struct inode *inode, + struct file *file) +{ + if (tcg_eventlog) { + kfree(tcg_eventlog); + tcg_eventlog = NULL; + } + return seq_release(inode, file); +} + +static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) +{ + int len = 0; + int i; + char *eventname; + struct tcpa_event *event = v; + unsigned char *event_entry = + (unsigned char *) (v + sizeof(struct tcpa_event)); + + eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); + if (!eventname) { + printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", + __func__); + return -EFAULT; + } + + seq_printf(m, "%2d ", event->pcr_index); + + /* 2nd: SHA1 */ + for (i = 0; i < 20; i++) + seq_printf(m, "%02x", event->pcr_value[i]); + + /* 3rd: event type identifier */ + seq_printf(m, " %02x", event->event_type); + + len += get_event_name(eventname, event, event_entry); + + /* 4th: eventname <= max + \'0' delimiter */ + seq_printf(m, " %s\n", eventname); + + return 0; +} + +static struct seq_operations tpm_ascii_b_measurments_seqops = { + .start = tpm_bios_measurements_start, + .next = tpm_bios_measurements_next, + .stop = tpm_bios_measurements_stop, + .show = tpm_ascii_bios_measurements_show, +}; + +static struct seq_operations tpm_binary_b_measurments_seqops = { + .start = tpm_bios_measurements_start, + .next = tpm_bios_measurements_next, + .stop = tpm_bios_measurements_stop, + .show = tpm_binary_bios_measurements_show, +}; + +/* read binary bios log */ +static int read_log(void) +{ + struct acpi_tcpa *buff; + acpi_status status; + void *virt; + + if (tcg_eventlog != NULL) { + printk(KERN_ERR + "%s: ERROR - Eventlog already initialized\n", + __func__); + return -EFAULT; + } + + /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ + status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1, + ACPI_LOGICAL_ADDRESSING, + (struct acpi_table_header **) + &buff); + + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", + __func__); + return -EIO; + } + + if (buff->log_max_len == 0) { + printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", + __func__); + return -EIO; + } + + /* malloc EventLog space */ + tcg_eventlog = kmalloc(buff->log_max_len, GFP_KERNEL); + if (!tcg_eventlog) { + printk + ("%s: ERROR - Not enough Memory for BIOS measurements\n", + __func__); + return -ENOMEM; + } + + tcg_eventlog_addr_limit = tcg_eventlog + buff->log_max_len; + + acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, &virt); + + memcpy(tcg_eventlog, virt, buff->log_max_len); + + acpi_os_unmap_memory(virt, buff->log_max_len); + return 0; +} + +static int tpm_ascii_bios_measurements_open(struct inode *inode, + struct file *file) +{ + int err; + + if ((err = read_log())) + return err; + + /* now register seq file */ + return seq_open(file, &tpm_ascii_b_measurments_seqops); +} + +struct file_operations tpm_ascii_bios_measurements_ops = { + .open = tpm_ascii_bios_measurements_open, + .read = seq_read, + .llseek = seq_lseek, + .release = tpm_bios_measurements_release, +}; + +static int tpm_binary_bios_measurements_open(struct inode *inode, + struct file *file) +{ + int err; + + if ((err = read_log())) + return err; + + /* now register seq file */ + return seq_open(file, &tpm_binary_b_measurments_seqops); +} + +struct file_operations tpm_binary_bios_measurements_ops = { + .open = tpm_binary_bios_measurements_open, + .read = seq_read, + .llseek = seq_lseek, + .release = tpm_bios_measurements_release, +}; + +struct dentry **tpm_bios_log_setup(char *name) +{ + struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; + + tpm_dir = securityfs_create_dir(name, NULL); + if (!tpm_dir) + goto out; + + bin_file = + securityfs_create_file("binary_bios_measurements", + S_IRUSR | S_IRGRP, tpm_dir, NULL, + &tpm_binary_bios_measurements_ops); + if (!bin_file) + goto out_tpm; + + ascii_file = + securityfs_create_file("ascii_bios_measurements", + S_IRUSR | S_IRGRP, tpm_dir, NULL, + &tpm_ascii_bios_measurements_ops); + if (!ascii_file) + goto out_bin; + + ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); + if (!ret) + goto out_ascii; + + ret[0] = ascii_file; + ret[1] = bin_file; + ret[2] = tpm_dir; + + return ret; + +out_ascii: + securityfs_remove(ascii_file); +out_bin: + securityfs_remove(bin_file); +out_tpm: + securityfs_remove(tpm_dir); +out: + return NULL; +} +EXPORT_SYMBOL_GPL(tpm_bios_log_setup); + +void tpm_bios_log_teardown(struct dentry **lst) +{ + int i; + + for (i = 0; i < 3; i++) + securityfs_remove(lst[i]); +} +EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); -- cgit v1.2.3 From c809406b4f2dfac9006d7eb8dca6b9f990f10b61 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Sun, 8 Jan 2006 01:03:17 -0800 Subject: [PATCH] Updated CPU hotplug documentation Thanks to Nathan Lynch for the review and comments. Thanks to Joel Schopp for the pointer to add user space scipts. Signed-off-by: Ashok Raj Signed-off-by: Nathan Lynch Signed-off-by: Joel Schopp Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cpu-hotplug.txt | 357 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 Documentation/cpu-hotplug.txt diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt new file mode 100644 index 000000000000..08c5d04f3086 --- /dev/null +++ b/Documentation/cpu-hotplug.txt @@ -0,0 +1,357 @@ + CPU hotplug Support in Linux(tm) Kernel + + Maintainers: + CPU Hotplug Core: + Rusty Russell + Srivatsa Vaddagiri + i386: + Zwane Mwaikambo + ppc64: + Nathan Lynch + Joel Schopp + ia64/x86_64: + Ashok Raj + +Authors: Ashok Raj +Lots of feedback: Nathan Lynch , + Joel Schopp + +Introduction + +Modern advances in system architectures have introduced advanced error +reporting and correction capabilities in processors. CPU architectures permit +partitioning support, where compute resources of a single CPU could be made +available to virtual machine environments. There are couple OEMS that +support NUMA hardware which are hot pluggable as well, where physical +node insertion and removal require support for CPU hotplug. + +Such advances require CPUs available to a kernel to be removed either for +provisioning reasons, or for RAS purposes to keep an offending CPU off +system execution path. Hence the need for CPU hotplug support in the +Linux kernel. + +A more novel use of CPU-hotplug support is its use today in suspend +resume support for SMP. Dual-core and HT support makes even +a laptop run SMP kernels which didn't support these methods. SMP support +for suspend/resume is a work in progress. + +General Stuff about CPU Hotplug +-------------------------------- + +Command Line Switches +--------------------- +maxcpus=n Restrict boot time cpus to n. Say if you have 4 cpus, using + maxcpus=2 will only boot 2. You can choose to bring the + other cpus later online, read FAQ's for more info. + +additional_cpus=n [x86_64 only] use this to limit hotpluggable cpus. + This option sets + cpu_possible_map = cpu_present_map + additional_cpus + +CPU maps and such +----------------- +[More on cpumaps and primitive to manipulate, please check +include/linux/cpumask.h that has more descriptive text.] + +cpu_possible_map: Bitmap of possible CPUs that can ever be available in the +system. This is used to allocate some boot time memory for per_cpu variables +that aren't designed to grow/shrink as CPUs are made available or removed. +Once set during boot time discovery phase, the map is static, i.e no bits +are added or removed anytime. Trimming it accurately for your system needs +upfront can save some boot time memory. See below for how we use heuristics +in x86_64 case to keep this under check. + +cpu_online_map: Bitmap of all CPUs currently online. Its set in __cpu_up() +after a cpu is available for kernel scheduling and ready to receive +interrupts from devices. Its cleared when a cpu is brought down using +__cpu_disable(), before which all OS services including interrupts are +migrated to another target CPU. + +cpu_present_map: Bitmap of CPUs currently present in the system. Not all +of them may be online. When physical hotplug is processed by the relevant +subsystem (e.g ACPI) can change and new bit either be added or removed +from the map depending on the event is hot-add/hot-remove. There are currently +no locking rules as of now. Typical usage is to init topology during boot, +at which time hotplug is disabled. + +You really dont need to manipulate any of the system cpu maps. They should +be read-only for most use. When setting up per-cpu resources almost always use +cpu_possible_map/for_each_cpu() to iterate. + +Never use anything other than cpumask_t to represent bitmap of CPUs. + +#include + +for_each_cpu - Iterate over cpu_possible_map +for_each_online_cpu - Iterate over cpu_online_map +for_each_present_cpu - Iterate over cpu_present_map +for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask. + +#include +lock_cpu_hotplug() and unlock_cpu_hotplug(): + +The above calls are used to inhibit cpu hotplug operations. While holding the +cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid +cpus going away, you could also use preempt_disable() and preempt_enable() +for those sections. Just remember the critical section cannot call any +function that can sleep or schedule this process away. The preempt_disable() +will work as long as stop_machine_run() is used to take a cpu down. + +CPU Hotplug - Frequently Asked Questions. + +Q: How to i enable my kernel to support CPU hotplug? +A: When doing make defconfig, Enable CPU hotplug support + + "Processor type and Features" -> Support for Hotpluggable CPUs + +Make sure that you have CONFIG_HOTPLUG, and CONFIG_SMP turned on as well. + +You would need to enable CONFIG_HOTPLUG_CPU for SMP suspend/resume support +as well. + +Q: What architectures support CPU hotplug? +A: As of 2.6.14, the following architectures support CPU hotplug. + +i386 (Intel), ppc, ppc64, parisc, s390, ia64 and x86_64 + +Q: How to test if hotplug is supported on the newly built kernel? +A: You should now notice an entry in sysfs. + +Check if sysfs is mounted, using the "mount" command. You should notice +an entry as shown below in the output. + +.... +none on /sys type sysfs (rw) +.... + +if this is not mounted, do the following. + +#mkdir /sysfs +#mount -t sysfs sys /sys + +now you should see entries for all present cpu, the following is an example +in a 8-way system. + +#pwd +#/sys/devices/system/cpu +#ls -l +total 0 +drwxr-xr-x 10 root root 0 Sep 19 07:44 . +drwxr-xr-x 13 root root 0 Sep 19 07:45 .. +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0 +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1 +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2 +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3 +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4 +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5 +drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6 +drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7 + +Under each directory you would find an "online" file which is the control +file to logically online/offline a processor. + +Q: Does hot-add/hot-remove refer to physical add/remove of cpus? +A: The usage of hot-add/remove may not be very consistently used in the code. +CONFIG_CPU_HOTPLUG enables logical online/offline capability in the kernel. +To support physical addition/removal, one would need some BIOS hooks and +the platform should have something like an attention button in PCI hotplug. +CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs. + +Q: How do i logically offline a CPU? +A: Do the following. + +#echo 0 > /sys/devices/system/cpu/cpuX/online + +once the logical offline is successful, check + +#cat /proc/interrupts + +you should now not see the CPU that you removed. Also online file will report +the state as 0 when a cpu if offline and 1 when its online. + +#To display the current cpu state. +#cat /sys/devices/system/cpu/cpuX/online + +Q: Why cant i remove CPU0 on some systems? +A: Some architectures may have some special dependency on a certain CPU. + +For e.g in IA64 platforms we have ability to sent platform interrupts to the +OS. a.k.a Corrected Platform Error Interrupts (CPEI). In current ACPI +specifications, we didn't have a way to change the target CPU. Hence if the +current ACPI version doesn't support such re-direction, we disable that CPU +by making it not-removable. + +In such cases you will also notice that the online file is missing under cpu0. + +Q: How do i find out if a particular CPU is not removable? +A: Depending on the implementation, some architectures may show this by the +absence of the "online" file. This is done if it can be determined ahead of +time that this CPU cannot be removed. + +In some situations, this can be a run time check, i.e if you try to remove the +last CPU, this will not be permitted. You can find such failures by +investigating the return value of the "echo" command. + +Q: What happens when a CPU is being logically offlined? +A: The following happen, listed in no particular order :-) + +- A notification is sent to in-kernel registered modules by sending an event + CPU_DOWN_PREPARE +- All process is migrated away from this outgoing CPU to a new CPU +- All interrupts targeted to this CPU is migrated to a new CPU +- timers/bottom half/task lets are also migrated to a new CPU +- Once all services are migrated, kernel calls an arch specific routine + __cpu_disable() to perform arch specific cleanup. +- Once this is successful, an event for successful cleanup is sent by an event + CPU_DEAD. + + "It is expected that each service cleans up when the CPU_DOWN_PREPARE + notifier is called, when CPU_DEAD is called its expected there is nothing + running on behalf of this CPU that was offlined" + +Q: If i have some kernel code that needs to be aware of CPU arrival and + departure, how to i arrange for proper notification? +A: This is what you would need in your kernel code to receive notifications. + + #include + static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) + { + unsigned int cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + foobar_online_action(cpu); + break; + case CPU_DEAD: + foobar_dead_action(cpu); + break; + } + return NOTIFY_OK; + } + + static struct notifier_block foobar_cpu_notifer = + { + .notifier_call = foobar_cpu_callback, + }; + + +In your init function, + + register_cpu_notifier(&foobar_cpu_notifier); + +You can fail PREPARE notifiers if something doesn't work to prepare resources. +This will stop the activity and send a following CANCELED event back. + +CPU_DEAD should not be failed, its just a goodness indication, but bad +things will happen if a notifier in path sent a BAD notify code. + +Q: I don't see my action being called for all CPUs already up and running? +A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined. + If you need to perform some action for each cpu already in the system, then + + for_each_online_cpu(i) { + foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i); + foobar_cpu_callback(&foobar-cpu_notifier, CPU_ONLINE, i); + } + +Q: If i would like to develop cpu hotplug support for a new architecture, + what do i need at a minimum? +A: The following are what is required for CPU hotplug infrastructure to work + correctly. + + - Make sure you have an entry in Kconfig to enable CONFIG_HOTPLUG_CPU + - __cpu_up() - Arch interface to bring up a CPU + - __cpu_disable() - Arch interface to shutdown a CPU, no more interrupts + can be handled by the kernel after the routine + returns. Including local APIC timers etc are + shutdown. + - __cpu_die() - This actually supposed to ensure death of the CPU. + Actually look at some example code in other arch + that implement CPU hotplug. The processor is taken + down from the idle() loop for that specific + architecture. __cpu_die() typically waits for some + per_cpu state to be set, to ensure the processor + dead routine is called to be sure positively. + +Q: I need to ensure that a particular cpu is not removed when there is some + work specific to this cpu is in progress. +A: First switch the current thread context to preferred cpu + + int my_func_on_cpu(int cpu) + { + cpumask_t saved_mask, new_mask = CPU_MASK_NONE; + int curr_cpu, err = 0; + + saved_mask = current->cpus_allowed; + cpu_set(cpu, new_mask); + err = set_cpus_allowed(current, new_mask); + + if (err) + return err; + + /* + * If we got scheduled out just after the return from + * set_cpus_allowed() before running the work, this ensures + * we stay locked. + */ + curr_cpu = get_cpu(); + + if (curr_cpu != cpu) { + err = -EAGAIN; + goto ret; + } else { + /* + * Do work : But cant sleep, since get_cpu() disables preempt + */ + } + ret: + put_cpu(); + set_cpus_allowed(current, saved_mask); + return err; + } + + +Q: How do we determine how many CPUs are available for hotplug. +A: There is no clear spec defined way from ACPI that can give us that + information today. Based on some input from Natalie of Unisys, + that the ACPI MADT (Multiple APIC Description Tables) marks those possible + CPUs in a system with disabled status. + + Andi implemented some simple heuristics that count the number of disabled + CPUs in MADT as hotpluggable CPUS. In the case there are no disabled CPUS + we assume 1/2 the number of CPUs currently present can be hotplugged. + + Caveat: Today's ACPI MADT can only provide 256 entries since the apicid field + in MADT is only 8 bits. + +User Space Notification + +Hotplug support for devices is common in Linux today. Its being used today to +support automatic configuration of network, usb and pci devices. A hotplug +event can be used to invoke an agent script to perform the configuration task. + +You can add /etc/hotplug/cpu.agent to handle hotplug notification user space +scripts. + + #!/bin/bash + # $Id: cpu.agent + # Kernel hotplug params include: + #ACTION=%s [online or offline] + #DEVPATH=%s + # + cd /etc/hotplug + . ./hotplug.functions + + case $ACTION in + online) + echo `date` ":cpu.agent" add cpu >> /tmp/hotplug.txt + ;; + offline) + echo `date` ":cpu.agent" remove cpu >>/tmp/hotplug.txt + ;; + *) + debug_mesg CPU $ACTION event not supported + exit 1 + ;; + esac -- cgit v1.2.3 From 4a0d11fae57989e24fe2ee3eff6d62d72db9716c Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Sun, 8 Jan 2006 01:03:18 -0800 Subject: [PATCH] pivot_root: add comment Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namespace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 2019899f2ab8..e5aa1eeb5748 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1526,6 +1526,10 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) * pointed to by put_old must yield the same directory as new_root. No other * file system may be mounted on put_old. After all, new_root is a mountpoint. * + * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem. + * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives + * in this situation. + * * Notes: * - we don't move root/cwd if they are not at the root (reason: if something * cared enough to change them, it's probably wrong to force them elsewhere) -- cgit v1.2.3 From bf066c7db775a04bd761f8ea206f5522d0cf40ff Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Sun, 8 Jan 2006 01:03:19 -0800 Subject: [PATCH] shared mounts: cleanup Small cleanups in shared mounts code. Signed-off-by: Miklos Szeredi Cc: Ram Pai Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namespace.c | 2 +- fs/pnode.c | 2 +- include/linux/fs.h | 2 +- include/linux/mount.h | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index e5aa1eeb5748..3e8fb61ad597 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -451,7 +451,7 @@ EXPORT_SYMBOL(may_umount); void release_mounts(struct list_head *head) { struct vfsmount *mnt; - while(!list_empty(head)) { + while (!list_empty(head)) { mnt = list_entry(head->next, struct vfsmount, mnt_hash); list_del_init(&mnt->mnt_hash); if (mnt->mnt_parent != mnt) { diff --git a/fs/pnode.c b/fs/pnode.c index aeeec8ba8dd2..f1871f773f64 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -103,7 +103,7 @@ static struct vfsmount *propagation_next(struct vfsmount *m, struct vfsmount *next; struct vfsmount *master = m->mnt_master; - if ( master == origin->mnt_master ) { + if (master == origin->mnt_master) { next = next_peer(m); return ((next == origin) ? NULL : next); } else if (m->mnt_slave.next != &master->mnt_slave_list) diff --git a/include/linux/fs.h b/include/linux/fs.h index 7f140480c6a8..a1e28f0895c0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -103,11 +103,11 @@ extern int dir_notify_enable; #define MS_MOVE 8192 #define MS_REC 16384 #define MS_VERBOSE 32768 +#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_UNBINDABLE (1<<17) /* change to unbindable */ #define MS_PRIVATE (1<<18) /* change to private */ #define MS_SLAVE (1<<19) /* change to slave */ #define MS_SHARED (1<<20) /* change to shared */ -#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) diff --git a/include/linux/mount.h b/include/linux/mount.h index dd4e83eba933..b98a709f1794 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -22,7 +22,8 @@ #define MNT_NOEXEC 0x04 #define MNT_SHARED 0x10 /* if the vfsmount is a shared mount */ #define MNT_UNBINDABLE 0x20 /* if the vfsmount is a unbindable mount */ -#define MNT_PNODE_MASK 0x30 /* propogation flag mask */ + +#define MNT_PNODE_MASK (MNT_SHARED | MNT_UNBINDABLE) struct vfsmount { struct list_head mnt_hash; -- cgit v1.2.3 From 71b9625744b7d4a6a2416389a5ba464bdf11f07f Mon Sep 17 00:00:00 2001 From: Johann Lombardi Date: Sun, 8 Jan 2006 01:03:20 -0800 Subject: [PATCH] ext3: external journal device as a mount option The patch below adds a new mount option to allow the external journal device to be specified. The syntax is as follows: # mount -t ext3 -o journal_dev=0x0820 ... where 0x0820 means major=8 and minor=32. Signed-off-by: Johann Lombardi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/ext3.txt | 5 ++++ fs/ext3/super.c | 54 +++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt index 9840d5b8d5b9..22e4040564d5 100644 --- a/Documentation/filesystems/ext3.txt +++ b/Documentation/filesystems/ext3.txt @@ -22,6 +22,11 @@ journal=inum When a journal already exists, this option is the inode which will represent the ext3 file system's journal file. +journal_dev=devnum When the external journal device's major/minor numbers + have changed, this option allows to specify the new + journal location. The journal device is identified + through its new major/minor numbers encoded in devnum. + noload Don't load the journal on mounting. data=journal All data are committed into the journal prior diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 4e6730622d90..7c45acf94589 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -43,7 +43,8 @@ #include "acl.h" #include "namei.h" -static int ext3_load_journal(struct super_block *, struct ext3_super_block *); +static int ext3_load_journal(struct super_block *, struct ext3_super_block *, + unsigned long journal_devnum); static int ext3_create_journal(struct super_block *, struct ext3_super_block *, int); static void ext3_commit_super (struct super_block * sb, @@ -628,7 +629,7 @@ enum { Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, - Opt_commit, Opt_journal_update, Opt_journal_inum, + Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, @@ -666,6 +667,7 @@ static match_table_t tokens = { {Opt_commit, "commit=%u"}, {Opt_journal_update, "journal=update"}, {Opt_journal_inum, "journal=%u"}, + {Opt_journal_dev, "journal_dev=%u"}, {Opt_abort, "abort"}, {Opt_data_journal, "data=journal"}, {Opt_data_ordered, "data=ordered"}, @@ -705,8 +707,9 @@ static unsigned long get_sb_block(void **data) return sb_block; } -static int parse_options (char * options, struct super_block *sb, - unsigned long * inum, unsigned long *n_blocks_count, int is_remount) +static int parse_options (char *options, struct super_block *sb, + unsigned long *inum, unsigned long *journal_devnum, + unsigned long *n_blocks_count, int is_remount) { struct ext3_sb_info *sbi = EXT3_SB(sb); char * p; @@ -839,6 +842,16 @@ static int parse_options (char * options, struct super_block *sb, return 0; *inum = option; break; + case Opt_journal_dev: + if (is_remount) { + printk(KERN_ERR "EXT3-fs: cannot specify " + "journal on remount\n"); + return 0; + } + if (match_int(&args[0], &option)) + return 0; + *journal_devnum = option; + break; case Opt_noload: set_opt (sbi->s_mount_opt, NOLOAD); break; @@ -1331,6 +1344,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) unsigned long logic_sb_block; unsigned long offset = 0; unsigned long journal_inum = 0; + unsigned long journal_devnum = 0; unsigned long def_mount_opts; struct inode *root; int blocksize; @@ -1411,7 +1425,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, RESERVATION); - if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0)) + if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, + NULL, 0)) goto failed_mount; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | @@ -1622,7 +1637,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) */ if (!test_opt(sb, NOLOAD) && EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { - if (ext3_load_journal(sb, es)) + if (ext3_load_journal(sb, es, journal_devnum)) goto failed_mount2; } else if (journal_inum) { if (ext3_create_journal(sb, es, journal_inum)) @@ -1902,15 +1917,24 @@ out_bdev: return NULL; } -static int ext3_load_journal(struct super_block * sb, - struct ext3_super_block * es) +static int ext3_load_journal(struct super_block *sb, + struct ext3_super_block *es, + unsigned long journal_devnum) { journal_t *journal; int journal_inum = le32_to_cpu(es->s_journal_inum); - dev_t journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev)); + dev_t journal_dev; int err = 0; int really_read_only; + if (journal_devnum && + journal_devnum != le32_to_cpu(es->s_journal_dev)) { + printk(KERN_INFO "EXT3-fs: external journal device major/minor " + "numbers have changed\n"); + journal_dev = new_decode_dev(journal_devnum); + } else + journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev)); + really_read_only = bdev_read_only(sb->s_bdev); /* @@ -1969,6 +1993,16 @@ static int ext3_load_journal(struct super_block * sb, EXT3_SB(sb)->s_journal = journal; ext3_clear_journal_err(sb, es); + + if (journal_devnum && + journal_devnum != le32_to_cpu(es->s_journal_dev)) { + es->s_journal_dev = cpu_to_le32(journal_devnum); + sb->s_dirt = 1; + + /* Make sure we flush the recovery flag to disk. */ + ext3_commit_super(sb, es, 1); + } + return 0; } @@ -2197,7 +2231,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) /* * Allow the "check" option to be passed as a remount option. */ - if (!parse_options(data, sb, NULL, &n_blocks_count, 1)) { + if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) { err = -EINVAL; goto restore_opts; } -- cgit v1.2.3 From 25ab7cd84eebdc1869d236029ada3a7b403de8ba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Jan 2006 01:03:21 -0800 Subject: [PATCH] oprofile: Use vmalloc_node() in alloc_cpu_buffers() Make oprofile alloc_cpu_buffers() function NUMA aware, allocating each CPU local buffer in its memory node if possible. Signed-off-by: Eric Dumazet Cc: Philippe Elie Cc: John Levon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/oprofile/cpu_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 026f671ea558..78193e4bbdb5 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -52,7 +52,8 @@ int alloc_cpu_buffers(void) for_each_online_cpu(i) { struct oprofile_cpu_buffer * b = &cpu_buffer[i]; - b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size); + b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, + cpu_to_node(i)); if (!b->buffer) goto fail; -- cgit v1.2.3 From 9f40668d7d14d4d16cedc2104bfb63a43584dacf Mon Sep 17 00:00:00 2001 From: Glauber de Oliveira Costa Date: Sun, 8 Jan 2006 01:03:22 -0800 Subject: [PATCH] ext3: remove trailing newlines from ext3_warning() calls Remove the trailing newlines in calls to ext3_warning(). This function already adds a trailing newline to the end of messages. Signed-off-by: Glauber de Oliveira Costa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/ialloc.c | 6 +++--- fs/ext3/namei.c | 2 +- fs/ext3/resize.c | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 9e4a24376210..69078079b19c 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -651,7 +651,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) /* Error cases - e2fsck has already cleaned up for us */ if (ino > max_ino) { ext3_warning(sb, __FUNCTION__, - "bad orphan ino %lu! e2fsck was run?\n", ino); + "bad orphan ino %lu! e2fsck was run?", ino); goto out; } @@ -660,7 +660,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) bitmap_bh = read_inode_bitmap(sb, block_group); if (!bitmap_bh) { ext3_warning(sb, __FUNCTION__, - "inode bitmap error for orphan %lu\n", ino); + "inode bitmap error for orphan %lu", ino); goto out; } @@ -672,7 +672,7 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) !(inode = iget(sb, ino)) || is_bad_inode(inode) || NEXT_ORPHAN(inode) > max_ino) { ext3_warning(sb, __FUNCTION__, - "bad orphan inode %lu! e2fsck was run?\n", ino); + "bad orphan inode %lu! e2fsck was run?", ino); printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n", bit, (unsigned long long)bitmap_bh->b_blocknr, ext3_test_bit(bit, bitmap_bh->b_data)); diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index b3c690a3b54a..af193a304ee5 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1476,7 +1476,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, if (levels && (dx_get_count(frames->entries) == dx_get_limit(frames->entries))) { ext3_warning(sb, __FUNCTION__, - "Directory index full!\n"); + "Directory index full!"); err = -ENOSPC; goto cleanup; } diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 6104ad310507..675aa24b0059 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -340,7 +340,7 @@ static int verify_reserved_gdb(struct super_block *sb, while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ ext3_warning(sb, __FUNCTION__, - "reserved GDT %ld missing grp %d (%ld)\n", + "reserved GDT %ld missing grp %d (%ld)", blk, grp, grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); return -EINVAL; @@ -393,7 +393,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, if (EXT3_SB(sb)->s_sbh->b_blocknr != le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { ext3_warning(sb, __FUNCTION__, - "won't resize using backup superblock at %llu\n", + "won't resize using backup superblock at %llu", (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); return -EPERM; } @@ -417,7 +417,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, data = (__u32 *)dind->b_data; if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { ext3_warning(sb, __FUNCTION__, - "new group %u GDT block %lu not reserved\n", + "new group %u GDT block %lu not reserved", input->group, gdblock); err = -EINVAL; goto exit_dind; @@ -540,7 +540,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, for (res = 0; res < reserved_gdb; res++, blk++) { if (le32_to_cpu(*data) != blk) { ext3_warning(sb, __FUNCTION__, - "reserved block %lu not at offset %ld\n", + "reserved block %lu not at offset %ld", blk, (long)(data - (__u32 *)dind->b_data)); err = -EINVAL; goto exit_bh; @@ -683,7 +683,7 @@ exit_err: if (err) { ext3_warning(sb, __FUNCTION__, "can't update backup for group %d (err %d), " - "forcing fsck on next reboot\n", group, err); + "forcing fsck on next reboot", group, err); sbi->s_mount_state &= ~EXT3_VALID_FS; sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS); mark_buffer_dirty(sbi->s_sbh); @@ -722,7 +722,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { ext3_warning(sb, __FUNCTION__, - "Can't resize non-sparse filesystem further\n"); + "Can't resize non-sparse filesystem further"); return -EPERM; } @@ -730,13 +730,13 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) if (!EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_RESIZE_INODE)){ ext3_warning(sb, __FUNCTION__, - "No reserved GDT blocks, can't resize\n"); + "No reserved GDT blocks, can't resize"); return -EPERM; } inode = iget(sb, EXT3_RESIZE_INO); if (!inode || is_bad_inode(inode)) { ext3_warning(sb, __FUNCTION__, - "Error opening resize inode\n"); + "Error opening resize inode"); iput(inode); return -ENOENT; } @@ -766,7 +766,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) lock_super(sb); if (input->group != EXT3_SB(sb)->s_groups_count) { ext3_warning(sb, __FUNCTION__, - "multiple resizers run on filesystem!\n"); + "multiple resizers run on filesystem!"); err = -EBUSY; goto exit_journal; } @@ -937,7 +937,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, if (last == 0) { ext3_warning(sb, __FUNCTION__, - "need to use ext2online to resize further\n"); + "need to use ext2online to resize further"); return -EPERM; } @@ -973,7 +973,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, lock_super(sb); if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { ext3_warning(sb, __FUNCTION__, - "multiple resizers run on filesystem!\n"); + "multiple resizers run on filesystem!"); err = -EBUSY; goto exit_put; } -- cgit v1.2.3 From 29ba17231222c42ca3df5424f43949e2a6fddec2 Mon Sep 17 00:00:00 2001 From: Glauber de Oliveira Costa Date: Sun, 8 Jan 2006 01:03:23 -0800 Subject: [PATCH] ext3: use sbi instead of EXT3_SB() in resize code. There are places in the resize code in which EXT3_SB() macro is used after an statement like sbi = EXT3_SB(sb) is done. Inside the same function, both sbi and EXT3_SB() are used to reference the super block Altough it is not wrong, keeping it coherent increases legibility, IMHO. Signed-off-by: Glauber de Oliveira Costa Cc: "Stephen C. Tweedie" Cc: Andreas Dilger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/resize.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 675aa24b0059..1041dab6de2f 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -31,7 +31,7 @@ static int verify_group_input(struct super_block *sb, unsigned start = le32_to_cpu(es->s_blocks_count); unsigned end = start + input->blocks_count; unsigned group = input->group; - unsigned itend = input->inode_table + EXT3_SB(sb)->s_itb_per_group; + unsigned itend = input->inode_table + sbi->s_itb_per_group; unsigned overhead = ext3_bg_has_super(sb, group) ? (1 + ext3_bg_num_gdb(sb, group) + le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; @@ -764,7 +764,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) } lock_super(sb); - if (input->group != EXT3_SB(sb)->s_groups_count) { + if (input->group != sbi->s_groups_count) { ext3_warning(sb, __FUNCTION__, "multiple resizers run on filesystem!"); err = -EBUSY; @@ -799,7 +799,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) * data. So we need to be careful to set all of the relevant * group descriptor data etc. *before* we enable the group. * - * The key field here is EXT3_SB(sb)->s_groups_count: as long as + * The key field here is sbi->s_groups_count: as long as * that retains its old value, nobody is going to access the new * group. * @@ -859,7 +859,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) smp_wmb(); /* Update the global fs size fields */ - EXT3_SB(sb)->s_groups_count++; + sbi->s_groups_count++; ext3_journal_dirty_metadata(handle, primary); @@ -874,7 +874,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) percpu_counter_mod(&sbi->s_freeinodes_counter, EXT3_INODES_PER_GROUP(sb)); - ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + ext3_journal_dirty_metadata(handle, sbi->s_sbh); sb->s_dirt = 1; exit_journal: -- cgit v1.2.3 From 08efd10edff199f0c992f04052e897a3f2048508 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Sun, 8 Jan 2006 01:03:26 -0800 Subject: [PATCH] MAINTAINERS: line duplication uniq -d MAINTAINERS Signed-off-by: Nicolas Kaiser Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7e780906d34c..76dc820bc889 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -927,7 +927,6 @@ S: Maintained FARSYNC SYNCHRONOUS DRIVER P: Kevin Curtis M: kevin.curtis@farsite.co.uk -M: kevin.curtis@farsite.co.uk W: http://www.farsite.co.uk/ S: Supported -- cgit v1.2.3 From 86174cdcb44c095ffd2e3ca69caa56244cf701d5 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:28 -0800 Subject: [PATCH] remove unneeded sig->curr_target recalculation This patch removes unneeded sig->curr_target recalculation under 'if (atomic_dec_and_test(&sig->count))' in __exit_signal(). When sig->count == 0 the signal can't be sent to this task and next_thread(tsk) == tsk anyway. Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/signal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 114cf9209bcd..08aa5b263f36 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -364,8 +364,6 @@ void __exit_signal(struct task_struct *tsk) posix_cpu_timers_exit(tsk); if (atomic_dec_and_test(&sig->count)) { posix_cpu_timers_exit_group(tsk); - if (tsk == sig->curr_target) - sig->curr_target = next_thread(tsk); tsk->signal = NULL; __exit_sighand(tsk); spin_unlock(&sighand->siglock); -- cgit v1.2.3 From 850d6fbe70c62a9792eac3e8ef34f2f09f209895 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:29 -0800 Subject: [PATCH] sigio: cleanup, don't take tasklist twice The only user of send_sigio_to_task() already holds tasklist_lock, so it is better not to send the signal via send_group_sig_info() (which takes tasklist recursively) but use group_send_sig_info(). The same change in send_sigurg()->send_sigurg_to_task(). Signed-off-by: Oleg Nesterov Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fcntl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/fcntl.c b/fs/fcntl.c index 863b46e0d78a..9903bde475f2 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -457,11 +457,11 @@ static void send_sigio_to_task(struct task_struct *p, else si.si_band = band_table[reason - POLL_IN]; si.si_fd = fd; - if (!send_group_sig_info(fown->signum, &si, p)) + if (!group_send_sig_info(fown->signum, &si, p)) break; /* fall-through: fall back on the old plain SIGIO signal */ case 0: - send_group_sig_info(SIGIO, SEND_SIG_PRIV, p); + group_send_sig_info(SIGIO, SEND_SIG_PRIV, p); } } @@ -495,7 +495,7 @@ static void send_sigurg_to_task(struct task_struct *p, struct fown_struct *fown) { if (sigio_perm(p, fown, SIGURG)) - send_group_sig_info(SIGURG, SEND_SIG_PRIV, p); + group_send_sig_info(SIGURG, SEND_SIG_PRIV, p); } int send_sigurg(struct fown_struct *fown) -- cgit v1.2.3 From 21b6bf143d05d77c350d9c6764ae090a877b66ea Mon Sep 17 00:00:00 2001 From: Jorn Dreyer Date: Sun, 8 Jan 2006 01:03:30 -0800 Subject: [PATCH] nfsroot: do not silently stop parsing on an unknown option It would be helpful if the kernel did not silently stop parsing nfs options, but instead warned about any he does not recognize. The attached patch adds one printk to do just that. It took me a couple of hours to find my configuration mistake. Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/nfs/nfsroot.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 985cc53b8dd5..e897e00c2c9d 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -275,7 +275,9 @@ static int __init root_nfs_parse(char *name, char *buf) case Opt_noacl: nfs_data.flags |= NFS_MOUNT_NOACL; break; - default : + default: + printk(KERN_WARNING "Root-NFS: unknown " + "option: %s\n", p); return 0; } } -- cgit v1.2.3 From 5160ee6fc891a9ca114be0e90fa6655647bb64b2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Jan 2006 01:03:32 -0800 Subject: [PATCH] shrink dentry struct Some long time ago, dentry struct was carefully tuned so that on 32 bits UP, sizeof(struct dentry) was exactly 128, ie a power of 2, and a multiple of memory cache lines. Then RCU was added and dentry struct enlarged by two pointers, with nice results for SMP, but not so good on UP, because breaking the above tuning (128 + 8 = 136 bytes) This patch reverts this unwanted side effect, by using an union (d_u), where d_rcu and d_child are placed so that these two fields can share their memory needs. At the time d_free() is called (and d_rcu is really used), d_child is known to be empty and not touched by the dentry freeing. Lockless lookups only access d_name, d_parent, d_lock, d_op, d_flags (so the previous content of d_child is not needed if said dentry was unhashed but still accessed by a CPU because of RCU constraints) As dentry cache easily contains millions of entries, a size reduction is worth the extra complexity of the ugly C union. Signed-off-by: Eric Dumazet Cc: Dipankar Sarma Cc: Maneesh Soni Cc: Miklos Szeredi Cc: "Paul E. McKenney" Cc: Ian Kent Cc: Paul Jackson Cc: Al Viro Cc: Christoph Hellwig Cc: Trond Myklebust Cc: Neil Brown Cc: James Morris Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/inode.c | 6 +++--- fs/autofs4/autofs_i.h | 2 +- fs/autofs4/expire.c | 12 ++++++------ fs/autofs4/inode.c | 4 ++-- fs/autofs4/root.c | 3 ++- fs/coda/cache.c | 2 +- fs/dcache.c | 34 +++++++++++++++++----------------- fs/libfs.c | 12 ++++++------ fs/ncpfs/dir.c | 2 +- fs/ncpfs/ncplib_kernel.h | 4 ++-- fs/smbfs/cache.c | 4 ++-- include/linux/dcache.h | 9 +++++++-- kernel/cpuset.c | 4 ++-- net/sunrpc/rpc_pipe.c | 2 +- security/selinux/selinuxfs.c | 2 +- 15 files changed, 54 insertions(+), 48 deletions(-) diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index c44bbedec817..4ddc453023a2 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -186,7 +186,7 @@ static void update_bus(struct dentry *bus) down(&bus->d_inode->i_sem); - list_for_each_entry(dev, &bus->d_subdirs, d_child) + list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) if (dev->d_inode) update_dev(dev); @@ -203,7 +203,7 @@ static void update_sb(struct super_block *sb) down(&root->d_inode->i_sem); - list_for_each_entry(bus, &root->d_subdirs, d_child) { + list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { if (bus->d_inode) { switch (S_IFMT & bus->d_inode->i_mode) { case S_IFDIR: @@ -319,7 +319,7 @@ static int usbfs_empty (struct dentry *dentry) spin_lock(&dcache_lock); list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_child); + struct dentry *de = list_entry(list, struct dentry, d_u.d_child); if (usbfs_positive(de)) { spin_unlock(&dcache_lock); return 0; diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index fca83e28edcf..385bed09b0d8 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -209,7 +209,7 @@ static inline int simple_empty_nolock(struct dentry *dentry) struct dentry *child; int ret = 0; - list_for_each_entry(child, &dentry->d_subdirs, d_child) + list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) if (simple_positive(child)) goto out; ret = 1; diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index feb6ac427d05..dc39589df165 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -105,7 +105,7 @@ repeat: next = this_parent->d_subdirs.next; resume: while (next != &this_parent->d_subdirs) { - struct dentry *dentry = list_entry(next, struct dentry, d_child); + struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if (!simple_positive(dentry)) { @@ -138,7 +138,7 @@ resume: } if (this_parent != top) { - next = this_parent->d_child.next; + next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; goto resume; } @@ -163,7 +163,7 @@ repeat: next = this_parent->d_subdirs.next; resume: while (next != &this_parent->d_subdirs) { - struct dentry *dentry = list_entry(next, struct dentry, d_child); + struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if (!simple_positive(dentry)) { @@ -199,7 +199,7 @@ cont: } if (this_parent != parent) { - next = this_parent->d_child.next; + next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; goto resume; } @@ -238,7 +238,7 @@ static struct dentry *autofs4_expire(struct super_block *sb, /* On exit from the loop expire is set to a dgot dentry * to expire or it's NULL */ while ( next != &root->d_subdirs ) { - struct dentry *dentry = list_entry(next, struct dentry, d_child); + struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - give up */ if ( !simple_positive(dentry) ) { @@ -302,7 +302,7 @@ next: expired, (int)expired->d_name.len, expired->d_name.name); spin_lock(&dcache_lock); list_del(&expired->d_parent->d_subdirs); - list_add(&expired->d_parent->d_subdirs, &expired->d_child); + list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child); spin_unlock(&dcache_lock); return expired; } diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 818b37be5153..2d3082854a29 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -91,7 +91,7 @@ repeat: next = this_parent->d_subdirs.next; resume: while (next != &this_parent->d_subdirs) { - struct dentry *dentry = list_entry(next, struct dentry, d_child); + struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); /* Negative dentry - don`t care */ if (!simple_positive(dentry)) { @@ -117,7 +117,7 @@ resume: if (this_parent != sbi->root) { struct dentry *dentry = this_parent; - next = this_parent->d_child.next; + next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; spin_unlock(&dcache_lock); DPRINTK("parent dentry %p %.*s", diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 2a771ec66956..2241405ffc41 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -143,7 +143,8 @@ static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t f } while(1) { - struct dentry *de = list_entry(list, struct dentry, d_child); + struct dentry *de = list_entry(list, + struct dentry, d_u.d_child); if (!d_unhashed(de) && de->d_inode) { spin_unlock(&dcache_lock); diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 80072fd9b7fa..c607d923350a 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -93,7 +93,7 @@ static void coda_flag_children(struct dentry *parent, int flag) spin_lock(&dcache_lock); list_for_each(child, &parent->d_subdirs) { - de = list_entry(child, struct dentry, d_child); + de = list_entry(child, struct dentry, d_u.d_child); /* don't know what to do with negative dentries */ if ( ! de->d_inode ) continue; diff --git a/fs/dcache.c b/fs/dcache.c index 17e439138681..1536f15c4d4c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -71,7 +71,7 @@ struct dentry_stat_t dentry_stat = { static void d_callback(struct rcu_head *head) { - struct dentry * dentry = container_of(head, struct dentry, d_rcu); + struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu); if (dname_external(dentry)) kfree(dentry->d_name.name); @@ -86,7 +86,7 @@ static void d_free(struct dentry *dentry) { if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - call_rcu(&dentry->d_rcu, d_callback); + call_rcu(&dentry->d_u.d_rcu, d_callback); } /* @@ -193,7 +193,7 @@ kill_it: { list_del(&dentry->d_lru); dentry_stat.nr_unused--; } - list_del(&dentry->d_child); + list_del(&dentry->d_u.d_child); dentry_stat.nr_dentry--; /* For d_free, below */ /*drops the locks, at that point nobody can reach this dentry */ dentry_iput(dentry); @@ -367,7 +367,7 @@ static inline void prune_one_dentry(struct dentry * dentry) struct dentry * parent; __d_drop(dentry); - list_del(&dentry->d_child); + list_del(&dentry->d_u.d_child); dentry_stat.nr_dentry--; /* For d_free, below */ dentry_iput(dentry); parent = dentry->d_parent; @@ -518,7 +518,7 @@ repeat: resume: while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); + struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; /* Have we found a mount point ? */ if (d_mountpoint(dentry)) @@ -532,7 +532,7 @@ resume: * All done at this level ... ascend and resume the search. */ if (this_parent != parent) { - next = this_parent->d_child.next; + next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; goto resume; } @@ -569,7 +569,7 @@ repeat: resume: while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); + struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; if (!list_empty(&dentry->d_lru)) { @@ -610,7 +610,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, found); * All done at this level ... ascend and resume the search. */ if (this_parent != parent) { - next = this_parent->d_child.next; + next = this_parent->d_u.d_child.next; this_parent = this_parent->d_parent; #ifdef DCACHE_DEBUG printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n", @@ -753,12 +753,12 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) dentry->d_parent = dget(parent); dentry->d_sb = parent->d_sb; } else { - INIT_LIST_HEAD(&dentry->d_child); + INIT_LIST_HEAD(&dentry->d_u.d_child); } spin_lock(&dcache_lock); if (parent) - list_add(&dentry->d_child, &parent->d_subdirs); + list_add(&dentry->d_u.d_child, &parent->d_subdirs); dentry_stat.nr_dentry++; spin_unlock(&dcache_lock); @@ -1310,8 +1310,8 @@ already_unhashed: /* Unhash the target: dput() will then get rid of it */ __d_drop(target); - list_del(&dentry->d_child); - list_del(&target->d_child); + list_del(&dentry->d_u.d_child); + list_del(&target->d_u.d_child); /* Switch the names.. */ switch_names(dentry, target); @@ -1322,15 +1322,15 @@ already_unhashed: if (IS_ROOT(dentry)) { dentry->d_parent = target->d_parent; target->d_parent = target; - INIT_LIST_HEAD(&target->d_child); + INIT_LIST_HEAD(&target->d_u.d_child); } else { do_switch(dentry->d_parent, target->d_parent); /* And add them back to the (new) parent lists */ - list_add(&target->d_child, &target->d_parent->d_subdirs); + list_add(&target->d_u.d_child, &target->d_parent->d_subdirs); } - list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); + list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); spin_unlock(&target->d_lock); spin_unlock(&dentry->d_lock); write_sequnlock(&rename_lock); @@ -1568,7 +1568,7 @@ repeat: resume: while (next != &this_parent->d_subdirs) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); + struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; if (d_unhashed(dentry)||!dentry->d_inode) continue; @@ -1579,7 +1579,7 @@ resume: atomic_dec(&dentry->d_count); } if (this_parent != root) { - next = this_parent->d_child.next; + next = this_parent->d_u.d_child.next; atomic_dec(&this_parent->d_count); this_parent = this_parent->d_parent; goto resume; diff --git a/fs/libfs.c b/fs/libfs.c index 58101dff2c66..9c50523382e7 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -93,16 +93,16 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) loff_t n = file->f_pos - 2; spin_lock(&dcache_lock); - list_del(&cursor->d_child); + list_del(&cursor->d_u.d_child); p = file->f_dentry->d_subdirs.next; while (n && p != &file->f_dentry->d_subdirs) { struct dentry *next; - next = list_entry(p, struct dentry, d_child); + next = list_entry(p, struct dentry, d_u.d_child); if (!d_unhashed(next) && next->d_inode) n--; p = p->next; } - list_add_tail(&cursor->d_child, p); + list_add_tail(&cursor->d_u.d_child, p); spin_unlock(&dcache_lock); } } @@ -126,7 +126,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_dentry; struct dentry *cursor = filp->private_data; - struct list_head *p, *q = &cursor->d_child; + struct list_head *p, *q = &cursor->d_u.d_child; ino_t ino; int i = filp->f_pos; @@ -153,7 +153,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) } for (p=q->next; p != &dentry->d_subdirs; p=p->next) { struct dentry *next; - next = list_entry(p, struct dentry, d_child); + next = list_entry(p, struct dentry, d_u.d_child); if (d_unhashed(next) || !next->d_inode) continue; @@ -261,7 +261,7 @@ int simple_empty(struct dentry *dentry) int ret = 0; spin_lock(&dcache_lock); - list_for_each_entry(child, &dentry->d_subdirs, d_child) + list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) if (simple_positive(child)) goto out; ret = 1; diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index a9f7a8ab1d59..cfd76f431dc0 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -365,7 +365,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) spin_lock(&dcache_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dent = list_entry(next, struct dentry, d_child); + dent = list_entry(next, struct dentry, d_u.d_child); if ((unsigned long)dent->d_fsdata == fpos) { if (dent->d_inode) dget_locked(dent); diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 9e4dc30c2435..799e5c2bec55 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -196,7 +196,7 @@ ncp_renew_dentries(struct dentry *parent) spin_lock(&dcache_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dentry = list_entry(next, struct dentry, d_child); + dentry = list_entry(next, struct dentry, d_u.d_child); if (dentry->d_fsdata == NULL) ncp_age_dentry(server, dentry); @@ -218,7 +218,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) spin_lock(&dcache_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dentry = list_entry(next, struct dentry, d_child); + dentry = list_entry(next, struct dentry, d_u.d_child); dentry->d_fsdata = NULL; ncp_age_dentry(server, dentry); next = next->next; diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c index f3e6b81288ab..74b86d9725a6 100644 --- a/fs/smbfs/cache.c +++ b/fs/smbfs/cache.c @@ -66,7 +66,7 @@ smb_invalidate_dircache_entries(struct dentry *parent) spin_lock(&dcache_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dentry = list_entry(next, struct dentry, d_child); + dentry = list_entry(next, struct dentry, d_u.d_child); dentry->d_fsdata = NULL; smb_age_dentry(server, dentry); next = next->next; @@ -100,7 +100,7 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) spin_lock(&dcache_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { - dent = list_entry(next, struct dentry, d_child); + dent = list_entry(next, struct dentry, d_u.d_child); if ((unsigned long)dent->d_fsdata == fpos) { if (dent->d_inode) dget_locked(dent); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 46a2ba617595..a3ed5e059d47 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -95,14 +95,19 @@ struct dentry { struct qstr d_name; struct list_head d_lru; /* LRU list */ - struct list_head d_child; /* child of parent list */ + /* + * d_child and d_rcu can share memory + */ + union { + struct list_head d_child; /* child of parent list */ + struct rcu_head d_rcu; + } d_u; struct list_head d_subdirs; /* our children */ struct list_head d_alias; /* inode alias list */ unsigned long d_time; /* used by d_revalidate */ struct dentry_operations *d_op; struct super_block *d_sb; /* The root of the dentry tree */ void *d_fsdata; /* fs-specific data */ - struct rcu_head d_rcu; struct dcookie_struct *d_cookie; /* cookie, if any */ int d_mounted; unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index e04c2da9dadb..eab64e23bcae 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -331,7 +331,7 @@ static void cpuset_d_remove_dir(struct dentry *dentry) spin_lock(&dcache_lock); node = dentry->d_subdirs.next; while (node != &dentry->d_subdirs) { - struct dentry *d = list_entry(node, struct dentry, d_child); + struct dentry *d = list_entry(node, struct dentry, d_u.d_child); list_del_init(node); if (d->d_inode) { d = dget_locked(d); @@ -343,7 +343,7 @@ static void cpuset_d_remove_dir(struct dentry *dentry) } node = dentry->d_subdirs.next; } - list_del_init(&dentry->d_child); + list_del_init(&dentry->d_u.d_child); spin_unlock(&dcache_lock); remove_dir(dentry); } diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 24cc23af9b95..e14c1cae7460 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -495,7 +495,7 @@ rpc_depopulate(struct dentry *parent) repeat: spin_lock(&dcache_lock); list_for_each_safe(pos, next, &parent->d_subdirs) { - dentry = list_entry(pos, struct dentry, d_child); + dentry = list_entry(pos, struct dentry, d_u.d_child); spin_lock(&dentry->d_lock); if (!d_unhashed(dentry)) { dget_locked(dentry); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index e59da6398d44..b5fa02d17b1e 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -889,7 +889,7 @@ static void sel_remove_bools(struct dentry *de) spin_lock(&dcache_lock); node = de->d_subdirs.next; while (node != &de->d_subdirs) { - struct dentry *d = list_entry(node, struct dentry, d_child); + struct dentry *d = list_entry(node, struct dentry, d_u.d_child); list_del_init(node); if (d->d_inode) { -- cgit v1.2.3 From cc398c2eae35b13d77b77337136325edc6ca94ca Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 Jan 2006 01:03:34 -0800 Subject: [PATCH] drivers/connector/cn_proc.c typos The parameter to put_cpu_var() is unreferenced by the implementation, and the compiler doesn't try to comprehend comments, so this wouldn't cause any problem, but if bugged me enough to post a fix :-) Signed-off-by: David S. Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/connector/cn_proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 969d2b4aaec0..385e52930c02 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -34,14 +34,14 @@ static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; -/* proc_counts is used as the sequence number of the netlink message */ +/* proc_event_counts is used as the sequence number of the netlink message */ static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 }; static inline void get_seq(__u32 *ts, int *cpu) { *ts = get_cpu_var(proc_event_counts)++; *cpu = smp_processor_id(); - put_cpu_var(proc_counts); + put_cpu_var(proc_event_counts); } void proc_fork_connector(struct task_struct *task) -- cgit v1.2.3 From dda6ebde96044e9b5f1b14588659b39b4e6c08e7 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 8 Jan 2006 01:03:35 -0800 Subject: [PATCH] Fix handling of ELF segments with zero filesize mmap() returns -EINVAL if given a zero length, and thus elf_map() in binfmt_elf.c does likewise if it attempts to map a (page-aligned) ELF segment with zero filesize. Such a situation never arises with the default linker scripts, but there's nothing inherently wrong with zero-filesize (but non-zero memsize) ELF segments. Custom linker scripts can generate them, and the kernel should be able to map them; this patch makes it so. Signed-off-by: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index f36f2210204f..288386b1deff 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -288,11 +288,17 @@ static unsigned long elf_map(struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) { unsigned long map_addr; + unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr); down_write(¤t->mm->mmap_sem); - map_addr = do_mmap(filep, ELF_PAGESTART(addr), - eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, - eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); + /* mmap() will return -EINVAL if given a zero size, but a + * segment with zero filesize is perfectly valid */ + if (eppnt->p_filesz + pageoffset) + map_addr = do_mmap(filep, ELF_PAGESTART(addr), + eppnt->p_filesz + pageoffset, prot, type, + eppnt->p_offset - pageoffset); + else + map_addr = ELF_PAGESTART(addr); up_write(¤t->mm->mmap_sem); return(map_addr); } -- cgit v1.2.3 From 44fce35f29a7f2d976d9160bfbc55635b459a6a0 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Sun, 8 Jan 2006 01:03:37 -0800 Subject: [PATCH] drivers/mfd: header included twice linux/delay.h included twice Signed-off-by: Nicolas Kaiser Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mfd/ucb1x00-ts.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 551061c2eadf..79fd062ccb34 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 90f2447d08a5fbddc8b58f8a6425b0513807f919 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 8 Jan 2006 01:03:38 -0800 Subject: [PATCH] Documentation: Small applying-patches.txt update Minor update to Documentation/applying-patches.txt Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/applying-patches.txt | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Documentation/applying-patches.txt b/Documentation/applying-patches.txt index 681e426e2482..05a08c2c1889 100644 --- a/Documentation/applying-patches.txt +++ b/Documentation/applying-patches.txt @@ -2,7 +2,8 @@ Applying Patches To The Linux Kernel ------------------------------------ - (Written by Jesper Juhl, August 2005) + Original by: Jesper Juhl, August 2005 + Last update: 2005-12-02 @@ -118,7 +119,7 @@ wrong. When patch encounters a change that it can't fix up with fuzz it rejects it outright and leaves a file with a .rej extension (a reject file). You can -read this file to see exactely what change couldn't be applied, so you can +read this file to see exactly what change couldn't be applied, so you can go fix it up by hand if you wish. If you don't have any third party patches applied to your kernel source, but @@ -127,7 +128,7 @@ and have made no modifications yourself to the source files, then you should never see a fuzz or reject message from patch. If you do see such messages anyway, then there's a high risk that either your local source tree or the patch file is corrupted in some way. In that case you should probably try -redownloading the patch and if things are still not OK then you'd be advised +re-downloading the patch and if things are still not OK then you'd be advised to start with a fresh tree downloaded in full from kernel.org. Let's look a bit more at some of the messages patch can produce. @@ -180,9 +181,11 @@ wish to apply. Are there any alternatives to `patch'? --- - Yes there are alternatives. You can use the `interdiff' program -(http://cyberelk.net/tim/patchutils/) to generate a patch representing the -differences between two patches and then apply the result. + Yes there are alternatives. + + You can use the `interdiff' program (http://cyberelk.net/tim/patchutils/) to +generate a patch representing the differences between two patches and then +apply the result. This will let you move from something like 2.6.12.2 to 2.6.12.3 in a single step. The -z flag to interdiff will even let you feed it patches in gzip or bzip2 compressed form directly without the use of zcat or bzcat or manual @@ -197,7 +200,7 @@ do the additional steps since interdiff can get things wrong in some cases. Another alternative is `ketchup', which is a python script for automatic downloading and applying of patches (http://www.selenic.com/ketchup/). -Other nice tools are diffstat which shows a summary of changes made by a + Other nice tools are diffstat which shows a summary of changes made by a patch, lsdiff which displays a short listing of affected files in a patch file, along with (optionally) the line numbers of the start of each patch and grepdiff which displays a list of the files modified by a patch where @@ -258,7 +261,7 @@ $ patch -p1 -R < ../patch-2.6.11.1 # revert the 2.6.11.1 patch # source dir is now 2.6.11 $ patch -p1 < ../patch-2.6.12 # apply new 2.6.12 patch $ cd .. -$ mv linux-2.6.11.1 inux-2.6.12 # rename source dir +$ mv linux-2.6.11.1 linux-2.6.12 # rename source dir The 2.6.x.y kernels @@ -433,7 +436,11 @@ $ cd .. $ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3 # rename the source dir -This concludes this list of explanations of the various kernel trees and I -hope you are now crystal clear on how to apply the various patches and help -testing the kernel. +This concludes this list of explanations of the various kernel trees. +I hope you are now clear on how to apply the various patches and help testing +the kernel. + +Thank you's to Randy Dunlap, Rolf Eike Beer, Linus Torvalds, Bodo Eggert, +Johannes Stezenbach, Grant Coady, Pavel Machek and others that I may have +forgotten for their reviews and contributions to this document. -- cgit v1.2.3 From e78c9a004aadebe22306c81d1a7f1d1278dc37f9 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 8 Jan 2006 01:03:39 -0800 Subject: [PATCH] fs: remove s_old_blocksize from struct super_block This patch inlines the single user of struct super_block field s_old_blocksize and removes the field. Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/super.c | 3 +-- include/linux/fs.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/super.c b/fs/super.c index 5a347a4f673a..0a30e51692cf 100644 --- a/fs/super.c +++ b/fs/super.c @@ -700,8 +700,7 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, s->s_flags = flags; strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); - s->s_old_blocksize = block_size(bdev); - sb_set_blocksize(s, s->s_old_blocksize); + sb_set_blocksize(s, block_size(bdev)); error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0); if (error) { up_write(&s->s_umount); diff --git a/include/linux/fs.h b/include/linux/fs.h index a1e28f0895c0..4c82219b0fae 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -808,7 +808,6 @@ struct super_block { struct list_head s_list; /* Keep this first */ dev_t s_dev; /* search index; _not_ kdev_t */ unsigned long s_blocksize; - unsigned long s_old_blocksize; unsigned char s_blocksize_bits; unsigned char s_dirt; unsigned long long s_maxbytes; /* Max file size */ -- cgit v1.2.3 From f867bac65419a98c9682f4409e087582d29ec5f6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Jan 2006 01:03:40 -0800 Subject: [PATCH] remove unused blkp field in percpu_data I found that blkp field was not used in kernel tree. As most of the times NR_CPUS is a power of two and kmalloc() memory blocks too, this extra field basically doubles the memory space allocated in __alloc_percpu() to store the 'struct percpu_data' (for example, if NR_CPUS=8 on i386, kmalloc(4*8+4) returns a 64 bytes block instead of a 32 bytes block after this patch) Signed-off-by: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/percpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 20317d88deba..cb9039a21f2a 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -19,7 +19,6 @@ struct percpu_data { void *ptrs[NR_CPUS]; - void *blkp; }; /* -- cgit v1.2.3 From 9841d61d75da5e46ed7a978bed4f50c78b1d87fd Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 8 Jan 2006 01:03:41 -0800 Subject: [PATCH] Add tainting for proprietary helper modules Kernels that have had Windows drivers loaded into them are undebuggable. I've wasted a number of hours chasing bugs filed in Fedora bugzilla only to find out much later that the user had used such 'helpers', and their problems were unreproducable without them loaded. Acked-by: Arjan van de Ven Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/module.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/module.c b/kernel/module.c index 4b06bbad49c2..5d9078d6f0fa 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1715,6 +1715,11 @@ static struct module *load_module(void __user *umod, /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); + if (strcmp(mod->name, "ndiswrapper") == 0) + add_taint(TAINT_PROPRIETARY_MODULE); + if (strcmp(mod->name, "driverloader") == 0) + add_taint(TAINT_PROPRIETARY_MODULE); + #ifdef CONFIG_MODULE_UNLOAD /* Set up MODINFO_ATTR fields */ setup_modinfo(mod, sechdrs, infoindex); -- cgit v1.2.3 From d84f520348d77e61f936227a048403dbc349fff1 Mon Sep 17 00:00:00 2001 From: Srivatsa Vaddagiri Date: Sun, 8 Jan 2006 01:03:42 -0800 Subject: [PATCH] Extend RCU torture module to test tickless idle CPU This patch forces RCU torture threads off various CPUs in the system allowing them to become idle and go tickless. Meant to test support for such tickless idle CPU in RCU. Signed-off-by: Srivatsa Vaddagiri Cc: Dipankar Sarma Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/rcutorture.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 75174c81529a..773219907dd8 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -48,9 +48,11 @@ MODULE_LICENSE("GPL"); static int nreaders = -1; /* # reader threads, defaults to 4*ncpus */ -static int stat_interval = 0; /* Interval between stats, in seconds. */ +static int stat_interval; /* Interval between stats, in seconds. */ /* Defaults to "only at end of test". */ -static int verbose = 0; /* Print more debug info. */ +static int verbose; /* Print more debug info. */ +static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ +static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ MODULE_PARM(nreaders, "i"); MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); @@ -58,6 +60,10 @@ MODULE_PARM(stat_interval, "i"); MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s"); MODULE_PARM(verbose, "i"); MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s"); +MODULE_PARM(test_no_idle_hz, "i"); +MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); +MODULE_PARM(shuffle_interval, "i"); +MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); #define TORTURE_FLAG "rcutorture: " #define PRINTK_STRING(s) \ do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0) @@ -72,6 +78,7 @@ static int nrealreaders; static struct task_struct *writer_task; static struct task_struct **reader_tasks; static struct task_struct *stats_task; +static struct task_struct *shuffler_task; #define RCU_TORTURE_PIPE_LEN 10 @@ -375,12 +382,77 @@ rcu_torture_stats(void *arg) return 0; } +static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ + +/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case + * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs. + */ +void rcu_torture_shuffle_tasks(void) +{ + cpumask_t tmp_mask = CPU_MASK_ALL; + int i; + + lock_cpu_hotplug(); + + /* No point in shuffling if there is only one online CPU (ex: UP) */ + if (num_online_cpus() == 1) { + unlock_cpu_hotplug(); + return; + } + + if (rcu_idle_cpu != -1) + cpu_clear(rcu_idle_cpu, tmp_mask); + + set_cpus_allowed(current, tmp_mask); + + if (reader_tasks != NULL) { + for (i = 0; i < nrealreaders; i++) + if (reader_tasks[i]) + set_cpus_allowed(reader_tasks[i], tmp_mask); + } + + if (writer_task) + set_cpus_allowed(writer_task, tmp_mask); + + if (stats_task) + set_cpus_allowed(stats_task, tmp_mask); + + if (rcu_idle_cpu == -1) + rcu_idle_cpu = num_online_cpus() - 1; + else + rcu_idle_cpu--; + + unlock_cpu_hotplug(); +} + +/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the + * system to become idle at a time and cut off its timer ticks. This is meant + * to test the support for such tickless idle CPU in RCU. + */ +static int +rcu_torture_shuffle(void *arg) +{ + VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started"); + do { + schedule_timeout_interruptible(shuffle_interval * HZ); + rcu_torture_shuffle_tasks(); + } while (!kthread_should_stop()); + VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); + return 0; +} + static void rcu_torture_cleanup(void) { int i; fullstop = 1; + if (shuffler_task != NULL) { + VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task"); + kthread_stop(shuffler_task); + } + shuffler_task = NULL; + if (writer_task != NULL) { VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task"); kthread_stop(writer_task); @@ -429,9 +501,11 @@ rcu_torture_init(void) nrealreaders = nreaders; else nrealreaders = 2 * num_online_cpus(); - printk(KERN_ALERT TORTURE_FLAG - "--- Start of test: nreaders=%d stat_interval=%d verbose=%d\n", - nrealreaders, stat_interval, verbose); + printk(KERN_ALERT TORTURE_FLAG "--- Start of test: nreaders=%d " + "stat_interval=%d verbose=%d test_no_idle_hz=%d " + "shuffle_interval = %d\n", + nrealreaders, stat_interval, verbose, test_no_idle_hz, + shuffle_interval); fullstop = 0; /* Set up the freelist. */ @@ -501,6 +575,18 @@ rcu_torture_init(void) goto unwind; } } + if (test_no_idle_hz) { + rcu_idle_cpu = num_online_cpus() - 1; + /* Create the shuffler thread */ + shuffler_task = kthread_run(rcu_torture_shuffle, NULL, + "rcu_torture_shuffle"); + if (IS_ERR(shuffler_task)) { + firsterr = PTR_ERR(shuffler_task); + VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler"); + shuffler_task = NULL; + goto unwind; + } + } return 0; unwind: -- cgit v1.2.3 From 99aef427e206f4ae7dcf0b18f66416145fea5d20 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 8 Jan 2006 01:03:43 -0800 Subject: [PATCH] update to the initramfs docs Based on questions people have asked me. Repeatedly. Signed-off-by: Rob Landley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../filesystems/ramfs-rootfs-initramfs.txt | 72 +++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt index b3404a032596..60ab61e54e8a 100644 --- a/Documentation/filesystems/ramfs-rootfs-initramfs.txt +++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt @@ -143,12 +143,26 @@ as the following example: dir /mnt 755 0 0 file /init initramfs/init.sh 755 0 0 +Run "usr/gen_init_cpio" (after the kernel build) to get a usage message +documenting the above file format. + One advantage of the text file is that root access is not required to set permissions or create device nodes in the new archive. (Note that those two example "file" entries expect to find files named "init.sh" and "busybox" in a directory called "initramfs", under the linux-2.6.* directory. See Documentation/early-userspace/README for more details.) +The kernel does not depend on external cpio tools, gen_init_cpio is created +from usr/gen_init_cpio.c which is entirely self-contained, and the kernel's +boot-time extractor is also (obviously) self-contained. However, if you _do_ +happen to have cpio installed, the following command line can extract the +generated cpio image back into its component files: + + cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames + +Contents of initramfs: +---------------------- + If you don't already understand what shared libraries, devices, and paths you need to get a minimal root filesystem up and running, here are some references: @@ -161,13 +175,69 @@ designed to be a tiny C library to statically link early userspace code against, along with some related utilities. It is BSD licensed. I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net) -myself. These are LGPL and GPL, respectively. +myself. These are LGPL and GPL, respectively. (A self-contained initramfs +package is planned for the busybox 1.2 release.) In theory you could use glibc, but that's not well suited for small embedded uses like this. (A "hello world" program statically linked against glibc is over 400k. With uClibc it's 7k. Also note that glibc dlopens libnss to do name lookups, even when otherwise statically linked.) +Why cpio rather than tar? +------------------------- + +This decision was made back in December, 2001. The discussion started here: + + http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1538.html + +And spawned a second thread (specifically on tar vs cpio), starting here: + + http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1587.html + +The quick and dirty summary version (which is no substitute for reading +the above threads) is: + +1) cpio is a standard. It's decades old (from the AT&T days), and already + widely used on Linux (inside RPM, Red Hat's device driver disks). Here's + a Linux Journal article about it from 1996: + + http://www.linuxjournal.com/article/1213 + + It's not as popular as tar because the traditional cpio command line tools + require _truly_hideous_ command line arguments. But that says nothing + either way about the archive format, and there are alternative tools, + such as: + + http://freshmeat.net/projects/afio/ + +2) The cpio archive format chosen by the kernel is simpler and cleaner (and + thus easier to create and parse) than any of the (literally dozens of) + various tar archive formats. The complete initramfs archive format is + explained in buffer-format.txt, created in usr/gen_init_cpio.c, and + extracted in init/initramfs.c. All three together come to less than 26k + total of human-readable text. + +3) The GNU project standardizing on tar is approximately as relevant as + Windows standardizing on zip. Linux is not part of either, and is free + to make its own technical decisions. + +4) Since this is a kernel internal format, it could easily have been + something brand new. The kernel provides its own tools to create and + extract this format anyway. Using an existing standard was preferable, + but not essential. + +5) Al Viro made the decision (quote: "tar is ugly as hell and not going to be + supported on the kernel side"): + + http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1540.html + + explained his reasoning: + + http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1550.html + http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1638.html + + and, most importantly, designed and implemented the initramfs code. + Future directions: ------------------ -- cgit v1.2.3 From 87ba81dba431232548ce29d5d224115d0c2355ac Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Sun, 8 Jan 2006 01:03:44 -0800 Subject: [PATCH] fadvise: return ESPIPE on FIFO/pipe The patch makes posix_fadvise return ESPIPE on FIFO/pipe in order to be fully POSIX-compliant. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/fadvise.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mm/fadvise.c b/mm/fadvise.c index 5f19e87bc5af..d257c89e7704 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -37,6 +37,11 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) if (!file) return -EBADF; + if (S_ISFIFO(file->f_dentry->d_inode->i_mode)) { + ret = -ESPIPE; + goto out; + } + mapping = file->f_mapping; if (!mapping || len < 0) { ret = -EINVAL; -- cgit v1.2.3 From 5e38291d80086f6972f471c7caffa03184de0bf0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 8 Jan 2006 01:03:46 -0800 Subject: [PATCH] Don't attempt to power off if power off is not implemented The problem. It is expected that /sbin/halt -p works exactly like /sbin/halt, when the kernel does not implement power off functionality. The kernel can do a lot of work in the reboot notifiers and in device_shutdown before we even get to machine_power_off. Some of that shutdown is not safe if you are leaving the power on, and it definitely gets in the way of using sysrq or pressing ctrl-alt-del. Since the shutdown happens in generic code there is no way to fix this in architecture specific code :( Some machines are kernel oopsing today because of this. The simple solution is to turn LINUX_REBOOT_CMD_POWER_OFF into LINUX_REBOOT_CMD_HALT if power_off functionality is not implemented. This has the unfortunate side effect of disabling the power off functionality on architectures that leave pm_power_off to null and still implement something in machine_power_off. And it will break the build on some architectures that don't have a pm_power_off variable at all. On both counts I say tough. For architectures like alpha that don't implement the pm_power_off variable pm_power_off is declared in linux/pm.h and it is a generic part of our power management code, and all architectures should implement it. For architectures like parisc that have a default power off method in machine_power_off if pm_power_off is not implemented or fails. It is easy enough to set the pm_power_off variable. And nothing bad happens there, the machines just stop powering off. The current semantics are impossible without a flag at the top level so we can avoid the problem code if a power off is not implemented. pm_power_off is as good a flag as any with the bonus that it works without modification on at least x86, x86_64, powerpc, and ppc today. Andrew can you pick this up and put this in the mm tree. Kernels that don't compile or don't power off seem saner than kernels that oops or panic. Until we get the arch specific patches for the problem architectures this probably isn't smart to push into the stable kernel. Unfortunately I don't have the time at the moment to walk through every architecture and make them work. And even if I did I couldn't test it :( From: Hirokazu Takata Add pm_power_off() for build fix of arch/m32r/kernel/process.c. From: Miklos Szeredi UML build fix Signed-off-by: Eric W. Biederman Signed-off-by: Hayato Fujiwara Signed-off-by: Hirokazu Takata Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/process.c | 5 +++++ arch/m32r/kernel/process.c | 4 ++++ arch/um/kernel/reboot.c | 2 ++ kernel/sys.c | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index a8682612abc0..abb739b88ed1 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -43,6 +43,11 @@ #include "proto.h" #include "pci_impl.h" +/* + * Power off function, if any + */ +void (*pm_power_off)(void) = machine_power_off; + void cpu_idle(void) { diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index cc4b571e5db7..3bf55d92933f 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -50,6 +50,10 @@ unsigned long thread_saved_pc(struct task_struct *tsk) * Powermanagement idle function, if any.. */ void (*pm_idle)(void) = NULL; +EXPORT_SYMBOL(pm_idle); + +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); void disable_hlt(void) { diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index a637e885c583..6f1a3a288117 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -12,6 +12,8 @@ #include "mode.h" #include "choose-mode.h" +void (*pm_power_off)(void); + #ifdef CONFIG_SMP static void kill_idlers(int me) { diff --git a/kernel/sys.c b/kernel/sys.c index eecf84526afe..d8e49e659027 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -489,6 +489,12 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user magic2 != LINUX_REBOOT_MAGIC2C)) return -EINVAL; + /* Instead of trying to make the power_off code look like + * halt when pm_power_off is not set do it the easy way. + */ + if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) + cmd = LINUX_REBOOT_CMD_HALT; + lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: -- cgit v1.2.3 From d09cf7d77f62f6fb2f6d63fe5980583805f2d559 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Sun, 8 Jan 2006 01:03:48 -0800 Subject: [PATCH] tpmdd: remove global event log Remove global event log in the tpm bios event measurement log code that would have caused problems when the code was run concurrently. A log is now allocated and attached to the seq file upon open and destroyed appropriately. Signed-off-by: Kylene Jo Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm_bios.c | 92 ++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 5e1f4dfefa17..aedf7a8e6da7 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -29,6 +29,11 @@ #define MAX_TEXT_EVENT 1000 /* Max event string length */ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ +struct tpm_bios_log { + void *bios_event_log; + void *bios_event_log_end; +}; + struct acpi_tcpa { struct acpi_table_header hdr; u16 reserved; @@ -117,39 +122,34 @@ static const char* tcpa_pc_event_id_strings[] = { "S-CRTM POST Contents", }; -/* (Binary) bios measurement buffer */ -static void *tcg_eventlog; -static void *tcg_eventlog_addr_limit; /* MAX */ - /* returns pointer to start of pos. entry of tcg log */ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) { loff_t i; - void *addr = tcg_eventlog; + struct tpm_bios_log *log = m->private; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; struct tcpa_event *event; /* read over *pos measurements */ for (i = 0; i < *pos; i++) { event = addr; - if ((addr + sizeof(struct tcpa_event)) < - tcg_eventlog_addr_limit) { + if ((addr + sizeof(struct tcpa_event)) < limit) { if (event->event_type == 0 && event->event_size == 0) return NULL; - addr += - sizeof(struct tcpa_event) + event->event_size; + addr += sizeof(struct tcpa_event) + event->event_size; } } /* now check if current entry is valid */ - if ((addr + sizeof(struct tcpa_event)) >= tcg_eventlog_addr_limit) + if ((addr + sizeof(struct tcpa_event)) >= limit) return NULL; event = addr; if ((event->event_type == 0 && event->event_size == 0) || - ((addr + sizeof(struct tcpa_event) + event->event_size) >= - tcg_eventlog_addr_limit)) + ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit)) return NULL; return addr; @@ -159,11 +159,13 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v, loff_t *pos) { struct tcpa_event *event = v; + struct tpm_bios_log *log = m->private; + void *limit = log->bios_event_log_end; v += sizeof(struct tcpa_event) + event->event_size; /* now check if current entry is valid */ - if ((v + sizeof(struct tcpa_event)) >= tcg_eventlog_addr_limit) + if ((v + sizeof(struct tcpa_event)) >= limit) return NULL; event = v; @@ -172,8 +174,7 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v, return NULL; if ((event->event_type == 0 && event->event_size == 0) || - ((v + sizeof(struct tcpa_event) + event->event_size) >= - tcg_eventlog_addr_limit)) + ((v + sizeof(struct tcpa_event) + event->event_size) >= limit)) return NULL; (*pos)++; @@ -312,10 +313,14 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) static int tpm_bios_measurements_release(struct inode *inode, struct file *file) { - if (tcg_eventlog) { - kfree(tcg_eventlog); - tcg_eventlog = NULL; + struct seq_file *seq = file->private_data; + struct tpm_bios_log *log = seq->private; + + if (log) { + kfree(log->bios_event_log); + kfree(log); } + return seq_release(inode, file); } @@ -367,13 +372,13 @@ static struct seq_operations tpm_binary_b_measurments_seqops = { }; /* read binary bios log */ -static int read_log(void) +static int read_log(struct tpm_bios_log *log) { struct acpi_tcpa *buff; acpi_status status; void *virt; - if (tcg_eventlog != NULL) { + if (log->bios_event_log != NULL) { printk(KERN_ERR "%s: ERROR - Eventlog already initialized\n", __func__); @@ -393,25 +398,24 @@ static int read_log(void) } if (buff->log_max_len == 0) { - printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", - __func__); + printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); return -EIO; } /* malloc EventLog space */ - tcg_eventlog = kmalloc(buff->log_max_len, GFP_KERNEL); - if (!tcg_eventlog) { + log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL); + if (!log->bios_event_log) { printk ("%s: ERROR - Not enough Memory for BIOS measurements\n", __func__); return -ENOMEM; } - tcg_eventlog_addr_limit = tcg_eventlog + buff->log_max_len; + log->bios_event_log_end = log->bios_event_log + buff->log_max_len; acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, &virt); - memcpy(tcg_eventlog, virt, buff->log_max_len); + memcpy(log->bios_event_log, virt, buff->log_max_len); acpi_os_unmap_memory(virt, buff->log_max_len); return 0; @@ -421,12 +425,26 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode, struct file *file) { int err; + struct tpm_bios_log *log; + struct seq_file *seq; - if ((err = read_log())) + log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); + if (!log) + return -ENOMEM; + + if ((err = read_log(log))) return err; /* now register seq file */ - return seq_open(file, &tpm_ascii_b_measurments_seqops); + err = seq_open(file, &tpm_ascii_b_measurments_seqops); + if (!err) { + seq = file->private_data; + seq->private = log; + } else { + kfree(log->bios_event_log); + kfree(log); + } + return err; } struct file_operations tpm_ascii_bios_measurements_ops = { @@ -440,12 +458,26 @@ static int tpm_binary_bios_measurements_open(struct inode *inode, struct file *file) { int err; + struct tpm_bios_log *log; + struct seq_file *seq; - if ((err = read_log())) + log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); + if (!log) + return -ENOMEM; + + if ((err = read_log(log))) return err; /* now register seq file */ - return seq_open(file, &tpm_binary_b_measurments_seqops); + err = seq_open(file, &tpm_binary_b_measurments_seqops); + if (!err) { + seq = file->private_data; + seq->private = log; + } else { + kfree(log->bios_event_log); + kfree(log); + } + return err; } struct file_operations tpm_binary_bios_measurements_ops = { -- cgit v1.2.3 From fb86a35b9ded8a7e53a432cbf28df603cdd4849c Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Sun, 8 Jan 2006 01:03:50 -0800 Subject: [PATCH] cciss: adds MSI and MSI-X support This creates a new function, cciss_interrupt_mode called from cciss_pci_init. This function determines what type of interrupt vector to use, i.e., MSI, MSI-X, or IO-APIC. One noticeable difference is changing the interrupt field of the controller struct to an array of 4 unsigned ints. The Smart Array HW is capable of generating 4 distinct interrupts depending on the transport method in use during operation. These are: #define DOORBELL_INT 0 Used to notify the contoller of configuration updates. We only use this feature when in polling mode. #define PERF_MODE_INT 0 Used when the controller is in Performant Mode. #define SIMPLE_MODE_INT 2 Used when the controller is in Simple Mode (current Linux implementation). #define MEMQ_INT_MODE 3 Not used. When using IO-APIC interrupts these 4 lines are OR'ed together so when any one fires an interrupt an is generated. In MSI or MSI-X mode this hardware OR'ing is ignored. We must register for our interrupt depending on what mode the controller is running. For Linux we use SIMPLE_MODE_INT exclusively at this time. Please consider this for inclusion. Signed-off-by: Mike Miller Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 87 ++++++++++++++++++++++++++++++++++++++++------ drivers/block/cciss.h | 8 ++++- drivers/block/cciss_scsi.c | 2 +- 3 files changed, 84 insertions(+), 13 deletions(-) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index bdb9c2717d40..46e8356a962a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1,6 +1,6 @@ /* * Disk Array driver for HP SA 5xxx and 6xxx Controllers - * Copyright 2000, 2005 Hewlett-Packard Development Company, L.P. + * Copyright 2000, 2006 Hewlett-Packard Development Company, L.P. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,12 +47,12 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 2.6.8)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8) +#define DRIVER_NAME "HP CISS Driver (v 2.6.10)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,10) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.10"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" " SA6i P600 P800 P400 P400i E200 E200i"); MODULE_LICENSE("GPL"); @@ -167,7 +167,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv); static void cciss_getgeometry(int cntl_num); - +static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32); static void start_io( ctlr_info_t *h); static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, @@ -284,7 +284,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, h->product_name, (unsigned long)h->board_id, h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], - (unsigned int)h->intr, + (unsigned int)h->intr[SIMPLE_MODE_INT], h->num_luns, h->Qdepth, h->commands_outstanding, h->maxQsinceinit, h->max_outstanding, h->maxSG); @@ -2662,6 +2662,60 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, return -1; } +/* If MSI/MSI-X is supported by the kernel we will try to enable it on + * controllers that are capable. If not, we use IO-APIC mode. + */ + +static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id) +{ +#ifdef CONFIG_PCI_MSI + int err; + struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1}, + {0,2}, {0,3}}; + + /* Some boards advertise MSI but don't really support it */ + if ((board_id == 0x40700E11) || + (board_id == 0x40800E11) || + (board_id == 0x40820E11) || + (board_id == 0x40830E11)) + goto default_int_mode; + + if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { + err = pci_enable_msix(pdev, cciss_msix_entries, 4); + if (!err) { + c->intr[0] = cciss_msix_entries[0].vector; + c->intr[1] = cciss_msix_entries[1].vector; + c->intr[2] = cciss_msix_entries[2].vector; + c->intr[3] = cciss_msix_entries[3].vector; + c->msix_vector = 1; + return; + } + if (err > 0) { + printk(KERN_WARNING "cciss: only %d MSI-X vectors " + "available\n", err); + } else { + printk(KERN_WARNING "cciss: MSI-X init failed %d\n", + err); + } + } + if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) { + if (!pci_enable_msi(pdev)) { + c->intr[SIMPLE_MODE_INT] = pdev->irq; + c->msi_vector = 1; + return; + } else { + printk(KERN_WARNING "cciss: MSI init failed\n"); + c->intr[SIMPLE_MODE_INT] = pdev->irq; + return; + } + } +#endif /* CONFIG_PCI_MSI */ + /* if we get here we're going to use the default interrupt mode */ +default_int_mode: + c->intr[SIMPLE_MODE_INT] = pdev->irq; + return; +} + static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; @@ -2722,7 +2776,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = pdev->irq; +/* If the kernel supports MSI/MSI-X we will try to enable that functionality, + * else we use the IO-APIC interrupt assigned to us by system ROM. + */ + cciss_interrupt_mode(c, pdev, board_id); /* * Memory base addr is first addr , the second points to the config @@ -3076,11 +3133,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, /* make sure the board interrupts are off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); - if( request_irq(hba[i]->intr, do_cciss_intr, + if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr, SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, hba[i]->devname, hba[i])) { printk(KERN_ERR "cciss: Unable to get irq %d for %s\n", - hba[i]->intr, hba[i]->devname); + hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname); goto clean2; } hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL); @@ -3186,7 +3243,7 @@ clean4: NR_CMDS * sizeof( ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); - free_irq(hba[i]->intr, hba[i]); + free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]); clean2: unregister_blkdev(hba[i]->major, hba[i]->devname); clean1: @@ -3227,7 +3284,15 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) printk(KERN_WARNING "Error Flushing cache on controller %d\n", i); } - free_irq(hba[i]->intr, hba[i]); + free_irq(hba[i]->intr[2], hba[i]); + +#ifdef CONFIG_PCI_MSI + if (hba[i]->msix_vector) + pci_disable_msix(hba[i]->pdev); + else if (hba[i]->msi_vector) + pci_disable_msi(hba[i]->pdev); +#endif /* CONFIG_PCI_MSI */ + pci_set_drvdata(pdev, NULL); iounmap(hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 3b0858c83897..ad45e581a91d 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -65,7 +65,6 @@ struct ctlr_info unsigned long io_mem_addr; unsigned long io_mem_length; CfgTable_struct __iomem *cfgtable; - unsigned int intr; int interrupts_enabled; int major; int max_commands; @@ -74,6 +73,13 @@ struct ctlr_info int num_luns; int highest_lun; int usage_count; /* number of opens all all minor devices */ +# define DOORBELL_INT 0 +# define PERF_MODE_INT 1 +# define SIMPLE_MODE_INT 2 +# define MEMQ_MODE_INT 3 + unsigned int intr[4]; + unsigned int msix_vector; + unsigned int msi_vector; // information about each logical volume drive_info_struct drv[CISS_MAX_LUN]; diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 2942d32280a5..9e35de05d5c5 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -714,7 +714,7 @@ cciss_scsi_detect(int ctlr) ((struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh; sh->hostdata[0] = (unsigned long) hba[ctlr]; - sh->irq = hba[ctlr]->intr; + sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT]; sh->unique_id = sh->irq; error = scsi_add_host(sh, &hba[ctlr]->pdev->dev); if (error) -- cgit v1.2.3 From 9a5d3023e626a0baf86ac6b892c983b3db13f22b Mon Sep 17 00:00:00 2001 From: Oren Laadan Date: Sun, 8 Jan 2006 01:03:51 -0800 Subject: [PATCH] fork: fix race in setting child's pgrp and tty In fork, child should recopy parent's pgrp/tty after it has tasklist_lock. Otherwise following a setpgid() on the parent, *after* copy_signal(), the child will own a stale pgrp (which may be reused); (eg. if copy_mm() sleeps a long while due to memory pressure). Similar issue for the tty. Signed-off-by: Oren Laadan Cc: Oleg Nesterov Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/fork.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index 7992ee759d89..4bc0bd8ef176 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -811,9 +811,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts sig->it_prof_expires = cputime_zero; sig->it_prof_incr = cputime_zero; - sig->tty = current->signal->tty; - sig->pgrp = process_group(current); - sig->session = current->signal->session; sig->leader = 0; /* session leadership doesn't inherit */ sig->tty_old_pgrp = 0; @@ -1136,15 +1133,15 @@ static task_t *copy_process(unsigned long clone_flags, attach_pid(p, PIDTYPE_PID, p->pid); attach_pid(p, PIDTYPE_TGID, p->tgid); if (thread_group_leader(p)) { + p->signal->tty = current->signal->tty; + p->signal->pgrp = process_group(current); + p->signal->session = current->signal->session; attach_pid(p, PIDTYPE_PGID, process_group(p)); attach_pid(p, PIDTYPE_SID, p->signal->session); if (p->pid) __get_cpu_var(process_counts)++; } - if (!current->signal->tty && p->signal->tty) - p->signal->tty = NULL; - nr_threads++; total_forks++; write_unlock_irq(&tasklist_lock); -- cgit v1.2.3 From ee0acf90d320c29916ba8c5c1b2e908d81f5057d Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:53 -0800 Subject: [PATCH] setpgid: should work for sub-threads setpgid(0, pgid) or setpgid(forked_child_pid, pgid) does not work unless the calling process is a thread_group_leader(). 'man setpgid' does not tell anything about that, so I consider this behaviour is a bug. Signed-off-by: Oleg Nesterov Cc: Oren Laadan Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sys.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kernel/sys.c b/kernel/sys.c index d8e49e659027..43e557211d8d 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1090,10 +1090,11 @@ asmlinkage long sys_times(struct tms __user * tbuf) asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) { struct task_struct *p; + struct task_struct *group_leader = current->group_leader; int err = -EINVAL; if (!pid) - pid = current->pid; + pid = group_leader->pid; if (!pgid) pgid = pid; if (pgid < 0) @@ -1113,16 +1114,16 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (!thread_group_leader(p)) goto out; - if (p->parent == current || p->real_parent == current) { + if (p->parent == current || p->real_parent == group_leader) { err = -EPERM; - if (p->signal->session != current->signal->session) + if (p->signal->session != group_leader->signal->session) goto out; err = -EACCES; if (p->did_exec) goto out; } else { err = -ESRCH; - if (p != current) + if (p != group_leader) goto out; } @@ -1134,7 +1135,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) struct task_struct *p; do_each_task_pid(pgid, PIDTYPE_PGID, p) { - if (p->signal->session == current->signal->session) + if (p->signal->session == group_leader->signal->session) goto ok_pgid; } while_each_task_pid(pgid, PIDTYPE_PGID, p); goto out; -- cgit v1.2.3 From e19f247a3dbd85485ec13174817ae9c2478fe541 Mon Sep 17 00:00:00 2001 From: Oren Laadan Date: Sun, 8 Jan 2006 01:03:58 -0800 Subject: [PATCH] setpgid: should work for sub-threads setsid() does not work unless the calling process is a thread_group_leader(). 'man setpgid' does not tell anything about that, so I consider this behaviour is a bug. Signed-off-by: Oren Laadan Cc: Oleg Nesterov Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/exit.c | 2 +- kernel/sys.c | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index a80824f6108b..caceabf3f230 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -257,7 +257,7 @@ static inline void reparent_to_init(void) void __set_special_pids(pid_t session, pid_t pgrp) { - struct task_struct *curr = current; + struct task_struct *curr = current->group_leader; if (curr->signal->session != session) { detach_pid(curr, PIDTYPE_SID); diff --git a/kernel/sys.c b/kernel/sys.c index 43e557211d8d..f497bf56ada1 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1215,24 +1215,22 @@ asmlinkage long sys_getsid(pid_t pid) asmlinkage long sys_setsid(void) { + struct task_struct *group_leader = current->group_leader; struct pid *pid; int err = -EPERM; - if (!thread_group_leader(current)) - return -EINVAL; - down(&tty_sem); write_lock_irq(&tasklist_lock); - pid = find_pid(PIDTYPE_PGID, current->pid); + pid = find_pid(PIDTYPE_PGID, group_leader->pid); if (pid) goto out; - current->signal->leader = 1; - __set_special_pids(current->pid, current->pid); - current->signal->tty = NULL; - current->signal->tty_old_pgrp = 0; - err = process_group(current); + group_leader->signal->leader = 1; + __set_special_pids(group_leader->pid, group_leader->pid); + group_leader->signal->tty = NULL; + group_leader->signal->tty_old_pgrp = 0; + err = process_group(group_leader); out: write_unlock_irq(&tasklist_lock); up(&tty_sem); -- cgit v1.2.3 From f7dd795e913656c390b6bde27790c518973feea1 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:03:59 -0800 Subject: [PATCH] setpgid: should not accept ptraced childs sys_setpgid() allows to change ->pgrp of ptraced childs. 'man setpgid' does not tell anything about that, so I consider this behaviour is a bug. Signed-off-by: Oleg Nesterov Cc: Oren Laadan Cc: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sys.c b/kernel/sys.c index f497bf56ada1..218937e837dc 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1114,7 +1114,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (!thread_group_leader(p)) goto out; - if (p->parent == current || p->real_parent == group_leader) { + if (p->real_parent == group_leader) { err = -EPERM; if (p->signal->session != group_leader->signal->session) goto out; -- cgit v1.2.3 From 37a327957e4b193369854f76afcedaee8d903521 Mon Sep 17 00:00:00 2001 From: Andy Isaacson Date: Sun, 8 Jan 2006 01:04:00 -0800 Subject: [PATCH] block/stat.txt I couldn't find any docs explaining the contents of /sys/block//stat, so I wrote up the following. I'm not completely sure it's accurate - Jens, could you give a yea or nay on this? In particular, the counts of read/write IOs and read/write sectors are incremented in different places - it looks like they both increment as the request is being finished, but I'm not completely sure of that. Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/block/stat.txt | 82 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/block/stat.txt diff --git a/Documentation/block/stat.txt b/Documentation/block/stat.txt new file mode 100644 index 000000000000..0dbc946de2ea --- /dev/null +++ b/Documentation/block/stat.txt @@ -0,0 +1,82 @@ +Block layer statistics in /sys/block//stat +=============================================== + +This file documents the contents of the /sys/block//stat file. + +The stat file provides several statistics about the state of block +device . + +Q. Why are there multiple statistics in a single file? Doesn't sysfs + normally contain a single value per file? +A. By having a single file, the kernel can guarantee that the statistics + represent a consistent snapshot of the state of the device. If the + statistics were exported as multiple files containing one statistic + each, it would be impossible to guarantee that a set of readings + represent a single point in time. + +The stat file consists of a single line of text containing 11 decimal +values separated by whitespace. The fields are summarized in the +following table, and described in more detail below. + +Name units description +---- ----- ----------- +read I/Os requests number of read I/Os processed +read merges requests number of read I/Os merged with in-queue I/O +read sectors sectors number of sectors read +read ticks milliseconds total wait time for read requests +write I/Os requests number of write I/Os processed +write merges requests number of write I/Os merged with in-queue I/O +write sectors sectors number of sectors written +write ticks milliseconds total wait time for write requests +in_flight requests number of I/Os currently in flight +io_ticks milliseconds total time this block device has been active +time_in_queue milliseconds total wait time for all requests + +read I/Os, write I/Os +===================== + +These values increment when an I/O request completes. + +read merges, write merges +========================= + +These values increment when an I/O request is merged with an +already-queued I/O request. + +read sectors, write sectors +=========================== + +These values count the number of sectors read from or written to this +block device. The "sectors" in question are the standard UNIX 512-byte +sectors, not any device- or filesystem-specific block size. The +counters are incremented when the I/O completes. + +read ticks, write ticks +======================= + +These values count the number of milliseconds that I/O requests have +waited on this block device. If there are multiple I/O requests waiting, +these values will increase at a rate greater than 1000/second; for +example, if 60 read requests wait for an average of 30 ms, the read_ticks +field will increase by 60*30 = 1800. + +in_flight +========= + +This value counts the number of I/O requests that have been issued to +the device driver but have not yet completed. It does not include I/O +requests that are in the queue but not yet issued to the device driver. + +io_ticks +======== + +This value counts the number of milliseconds during which the device has +had I/O requests queued. + +time_in_queue +============= + +This value counts the number of milliseconds that I/O requests have waited +on this block device. If there are multiple I/O requests waiting, this +value will increase as the product of the number of milliseconds times the +number of requests waiting (see "read ticks" above for an example). -- cgit v1.2.3 From ddc0f846aa7621940b74cee0c91cd26405058a4d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:04:01 -0800 Subject: [PATCH] fs/udf/balloc.c: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/balloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 6598a5037ac8..4fae57d9d115 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -41,7 +41,7 @@ #define uint(x) xuint(x) #define xuint(x) __le ## x -extern inline int find_next_one_bit (void * addr, int size, int offset) +static inline int find_next_one_bit (void * addr, int size, int offset) { uintBPL_t * p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG); int result = offset & ~(BITS_PER_LONG-1); -- cgit v1.2.3 From fe7d37d1fbf8ffe78abd72728b24fb0c64f7af55 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:04:02 -0800 Subject: [PATCH] copy_process: error path cleanup This patch moves 'fork_out:' under 'bad_fork_free:', and removes now unneeded 'if (retval)' check. Signed-off-by: Oleg Nesterov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/fork.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index 4bc0bd8ef176..72e3252c6763 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1146,11 +1146,6 @@ static task_t *copy_process(unsigned long clone_flags, total_forks++; write_unlock_irq(&tasklist_lock); proc_fork_connector(p); - retval = 0; - -fork_out: - if (retval) - return ERR_PTR(retval); return p; bad_fork_cleanup_namespace: @@ -1191,7 +1186,8 @@ bad_fork_cleanup_count: free_uid(p->user); bad_fork_free: free_task(p); - goto fork_out; +fork_out: + return ERR_PTR(retval); } struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs) -- cgit v1.2.3 From fd285bb54d8a3e99810090ae88cfe8ed77d1da25 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:04:07 -0800 Subject: [PATCH] Abandon gcc-2.95.x There's one scsi driver which doesn't compile due to weird __VA_ARGS__ tricks and the rather useful scsi/sd.c is currently getting an ICE. None of the new SAS code compiles, due to extensive use of anonymous unions. The V4L guys are very good at exploiting the gcc-2.95.x macro expansion bug (_why_ does each driver need to implement its own debug macros?) and various people keep on sneaking in anonymous unions, which are rather nice. Plus anonymous unions are rather useful. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/compiler-gcc2.h | 29 ----------------------------- include/linux/compiler.h | 2 -- init/main.c | 7 +------ 3 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 include/linux/compiler-gcc2.h diff --git a/include/linux/compiler-gcc2.h b/include/linux/compiler-gcc2.h deleted file mode 100644 index ebed17660c5f..000000000000 --- a/include/linux/compiler-gcc2.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Never include this file directly. Include instead. */ - -/* These definitions are for GCC v2.x. */ - -/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented - a mechanism by which the user can annotate likely branch directions and - expect the blocks to be reordered appropriately. Define __builtin_expect - to nothing for earlier compilers. */ -#include - -#if __GNUC_MINOR__ < 96 -# define __builtin_expect(x, expected_value) (x) -#endif - -#define __attribute_used__ __attribute__((__unused__)) - -/* - * The attribute `pure' is not implemented in GCC versions earlier - * than 2.96. - */ -#if __GNUC_MINOR__ >= 96 -# define __attribute_pure__ __attribute__((pure)) -# define __attribute_const__ __attribute__((__const__)) -#endif - -/* GCC 2.95.x/2.96 recognize __va_copy, but not va_copy. Actually later GCC's - * define both va_copy and __va_copy, but the latter may go away, so limit this - * to this header */ -#define va_copy __va_copy diff --git a/include/linux/compiler.h b/include/linux/compiler.h index d7378215b851..f23d3c6fc2c0 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -42,8 +42,6 @@ extern void __chk_io_ptr(void __iomem *); # include #elif __GNUC__ == 3 # include -#elif __GNUC__ == 2 -# include #else # error Sorry, your compiler is too old/not recognized. #endif diff --git a/init/main.c b/init/main.c index afe5eb84ad52..8342c2890b16 100644 --- a/init/main.c +++ b/init/main.c @@ -58,11 +58,6 @@ * This is one of the first .c files built. Error out early * if we have compiler trouble.. */ -#if __GNUC__ == 2 && __GNUC_MINOR__ == 96 -#ifdef CONFIG_FRAME_POINTER -#error This compiler cannot compile correctly with frame pointers enabled -#endif -#endif #ifdef CONFIG_X86_LOCAL_APIC #include @@ -74,7 +69,7 @@ * To avoid associated bogus bug reports, we flatly refuse to compile * with a gcc that is known to be too old from the very beginning. */ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) +#if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2) #error Sorry, your GCC is too old. It builds incorrect kernels. #endif -- cgit v1.2.3 From a1365647022eb05a5993f270a78e9bef3bf554eb Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:04:09 -0800 Subject: [PATCH] remove gcc-2 checks Remove various things which were checking for gcc-1.x and gcc-2.x compilers. From: Adrian Bunk Some documentation updates and removes some code paths for gcc < 3.2. Acked-by: Russell King Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/Changes | 31 +++++-------------------------- README | 7 ++----- arch/arm/kernel/asm-offsets.c | 9 ++------- arch/arm26/kernel/asm-offsets.c | 7 ------- arch/i386/Kconfig | 4 ---- arch/i386/Makefile | 5 +---- arch/i386/Makefile.cpu | 10 +++++----- arch/ia64/Makefile | 4 ---- arch/ia64/kernel/head.S | 2 +- arch/ia64/kernel/ia64_ksyms.c | 2 +- arch/ia64/oprofile/backtrace.c | 2 +- drivers/md/raid0.c | 6 ------ drivers/media/video/v4l2-common.c | 2 -- fs/ocfs2/cluster/masklog.h | 7 +++---- fs/xfs/xfs_log.h | 8 +------- include/asm-alpha/compiler.h | 2 -- include/asm-alpha/processor.h | 21 --------------------- include/asm-ia64/bug.h | 6 +----- include/asm-ia64/spinlock.h | 2 +- include/asm-sparc64/system.h | 4 ---- include/asm-um/rwsem.h | 4 ---- include/asm-v850/unistd.h | 18 ------------------ include/linux/byteorder/generic.h | 2 +- include/linux/byteorder/swab.h | 2 +- include/linux/byteorder/swabb.h | 2 +- include/linux/compiler-gcc.h | 9 +++++++++ include/linux/compiler-gcc3.h | 17 ----------------- include/linux/compiler-gcc4.h | 7 ------- include/linux/kernel.h | 2 -- include/linux/seccomp.h | 6 +----- include/linux/spinlock_types_up.h | 14 -------------- sound/isa/wavefront/wavefront_synth.c | 7 ------- 32 files changed, 37 insertions(+), 194 deletions(-) diff --git a/Documentation/Changes b/Documentation/Changes index 86b86399d61d..fe5ae0f55020 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -31,8 +31,6 @@ al espa Eine deutsche Version dieser Datei finden Sie unter . -Last updated: October 29th, 2002 - Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). Current Minimal Requirements @@ -48,7 +46,7 @@ necessary on all systems; obviously, if you don't have any ISDN hardware, for example, you probably needn't concern yourself with isdn4k-utils. -o Gnu C 2.95.3 # gcc --version +o Gnu C 3.2 # gcc --version o Gnu make 3.79.1 # make --version o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version @@ -74,26 +72,7 @@ GCC --- The gcc version requirements may vary depending on the type of CPU in your -computer. The next paragraph applies to users of x86 CPUs, but not -necessarily to users of other CPUs. Users of other CPUs should obtain -information about their gcc version requirements from another source. - -The recommended compiler for the kernel is gcc 2.95.x (x >= 3), and it -should be used when you need absolute stability. You may use gcc 3.0.x -instead if you wish, although it may cause problems. Later versions of gcc -have not received much testing for Linux kernel compilation, and there are -almost certainly bugs (mainly, but not exclusively, in the kernel) that -will need to be fixed in order to use these compilers. In any case, using -pgcc instead of plain gcc is just asking for trouble. - -The Red Hat gcc 2.96 compiler subtree can also be used to build this tree. -You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build -the kernel correctly. - -In addition, please pay attention to compiler optimization. Anything -greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95.x -or derivatives, be sure not to use -fstrict-aliasing (which, depending on -your version of gcc 2.95.x, may necessitate using -fno-strict-aliasing). +computer. Make ---- @@ -322,9 +301,9 @@ Getting updated software Kernel compilation ****************** -gcc 2.95.3 ----------- -o +gcc +--- +o Make ---- diff --git a/README b/README index 61c4f7429233..cd5e2eb6213b 100644 --- a/README +++ b/README @@ -183,11 +183,8 @@ CONFIGURING the kernel: COMPILING the kernel: - - Make sure you have gcc 2.95.3 available. - gcc 2.91.66 (egcs-1.1.2), and gcc 2.7.2.3 are known to miscompile - some parts of the kernel, and are *no longer supported*. - Also remember to upgrade your binutils package (for as/ld/nm and company) - if necessary. For more information, refer to Documentation/Changes. + - Make sure you have at least gcc 3.2 available. + For more information, refer to Documentation/Changes. Please note that you can still run a.out user programs with this kernel. diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 04d3082a7b94..0abbce8c70bc 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -23,20 +23,15 @@ #error Sorry, your compiler targets APCS-26 but this kernel requires APCS-32 #endif /* - * GCC 2.95.1, 2.95.2: ignores register clobber list in asm(). * GCC 3.0, 3.1: general bad code generation. * GCC 3.2.0: incorrect function argument offset calculation. * GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c * (http://gcc.gnu.org/PR8896) and incorrect structure * initialisation in fs/jffs2/erase.c */ -#if __GNUC__ < 2 || \ - (__GNUC__ == 2 && __GNUC_MINOR__ < 95) || \ - (__GNUC__ == 2 && __GNUC_MINOR__ == 95 && __GNUC_PATCHLEVEL__ != 0 && \ - __GNUC_PATCHLEVEL__ < 3) || \ - (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) #error Your compiler is too buggy; it is known to miscompile kernels. -#error Known good compilers: 2.95.3, 2.95.4, 2.96, 3.3 +#error Known good compilers: 3.3 #endif /* Use marker if you need to separate the values later */ diff --git a/arch/arm26/kernel/asm-offsets.c b/arch/arm26/kernel/asm-offsets.c index 4ccacaef94df..ac682d5fd039 100644 --- a/arch/arm26/kernel/asm-offsets.c +++ b/arch/arm26/kernel/asm-offsets.c @@ -25,13 +25,6 @@ #if defined(__APCS_32__) && defined(CONFIG_CPU_26) #error Sorry, your compiler targets APCS-32 but this kernel requires APCS-26 #endif -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) -#error Sorry, your compiler is known to miscompile kernels. Only use gcc 2.95.3 and later. -#endif -#if __GNUC__ == 2 && __GNUC_MINOR__ == 95 -/* shame we can't detect the .1 or .2 releases */ -#warning GCC 2.95.2 and earlier miscompiles kernels. -#endif /* Use marker if you need to separate the values later */ diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 968fabd8723f..486449e9e710 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -630,10 +630,6 @@ config REGPARM and passes the first three arguments of a function call in registers. This will probably break binary only modules. - This feature is only enabled for gcc-3.0 and later - earlier compilers - generate incorrect output with certain kernel constructs when - -mregparm=3 is used. - config SECCOMP bool "Enable seccomp to safely compute untrusted bytecode" depends on PROC_FS diff --git a/arch/i386/Makefile b/arch/i386/Makefile index d121ea18460f..b84119f9cc63 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -37,10 +37,7 @@ CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2) # CPU-specific tuning. Anything which can be shared with UML should go here. include $(srctree)/arch/i386/Makefile.cpu -# -mregparm=3 works ok on gcc-3.0 and later -# -GCC_VERSION := $(call cc-version) -cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;) +cflags-$(CONFIG_REGPARM) += -mregparm=3 # Disable unit-at-a-time mode, it makes gcc use a lot more stack # due to the lack of sharing of stacklots. diff --git a/arch/i386/Makefile.cpu b/arch/i386/Makefile.cpu index 8e51456df23d..dcd936ef45db 100644 --- a/arch/i386/Makefile.cpu +++ b/arch/i386/Makefile.cpu @@ -1,7 +1,7 @@ # CPU tuning section - shared with UML. # Must change only cflags-y (or [yn]), not CFLAGS! That makes a difference for UML. -#-mtune exists since gcc 3.4, and some -mcpu flavors didn't exist in gcc 2.95. +#-mtune exists since gcc 3.4 HAS_MTUNE := $(call cc-option-yn, -mtune=i386) ifeq ($(HAS_MTUNE),y) tune = $(call cc-option,-mtune=$(1),) @@ -14,7 +14,7 @@ cflags-$(CONFIG_M386) += -march=i386 cflags-$(CONFIG_M486) += -march=i486 cflags-$(CONFIG_M586) += -march=i586 cflags-$(CONFIG_M586TSC) += -march=i586 -cflags-$(CONFIG_M586MMX) += $(call cc-option,-march=pentium-mmx,-march=i586) +cflags-$(CONFIG_M586MMX) += -march=pentium-mmx cflags-$(CONFIG_M686) += -march=i686 cflags-$(CONFIG_MPENTIUMII) += -march=i686 $(call tune,pentium2) cflags-$(CONFIG_MPENTIUMIII) += -march=i686 $(call tune,pentium3) @@ -23,8 +23,8 @@ cflags-$(CONFIG_MPENTIUM4) += -march=i686 $(call tune,pentium4) cflags-$(CONFIG_MK6) += -march=k6 # Please note, that patches that add -march=athlon-xp and friends are pointless. # They make zero difference whatsosever to performance at this time. -cflags-$(CONFIG_MK7) += $(call cc-option,-march=athlon,-march=i686 $(align)-functions=4) -cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,$(call cc-option,-march=athlon,-march=i686 $(align)-functions=4)) +cflags-$(CONFIG_MK7) += -march=athlon +cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,-march=athlon) cflags-$(CONFIG_MCRUSOE) += -march=i686 $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0 cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) @@ -37,5 +37,5 @@ cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) cflags-$(CONFIG_X86_ELAN) += -march=i486 # Geode GX1 support -cflags-$(CONFIG_MGEODEGX1) += $(call cc-option,-march=pentium-mmx,-march=i486) +cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 67932ad53082..57b047c27e46 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -37,10 +37,6 @@ $(error Sorry, you need a newer version of the assember, one that is built from ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifneq ($(shell if [ $(GCC_VERSION) -lt 0300 ] ; then echo "bad"; fi ;),) -$(error Sorry, your compiler is too old. GCC v2.96 is known to generate bad code.) -endif - ifeq ($(GCC_VERSION),0304) cflags-$(CONFIG_ITANIUM) += -mtune=merced cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index bfe65b2e8621..fbc7ea35dd57 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -1060,7 +1060,7 @@ SET_REG(b5); * the clobber lists for spin_lock() in include/asm-ia64/spinlock.h. */ -#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) GLOBAL_ENTRY(ia64_spinlock_contention_pre3_4) .prologue diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 5db9d3bcbbcb..e72de580ebbf 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -103,7 +103,7 @@ EXPORT_SYMBOL(unw_init_running); #ifdef ASM_SUPPORTED # ifdef CONFIG_SMP -# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +# if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) /* * This is not a normal routine and we don't want a function descriptor for it, so we use * a fake declaration here. diff --git a/arch/ia64/oprofile/backtrace.c b/arch/ia64/oprofile/backtrace.c index b7dabbfb0d61..adb01566bd57 100644 --- a/arch/ia64/oprofile/backtrace.c +++ b/arch/ia64/oprofile/backtrace.c @@ -32,7 +32,7 @@ typedef struct u64 *prev_pfs_loc; /* state for WAR for old spinlock ool code */ } ia64_backtrace_t; -#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) /* * Returns non-zero if the PC is in the spinlock contention out-of-line code * with non-standard calling sequence (on older compilers). diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index abbca150202b..d03f99cf4b7d 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -306,9 +306,6 @@ static int raid0_run (mddev_t *mddev) printk("raid0 : conf->hash_spacing is %llu blocks.\n", (unsigned long long)conf->hash_spacing); { -#if __GNUC__ < 3 - volatile -#endif sector_t s = mddev->array_size; sector_t space = conf->hash_spacing; int round; @@ -439,9 +436,6 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) { -#if __GNUC__ < 3 - volatile -#endif sector_t x = block >> conf->preshift; sector_div(x, (u32)conf->hash_spacing); zone = conf->hash_table[x]; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 597b8db35a13..62a7d636ef11 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -191,9 +191,7 @@ char *v4l2_type_names[] = { }; char *v4l2_ioctl_names[256] = { -#if __GNUC__ >= 3 [0 ... 255] = "UNKNOWN", -#endif [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index f5ef5ea61a05..e8c56a3d9c64 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -212,11 +212,10 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; mlog(ML_ENTRY, "ENTRY:\n"); \ } while (0) -/* We disable this for old compilers since they don't have support for - * __builtin_types_compatible_p. +/* + * We disable this for sparse. */ -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) && \ - !defined(__CHECKER__) +#if !defined(__CHECKER__) #define mlog_exit(st) do { \ if (__builtin_types_compatible_p(typeof(st), unsigned long)) \ mlog(ML_EXIT, "EXIT: %lu\n", (unsigned long) (st)); \ diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index 158829ca56f6..f40d4391fcfc 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h @@ -30,13 +30,7 @@ * By comparing each compnent, we don't have to worry about extra * endian issues in treating two 32 bit numbers as one 64 bit number */ -static -#if defined(__GNUC__) && (__GNUC__ == 2) && ( (__GNUC_MINOR__ == 95) || (__GNUC_MINOR__ == 96)) -__attribute__((unused)) /* gcc 2.95, 2.96 miscompile this when inlined */ -#else -__inline__ -#endif -xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2) +static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2) { if (CYCLE_LSN(lsn1) != CYCLE_LSN(lsn2)) return (CYCLE_LSN(lsn1)= 1 || __GNUC__ > 3 #undef __always_inline #define __always_inline inline __attribute__((always_inline)) -#endif #endif /* __ALPHA_COMPILER_H */ diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h index 059780a7d3d7..bb1a7a3abb8b 100644 --- a/include/asm-alpha/processor.h +++ b/include/asm-alpha/processor.h @@ -77,7 +77,6 @@ unsigned long get_wchan(struct task_struct *p); #define spin_lock_prefetch(lock) do { } while (0) #endif -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) extern inline void prefetch(const void *ptr) { __builtin_prefetch(ptr, 0, 3); @@ -95,24 +94,4 @@ extern inline void spin_lock_prefetch(const void *ptr) } #endif -#else -extern inline void prefetch(const void *ptr) -{ - __asm__ ("ldl $31,%0" : : "m"(*(char *)ptr)); -} - -extern inline void prefetchw(const void *ptr) -{ - __asm__ ("ldq $31,%0" : : "m"(*(char *)ptr)); -} - -#ifdef CONFIG_SMP -extern inline void spin_lock_prefetch(const void *ptr) -{ - __asm__ ("ldq $31,%0" : : "m"(*(char *)ptr)); -} -#endif - -#endif /* GCC 3.1 */ - #endif /* __ASM_ALPHA_PROCESSOR_H */ diff --git a/include/asm-ia64/bug.h b/include/asm-ia64/bug.h index 3aa0a0a5474b..823616b5020b 100644 --- a/include/asm-ia64/bug.h +++ b/include/asm-ia64/bug.h @@ -2,11 +2,7 @@ #define _ASM_IA64_BUG_H #ifdef CONFIG_BUG -#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) -# define ia64_abort() __builtin_trap() -#else -# define ia64_abort() (*(volatile int *) 0 = 0) -#endif +#define ia64_abort() __builtin_trap() #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) /* should this BUG be made generic? */ diff --git a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h index 0c91a76c5ea3..9e83210dc312 100644 --- a/include/asm-ia64/spinlock.h +++ b/include/asm-ia64/spinlock.h @@ -34,7 +34,7 @@ __raw_spin_lock_flags (raw_spinlock_t *lock, unsigned long flags) { register volatile unsigned int *ptr asm ("r31") = &lock->lock; -#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) # ifdef CONFIG_ITANIUM /* don't use brl on Itanium... */ asm volatile ("{\n\t" diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index b5417529f6f1..309f1466b6fa 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -193,11 +193,7 @@ do { \ * not preserve it's value. Hairy, but it lets us remove 2 loads * and 2 stores in this critical code path. -DaveM */ -#if __GNUC__ >= 3 #define EXTRA_CLOBBER ,"%l1" -#else -#define EXTRA_CLOBBER -#endif #define switch_to(prev, next, last) \ do { if (test_thread_flag(TIF_PERFCTR)) { \ unsigned long __tmp; \ diff --git a/include/asm-um/rwsem.h b/include/asm-um/rwsem.h index 661c0e54702b..b5fc449dc86b 100644 --- a/include/asm-um/rwsem.h +++ b/include/asm-um/rwsem.h @@ -1,10 +1,6 @@ #ifndef __UM_RWSEM_H__ #define __UM_RWSEM_H__ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) -#define __builtin_expect(exp,c) (exp) -#endif - #include "asm/arch/rwsem.h" #endif diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h index 5a86f8e976ec..82460a7bb233 100644 --- a/include/asm-v850/unistd.h +++ b/include/asm-v850/unistd.h @@ -241,9 +241,6 @@ /* User programs sometimes end up including this header file (indirectly, via uClibc header files), so I'm a bit nervous just including . */ -#if !defined(__builtin_expect) && __GNUC__ == 2 && __GNUC_MINOR__ < 96 -#define __builtin_expect(x, expected_value) (x) -#endif #define __syscall_return(type, res) \ do { \ @@ -346,20 +343,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e) \ __syscall_return (type, __ret); \ } -#if __GNUC__ < 3 -/* In older versions of gcc, `asm' statements with more than 10 - input/output arguments produce a fatal error. To work around this - problem, we use two versions, one for gcc-3.x and one for earlier - versions of gcc (the `earlier gcc' version doesn't work with gcc-3.x - because gcc-3.x doesn't allow clobbers to also be input arguments). */ -#define __SYSCALL6_TRAP(syscall, ret, a, b, c, d, e, f) \ - __asm__ __volatile__ ("trap " SYSCALL_LONG_TRAP \ - : "=r" (ret), "=r" (syscall) \ - : "1" (syscall), \ - "r" (a), "r" (b), "r" (c), "r" (d), \ - "r" (e), "r" (f) \ - : SYSCALL_CLOBBERS, SYSCALL_ARG4, SYSCALL_ARG5); -#else /* __GNUC__ >= 3 */ #define __SYSCALL6_TRAP(syscall, ret, a, b, c, d, e, f) \ __asm__ __volatile__ ("trap " SYSCALL_LONG_TRAP \ : "=r" (ret), "=r" (syscall), \ @@ -368,7 +351,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e) \ "r" (a), "r" (b), "r" (c), "r" (d), \ "2" (e), "3" (f) \ : SYSCALL_CLOBBERS); -#endif #define _syscall6(type, name, atype, a, btype, b, ctype, c, dtype, d, etype, e, ftype, f) \ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h index 04bd756efc67..e86e4a938373 100644 --- a/include/linux/byteorder/generic.h +++ b/include/linux/byteorder/generic.h @@ -156,7 +156,7 @@ extern __be32 htonl(__u32); extern __u16 ntohs(__be16); extern __be16 htons(__u16); -#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__) +#if defined(__GNUC__) && defined(__OPTIMIZE__) #define ___htonl(x) __cpu_to_be32(x) #define ___htons(x) __cpu_to_be16(x) diff --git a/include/linux/byteorder/swab.h b/include/linux/byteorder/swab.h index 2f1cb775125a..25f7f32883ec 100644 --- a/include/linux/byteorder/swab.h +++ b/include/linux/byteorder/swab.h @@ -110,7 +110,7 @@ /* * Allow constant folding */ -#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__) +#if defined(__GNUC__) && defined(__OPTIMIZE__) # define __swab16(x) \ (__builtin_constant_p((__u16)(x)) ? \ ___swab16((x)) : \ diff --git a/include/linux/byteorder/swabb.h b/include/linux/byteorder/swabb.h index d5f2a3205109..ae5e5f914bf4 100644 --- a/include/linux/byteorder/swabb.h +++ b/include/linux/byteorder/swabb.h @@ -77,7 +77,7 @@ /* * Allow constant folding */ -#if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__) +#if defined(__GNUC__) && defined(__OPTIMIZE__) # define __swahw32(x) \ (__builtin_constant_p((__u32)(x)) ? \ ___swahw32((x)) : \ diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 152734055403..2e05e1e6b0e6 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -15,3 +15,12 @@ ({ unsigned long __ptr; \ __asm__ ("" : "=g"(__ptr) : "0"(ptr)); \ (typeof(ptr)) (__ptr + (off)); }) + + +#define inline inline __attribute__((always_inline)) +#define __inline__ __inline__ __attribute__((always_inline)) +#define __inline __inline __attribute__((always_inline)) +#define __deprecated __attribute__((deprecated)) +#define noinline __attribute__((noinline)) +#define __attribute_pure__ __attribute__((pure)) +#define __attribute_const__ __attribute__((__const__)) diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h index a6fa615afab5..4209082ee934 100644 --- a/include/linux/compiler-gcc3.h +++ b/include/linux/compiler-gcc3.h @@ -3,29 +3,12 @@ /* These definitions are for GCC v3.x. */ #include -#if __GNUC_MINOR__ >= 1 -# define inline inline __attribute__((always_inline)) -# define __inline__ __inline__ __attribute__((always_inline)) -# define __inline __inline __attribute__((always_inline)) -#endif - -#if __GNUC_MINOR__ > 0 -# define __deprecated __attribute__((deprecated)) -#endif - #if __GNUC_MINOR__ >= 3 # define __attribute_used__ __attribute__((__used__)) #else # define __attribute_used__ __attribute__((__unused__)) #endif -#define __attribute_pure__ __attribute__((pure)) -#define __attribute_const__ __attribute__((__const__)) - -#if __GNUC_MINOR__ >= 1 -#define noinline __attribute__((noinline)) -#endif - #if __GNUC_MINOR__ >= 4 #define __must_check __attribute__((warn_unused_result)) #endif diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h index 53686c037a06..e913e9beaf69 100644 --- a/include/linux/compiler-gcc4.h +++ b/include/linux/compiler-gcc4.h @@ -3,14 +3,7 @@ /* These definitions are for GCC v4.x. */ #include -#define inline inline __attribute__((always_inline)) -#define __inline__ __inline__ __attribute__((always_inline)) -#define __inline __inline __attribute__((always_inline)) -#define __deprecated __attribute__((deprecated)) #define __attribute_used__ __attribute__((__used__)) -#define __attribute_pure__ __attribute__((pure)) -#define __attribute_const__ __attribute__((__const__)) -#define noinline __attribute__((noinline)) #define __must_check __attribute__((warn_unused_result)) #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b1e407a4fbda..ca7ff8fdd090 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -316,8 +316,6 @@ extern int randomize_va_space; #endif /* Trap pasters of __FUNCTION__ at compile-time */ -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 95 #define __FUNCTION__ (__func__) -#endif #endif diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index dc89116bb1ca..cd2773b29a64 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -26,11 +26,7 @@ static inline int has_secure_computing(struct thread_info *ti) #else /* CONFIG_SECCOMP */ -#if (__GNUC__ > 2) - typedef struct { } seccomp_t; -#else - typedef struct { int gcc_is_buggy; } seccomp_t; -#endif +typedef struct { } seccomp_t; #define secure_computing(x) do { } while (0) /* static inline to preserve typechecking */ diff --git a/include/linux/spinlock_types_up.h b/include/linux/spinlock_types_up.h index def2d173a8db..04135b0e198e 100644 --- a/include/linux/spinlock_types_up.h +++ b/include/linux/spinlock_types_up.h @@ -22,30 +22,16 @@ typedef struct { #else -/* - * All gcc 2.95 versions and early versions of 2.96 have a nasty bug - * with empty initializers. - */ -#if (__GNUC__ > 2) typedef struct { } raw_spinlock_t; #define __RAW_SPIN_LOCK_UNLOCKED { } -#else -typedef struct { int gcc_is_buggy; } raw_spinlock_t; -#define __RAW_SPIN_LOCK_UNLOCKED (raw_spinlock_t) { 0 } -#endif #endif -#if (__GNUC__ > 2) typedef struct { /* no debug version on UP */ } raw_rwlock_t; #define __RAW_RW_LOCK_UNLOCKED { } -#else -typedef struct { int gcc_is_buggy; } raw_rwlock_t; -#define __RAW_RW_LOCK_UNLOCKED (raw_rwlock_t) { 0 } -#endif #endif /* __LINUX_SPINLOCK_TYPES_UP_H */ diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 679d0ae97e4f..ed81eec6e732 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -115,18 +115,11 @@ MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS"); #ifdef WF_DEBUG -#if defined(NEW_MACRO_VARARGS) || __GNUC__ >= 3 #define DPRINT(cond, ...) \ if ((dev->debug & (cond)) == (cond)) { \ snd_printk (__VA_ARGS__); \ } #else -#define DPRINT(cond, args...) \ - if ((dev->debug & (cond)) == (cond)) { \ - snd_printk (args); \ - } -#endif -#else #define DPRINT(cond, args...) #endif /* WF_DEBUG */ -- cgit v1.2.3 From 44ac8413901167589226abf824d994aa57e4fd28 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 8 Jan 2006 01:04:10 -0800 Subject: [PATCH] /dev/mem __HAVE_PHYS_MEM_ACCESS_PROT tidy-up Tidy up __HAVE_PHYS_MEM_ACCESS_PROT usage to make mmap_mem() easier to read. Signed-off-by: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index a85f3a361442..ce3ff8641191 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -228,20 +228,25 @@ static ssize_t write_mem(struct file * file, const char __user * buf, return written; } +#ifndef __HAVE_PHYS_MEM_ACCESS_PROT +static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot) +{ +#ifdef pgprot_noncached + unsigned long offset = pfn << PAGE_SHIFT; + + if (uncached_access(file, offset)) + return pgprot_noncached(vma_prot); +#endif + return vma_prot; +} +#endif + static int mmap_mem(struct file * file, struct vm_area_struct * vma) { -#if defined(__HAVE_PHYS_MEM_ACCESS_PROT) vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); -#elif defined(pgprot_noncached) - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int uncached; - - uncached = uncached_access(file, offset); - if (uncached) - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, -- cgit v1.2.3 From 80851ef2a5a404e6054211ca96ecd5ac4b06d297 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 8 Jan 2006 01:04:13 -0800 Subject: [PATCH] /dev/mem: validate mmap requests Add a hook so architectures can validate /dev/mem mmap requests. This is analogous to validation we already perform in the read/write paths. The identity mapping scheme used on ia64 requires that each 16MB or 64MB granule be accessed with exactly one attribute (write-back or uncacheable). This avoids "attribute aliasing", which can cause a machine check. Sample problem scenario: - Machine supports VGA, so it has uncacheable (UC) MMIO at 640K-768K - efi_memmap_init() discards any write-back (WB) memory in the first granule - Application (e.g., "hwinfo") mmaps /dev/mem, offset 0 - hwinfo receives UC mapping (the default, since memmap says "no WB here") - Machine check abort (on chipsets that don't support UC access to WB memory, e.g., sx1000) In the scenario above, the only choices are - Use WB for hwinfo mmap. Can't do this because it causes attribute aliasing with the UC mapping for the VGA MMIO space. - Use UC for hwinfo mmap. Can't do this because the chipset may not support UC for that region. - Disallow the hwinfo mmap with -EINVAL. That's what this patch does. Signed-off-by: Bjorn Helgaas Cc: Hugh Dickins Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/kernel/efi.c | 160 ++++++++++++++++++++++++++++++++++--------------- drivers/char/mem.c | 14 ++++- include/asm-ia64/io.h | 1 + 3 files changed, 124 insertions(+), 51 deletions(-) diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index a3aa45cbcfa0..c485a3b32ba8 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -247,6 +247,32 @@ typedef struct kern_memdesc { static kern_memdesc_t *kern_memmap; +#define efi_md_size(md) (md->num_pages << EFI_PAGE_SHIFT) + +static inline u64 +kmd_end(kern_memdesc_t *kmd) +{ + return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT)); +} + +static inline u64 +efi_md_end(efi_memory_desc_t *md) +{ + return (md->phys_addr + efi_md_size(md)); +} + +static inline int +efi_wb(efi_memory_desc_t *md) +{ + return (md->attribute & EFI_MEMORY_WB); +} + +static inline int +efi_uc(efi_memory_desc_t *md) +{ + return (md->attribute & EFI_MEMORY_UC); +} + static void walk (efi_freemem_callback_t callback, void *arg, u64 attr) { @@ -595,8 +621,8 @@ efi_get_iobase (void) return 0; } -u32 -efi_mem_type (unsigned long phys_addr) +static efi_memory_desc_t * +efi_memory_descriptor (unsigned long phys_addr) { void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; @@ -610,13 +636,13 @@ efi_mem_type (unsigned long phys_addr) md = p; if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) - return md->type; + return md; } return 0; } -u64 -efi_mem_attributes (unsigned long phys_addr) +static int +efi_memmap_has_mmio (void) { void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; @@ -629,36 +655,98 @@ efi_mem_attributes (unsigned long phys_addr) for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) - return md->attribute; + if (md->type == EFI_MEMORY_MAPPED_IO) + return 1; } return 0; } + +u32 +efi_mem_type (unsigned long phys_addr) +{ + efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); + + if (md) + return md->type; + return 0; +} + +u64 +efi_mem_attributes (unsigned long phys_addr) +{ + efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); + + if (md) + return md->attribute; + return 0; +} EXPORT_SYMBOL(efi_mem_attributes); +/* + * Determines whether the memory at phys_addr supports the desired + * attribute (WB, UC, etc). If this returns 1, the caller can safely + * access *size bytes at phys_addr with the specified attribute. + */ +static int +efi_mem_attribute_range (unsigned long phys_addr, unsigned long *size, u64 attr) +{ + efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); + unsigned long md_end; + + if (!md || (md->attribute & attr) != attr) + return 0; + + do { + md_end = efi_md_end(md); + if (phys_addr + *size <= md_end) + return 1; + + md = efi_memory_descriptor(md_end); + if (!md || (md->attribute & attr) != attr) { + *size = md_end - phys_addr; + return 1; + } + } while (md); + return 0; +} + +/* + * For /dev/mem, we only allow read & write system calls to access + * write-back memory, because read & write don't allow the user to + * control access size. + */ int valid_phys_addr_range (unsigned long phys_addr, unsigned long *size) { - void *efi_map_start, *efi_map_end, *p; - efi_memory_desc_t *md; - u64 efi_desc_size; + return efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB); +} - efi_map_start = __va(ia64_boot_param->efi_memmap); - efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; - efi_desc_size = ia64_boot_param->efi_memdesc_size; +/* + * We allow mmap of anything in the EFI memory map that supports + * either write-back or uncacheable access. For uncacheable regions, + * the supported access sizes are system-dependent, and the user is + * responsible for using the correct size. + * + * Note that this doesn't currently allow access to hot-added memory, + * because that doesn't appear in the boot-time EFI memory map. + */ +int +valid_mmap_phys_addr_range (unsigned long phys_addr, unsigned long *size) +{ + if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_WB)) + return 1; - for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { - md = p; + if (efi_mem_attribute_range(phys_addr, size, EFI_MEMORY_UC)) + return 1; - if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) { - if (!(md->attribute & EFI_MEMORY_WB)) - return 0; + /* + * Some firmware doesn't report MMIO regions in the EFI memory map. + * The Intel BigSur (a.k.a. HP i2000) has this problem. In this + * case, we can't use the EFI memory map to validate mmap requests. + */ + if (!efi_memmap_has_mmio()) + return 1; - if (*size > md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - phys_addr) - *size = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - phys_addr; - return 1; - } - } return 0; } @@ -707,32 +795,6 @@ efi_uart_console_only(void) return 0; } -#define efi_md_size(md) (md->num_pages << EFI_PAGE_SHIFT) - -static inline u64 -kmd_end(kern_memdesc_t *kmd) -{ - return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT)); -} - -static inline u64 -efi_md_end(efi_memory_desc_t *md) -{ - return (md->phys_addr + efi_md_size(md)); -} - -static inline int -efi_wb(efi_memory_desc_t *md) -{ - return (md->attribute & EFI_MEMORY_WB); -} - -static inline int -efi_uc(efi_memory_desc_t *md) -{ - return (md->attribute & EFI_MEMORY_UC); -} - /* * Look for the first granule aligned memory descriptor memory * that is big enough to hold EFI memory map. Make sure this diff --git a/drivers/char/mem.c b/drivers/char/mem.c index ce3ff8641191..5b2d18035073 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -101,6 +101,11 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t *count) return 1; } + +static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t *size) +{ + return 1; +} #endif /* @@ -244,15 +249,20 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, static int mmap_mem(struct file * file, struct vm_area_struct * vma) { + size_t size = vma->vm_end - vma->vm_start; + + if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, &size)) + return -EINVAL; + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, - vma->vm_end - vma->vm_start, + size, vma->vm_page_prot); /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end-vma->vm_start, + size, vma->vm_page_prot)) return -EAGAIN; return 0; diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h index cf772a67f858..b64fdb985494 100644 --- a/include/asm-ia64/io.h +++ b/include/asm-ia64/io.h @@ -89,6 +89,7 @@ phys_to_virt (unsigned long address) #define ARCH_HAS_VALID_PHYS_ADDR_RANGE extern int valid_phys_addr_range (unsigned long addr, size_t *count); /* efi.c */ +extern int valid_mmap_phys_addr_range (unsigned long addr, size_t *count); /* * The following two macros are deprecated and scheduled for removal. -- cgit v1.2.3 From fee781e6c25772db862d3322b4745a896022a4f1 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:04:16 -0800 Subject: [PATCH] fs/proc/: function prototypes belong in header files Function prototypes belong into header files. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/generic.c | 2 ++ fs/proc/inode.c | 2 +- fs/proc/internal.h | 4 ++++ fs/proc/root.c | 3 ++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 72b431d0a0a4..20e5c4509a43 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -21,6 +21,8 @@ #include #include +#include "internal.h" + static ssize_t proc_file_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos); static ssize_t proc_file_write(struct file *file, const char __user *buffer, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e6a818a93f3d..6573f31f1fd9 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -19,7 +19,7 @@ #include #include -extern void free_proc_entry(struct proc_dir_entry *); +#include "internal.h" static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de) { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 3e55198f9806..95a1cf32b838 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -37,6 +37,10 @@ extern int proc_tgid_stat(struct task_struct *, char *); extern int proc_pid_status(struct task_struct *, char *); extern int proc_pid_statm(struct task_struct *, char *); +void free_proc_entry(struct proc_dir_entry *de); + +int proc_init_inodecache(void); + static inline struct task_struct *proc_task(struct inode *inode) { return PROC_I(inode)->task; diff --git a/fs/proc/root.c b/fs/proc/root.c index aef148f099a2..68896283c8ae 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -18,6 +18,8 @@ #include #include +#include "internal.h" + struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; #ifdef CONFIG_SYSCTL @@ -36,7 +38,6 @@ static struct file_system_type proc_fs_type = { .kill_sb = kill_anon_super, }; -extern int __init proc_init_inodecache(void); void __init proc_root_init(void) { int err = proc_init_inodecache(); -- cgit v1.2.3 From 44f061033360f9d4db7e9b29d64f9df3667cb41e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 8 Jan 2006 01:04:22 -0800 Subject: [PATCH] Sonypi: convert to the new platform device interface Do not use platform_device_register_simple() as it is going away, implement ->probe() and -remove() functions so manual binding and unbinding will work with this driver. Signed-off-by: Dmitry Torokhov Cc: Stelian Pop Cc: Mattia Dongili Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sonypi.c | 358 +++++++++++++++++++++++++++++--------------------- 1 file changed, 206 insertions(+), 152 deletions(-) diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 51a07370e636..6a9e23dc4897 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -471,7 +471,6 @@ struct sonypi_keypress { static struct sonypi_device { struct pci_dev *dev; - struct platform_device *pdev; u16 irq; u16 bits; u16 ioport1; @@ -1165,45 +1164,12 @@ static int sonypi_disable(void) return 0; } -#ifdef CONFIG_PM -static int old_camera_power; - -static int sonypi_suspend(struct platform_device *dev, pm_message_t state) -{ - old_camera_power = sonypi_device.camera_power; - sonypi_disable(); - - return 0; -} - -static int sonypi_resume(struct platform_device *dev) -{ - sonypi_enable(old_camera_power); - return 0; -} -#endif - -static void sonypi_shutdown(struct platform_device *dev) -{ - sonypi_disable(); -} - -static struct platform_driver sonypi_driver = { -#ifdef CONFIG_PM - .suspend = sonypi_suspend, - .resume = sonypi_resume, -#endif - .shutdown = sonypi_shutdown, - .driver = { - .name = "sonypi", - }, -}; - static int __devinit sonypi_create_input_devices(void) { struct input_dev *jog_dev; struct input_dev *key_dev; int i; + int error; sonypi_device.input_jog_dev = jog_dev = input_allocate_device(); if (!jog_dev) @@ -1219,9 +1185,8 @@ static int __devinit sonypi_create_input_devices(void) sonypi_device.input_key_dev = key_dev = input_allocate_device(); if (!key_dev) { - input_free_device(jog_dev); - sonypi_device.input_jog_dev = NULL; - return -ENOMEM; + error = -ENOMEM; + goto err_free_jogdev; } key_dev->name = "Sony Vaio Keys"; @@ -1234,56 +1199,122 @@ static int __devinit sonypi_create_input_devices(void) if (sonypi_inputkeys[i].inputev) set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); - input_register_device(jog_dev); - input_register_device(key_dev); + error = input_register_device(jog_dev); + if (error) + goto err_free_keydev; + + error = input_register_device(key_dev); + if (error) + goto err_unregister_jogdev; return 0; + + err_unregister_jogdev: + input_unregister_device(jog_dev); + /* Set to NULL so we don't free it again below */ + jog_dev = NULL; + err_free_keydev: + input_free_device(key_dev); + sonypi_device.input_key_dev = NULL; + err_free_jogdev: + input_free_device(jog_dev); + sonypi_device.input_jog_dev = NULL; + + return error; } -static int __devinit sonypi_probe(void) +static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, + const struct sonypi_ioport_list *ioport_list) { - int i, ret; - struct sonypi_ioport_list *ioport_list; - struct sonypi_irq_list *irq_list; - struct pci_dev *pcidev; + while (ioport_list->port1) { - if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) - sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; - else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) - sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; - else - sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; + if (request_region(ioport_list->port1, + sonypi_device.region_size, + "Sony Programable I/O Device")) { + dev->ioport1 = ioport_list->port1; + dev->ioport2 = ioport_list->port2; + return 0; + } + ioport_list++; + } - sonypi_device.dev = pcidev; + return -EBUSY; +} + +static int __devinit sonypi_setup_irq(struct sonypi_device *dev, + const struct sonypi_irq_list *irq_list) +{ + while (irq_list->irq) { + + if (!request_irq(irq_list->irq, sonypi_irq, + SA_SHIRQ, "sonypi", sonypi_irq)) { + dev->irq = irq_list->irq; + dev->bits = irq_list->bits; + return 0; + } + irq_list++; + } + + return -EBUSY; +} + +static void __devinit sonypi_display_info(void) +{ + printk(KERN_INFO "sonypi: detected type%d model, " + "verbose = %d, fnkeyinit = %s, camera = %s, " + "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", + sonypi_device.model, + verbose, + fnkeyinit ? "on" : "off", + camera ? "on" : "off", + compat ? "on" : "off", + mask, + useinput ? "on" : "off", + SONYPI_ACPI_ACTIVE ? "on" : "off"); + printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", + sonypi_device.irq, + sonypi_device.ioport1, sonypi_device.ioport2); + + if (minor == -1) + printk(KERN_INFO "sonypi: device allocated minor is %d\n", + sonypi_misc_device.minor); +} + +static int __devinit sonypi_probe(struct platform_device *dev) +{ + const struct sonypi_ioport_list *ioport_list; + const struct sonypi_irq_list *irq_list; + struct pci_dev *pcidev; + int error; spin_lock_init(&sonypi_device.fifo_lock); sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, &sonypi_device.fifo_lock); if (IS_ERR(sonypi_device.fifo)) { printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); - ret = PTR_ERR(sonypi_device.fifo); - goto out_fifo; + return PTR_ERR(sonypi_device.fifo); } init_waitqueue_head(&sonypi_device.fifo_proc_list); init_MUTEX(&sonypi_device.lock); sonypi_device.bluetooth_power = -1; + if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; + if (pcidev && pci_enable_device(pcidev)) { printk(KERN_ERR "sonypi: pci_enable_device failed\n"); - ret = -EIO; - goto out_pcienable; - } - - if (minor != -1) - sonypi_misc_device.minor = minor; - if ((ret = misc_register(&sonypi_misc_device))) { - printk(KERN_ERR "sonypi: misc_register failed\n"); - goto out_miscreg; + error = -EIO; + goto err_put_pcidev; } + sonypi_device.dev = pcidev; if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { ioport_list = sonypi_type1_ioport_list; @@ -1302,43 +1333,36 @@ static int __devinit sonypi_probe(void) irq_list = sonypi_type3_irq_list; } - for (i = 0; ioport_list[i].port1; i++) { - if (request_region(ioport_list[i].port1, - sonypi_device.region_size, - "Sony Programable I/O Device")) { - /* get the ioport */ - sonypi_device.ioport1 = ioport_list[i].port1; - sonypi_device.ioport2 = ioport_list[i].port2; - break; - } - } - if (!sonypi_device.ioport1) { - printk(KERN_ERR "sonypi: request_region failed\n"); - ret = -ENODEV; - goto out_reqreg; + error = sonypi_setup_ioports(&sonypi_device, ioport_list); + if (error) { + printk(KERN_ERR "sonypi: failed to request ioports\n"); + goto err_disable_pcidev; } - for (i = 0; irq_list[i].irq; i++) { - - sonypi_device.irq = irq_list[i].irq; - sonypi_device.bits = irq_list[i].bits; - - if (!request_irq(sonypi_device.irq, sonypi_irq, - SA_SHIRQ, "sonypi", sonypi_irq)) - break; + error = sonypi_setup_irq(&sonypi_device, irq_list); + if (error) { + printk(KERN_ERR "sonypi: request_irq failed\n"); + goto err_free_ioports; } - if (!irq_list[i].irq) { - printk(KERN_ERR "sonypi: request_irq failed\n"); - ret = -ENODEV; - goto out_reqirq; + if (minor != -1) + sonypi_misc_device.minor = minor; + error = misc_register(&sonypi_misc_device); + if (error) { + printk(KERN_ERR "sonypi: misc_register failed\n"); + goto err_free_irq; } + sonypi_display_info(); + if (useinput) { - ret = sonypi_create_input_devices(); - if (ret) - goto out_inputdevices; + error = sonypi_create_input_devices(); + if (error) { + printk(KERN_ERR + "sonypi: failed to create input devices\n"); + goto err_miscdev_unregister; + } spin_lock_init(&sonypi_device.input_fifo_lock); sonypi_device.input_fifo = @@ -1346,91 +1370,104 @@ static int __devinit sonypi_probe(void) &sonypi_device.input_fifo_lock); if (IS_ERR(sonypi_device.input_fifo)) { printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); - ret = PTR_ERR(sonypi_device.input_fifo); - goto out_infifo; + error = PTR_ERR(sonypi_device.input_fifo); + goto err_inpdev_unregister; } INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); } - sonypi_device.pdev = platform_device_register_simple("sonypi", -1, - NULL, 0); - if (IS_ERR(sonypi_device.pdev)) { - ret = PTR_ERR(sonypi_device.pdev); - goto out_platformdev; - } - sonypi_enable(0); - printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver" - "v%s.\n", SONYPI_DRIVER_VERSION); - printk(KERN_INFO "sonypi: detected type%d model, " - "verbose = %d, fnkeyinit = %s, camera = %s, " - "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", - sonypi_device.model, - verbose, - fnkeyinit ? "on" : "off", - camera ? "on" : "off", - compat ? "on" : "off", - mask, - useinput ? "on" : "off", - SONYPI_ACPI_ACTIVE ? "on" : "off"); - printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", - sonypi_device.irq, - sonypi_device.ioport1, sonypi_device.ioport2); - - if (minor == -1) - printk(KERN_INFO "sonypi: device allocated minor is %d\n", - sonypi_misc_device.minor); - return 0; -out_platformdev: - kfifo_free(sonypi_device.input_fifo); -out_infifo: + err_inpdev_unregister: input_unregister_device(sonypi_device.input_key_dev); input_unregister_device(sonypi_device.input_jog_dev); -out_inputdevices: + err_miscdev_unregister: + misc_deregister(&sonypi_misc_device); + err_free_irq: free_irq(sonypi_device.irq, sonypi_irq); -out_reqirq: + err_free_ioports: release_region(sonypi_device.ioport1, sonypi_device.region_size); -out_reqreg: - misc_deregister(&sonypi_misc_device); -out_miscreg: + err_disable_pcidev: if (pcidev) pci_disable_device(pcidev); -out_pcienable: + err_put_pcidev: + pci_dev_put(pcidev); kfifo_free(sonypi_device.fifo); -out_fifo: - pci_dev_put(sonypi_device.dev); - return ret; + + return error; } -static void __devexit sonypi_remove(void) +static int __devexit sonypi_remove(struct platform_device *dev) { sonypi_disable(); synchronize_sched(); /* Allow sonypi interrupt to complete. */ flush_scheduled_work(); - platform_device_unregister(sonypi_device.pdev); - if (useinput) { input_unregister_device(sonypi_device.input_key_dev); input_unregister_device(sonypi_device.input_jog_dev); kfifo_free(sonypi_device.input_fifo); } + misc_deregister(&sonypi_misc_device); + free_irq(sonypi_device.irq, sonypi_irq); release_region(sonypi_device.ioport1, sonypi_device.region_size); - misc_deregister(&sonypi_misc_device); - if (sonypi_device.dev) + + if (sonypi_device.dev) { pci_disable_device(sonypi_device.dev); + pci_dev_put(sonypi_device.dev); + } + kfifo_free(sonypi_device.fifo); - pci_dev_put(sonypi_device.dev); - printk(KERN_INFO "sonypi: removed.\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int old_camera_power; + +static int sonypi_suspend(struct platform_device *dev, pm_message_t state) +{ + old_camera_power = sonypi_device.camera_power; + sonypi_disable(); + + return 0; +} + +static int sonypi_resume(struct platform_device *dev) +{ + sonypi_enable(old_camera_power); + return 0; +} +#else +#define sonypi_suspend NULL +#define sonypi_resume NULL +#endif + +static void sonypi_shutdown(struct platform_device *dev) +{ + sonypi_disable(); } +static struct platform_driver sonypi_driver = { + .driver = { + .name = "sonypi", + .owner = THIS_MODULE, + }, + .probe = sonypi_probe, + .remove = __devexit_p(sonypi_remove), + .shutdown = sonypi_shutdown, + .suspend = sonypi_suspend, + .resume = sonypi_resume, +}; + +static struct platform_device *sonypi_platform_device; + static struct dmi_system_id __initdata sonypi_dmi_table[] = { { .ident = "Sony Vaio", @@ -1451,26 +1488,43 @@ static struct dmi_system_id __initdata sonypi_dmi_table[] = { static int __init sonypi_init(void) { - int ret; + int error; + + printk(KERN_INFO + "sonypi: Sony Programmable I/O Controller Driver v%s.\n", + SONYPI_DRIVER_VERSION); if (!dmi_check_system(sonypi_dmi_table)) return -ENODEV; - ret = platform_driver_register(&sonypi_driver); - if (ret) - return ret; + error = platform_driver_register(&sonypi_driver); + if (error) + return error; - ret = sonypi_probe(); - if (ret) - platform_driver_unregister(&sonypi_driver); + sonypi_platform_device = platform_device_alloc("sonypi", -1); + if (!sonypi_platform_device) { + error = -ENOMEM; + goto err_driver_unregister; + } - return ret; + error = platform_device_add(sonypi_platform_device); + if (error) + goto err_free_device; + + return 0; + + err_free_device: + platform_device_put(sonypi_platform_device); + err_driver_unregister: + platform_driver_unregister(&sonypi_driver); + return error; } static void __exit sonypi_exit(void) { + platform_device_unregister(sonypi_platform_device); platform_driver_unregister(&sonypi_driver); - sonypi_remove(); + printk(KERN_INFO "sonypi: removed.\n"); } module_init(sonypi_init); -- cgit v1.2.3 From b368fae6abaa1736b8f26128c32947d47237b8e5 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Sun, 8 Jan 2006 01:04:24 -0800 Subject: [PATCH] sonypi: Enable ACPI events for Sony laptop hotkeys Signed-off-by: Ben Collins Cc: "Brown, Len" Cc: linux-acpi@vger.kernel.org Cc: Stelian Pop Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sonypi.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 6a9e23dc4897..f8dd8527c6aa 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -510,6 +510,11 @@ static struct sonypi_device { #define SONYPI_ACPI_ACTIVE 0 #endif /* CONFIG_ACPI */ +#ifdef CONFIG_ACPI +static struct acpi_device *sonypi_acpi_device; +static int acpi_enabled; +#endif + static int sonypi_ec_write(u8 addr, u8 value) { #ifdef CONFIG_ACPI_EC @@ -863,6 +868,11 @@ found: if (useinput) sonypi_report_input_event(event); +#ifdef CONFIG_ACPI + if (acpi_enabled) + acpi_bus_generate_event(sonypi_acpi_device, 1, event); +#endif + kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); wake_up_interruptible(&sonypi_device.fifo_proc_list); @@ -1164,6 +1174,32 @@ static int sonypi_disable(void) return 0; } +#ifdef CONFIG_ACPI +static int sonypi_acpi_add(struct acpi_device *device) +{ + sonypi_acpi_device = device; + strcpy(acpi_device_name(device), "Sony laptop hotkeys"); + strcpy(acpi_device_class(device), "sony/hotkey"); + return 0; +} + +static int sonypi_acpi_remove(struct acpi_device *device, int type) +{ + sonypi_acpi_device = NULL; + return 0; +} + +static struct acpi_driver sonypi_acpi_driver = { + .name = "sonypi", + .class = "hkey", + .ids = "SNY6001", + .ops = { + .add = sonypi_acpi_add, + .remove = sonypi_acpi_remove, + }, +}; +#endif + static int __devinit sonypi_create_input_devices(void) { struct input_dev *jog_dev; @@ -1511,6 +1547,11 @@ static int __init sonypi_init(void) if (error) goto err_free_device; +#ifdef CONFIG_ACPI + if (acpi_bus_register_driver(&sonypi_acpi_driver) > 0) + acpi_enabled = 1; +#endif + return 0; err_free_device: @@ -1522,6 +1563,10 @@ static int __init sonypi_init(void) static void __exit sonypi_exit(void) { +#ifdef CONFIG_ACPI + if (acpi_enabled) + acpi_bus_unregister_driver(&sonypi_acpi_driver); +#endif platform_device_unregister(sonypi_platform_device); platform_driver_unregister(&sonypi_driver); printk(KERN_INFO "sonypi: removed.\n"); -- cgit v1.2.3 From eea8b54dc0dceb740da697a89c54d20dde340306 Mon Sep 17 00:00:00 2001 From: Ashutosh Naik Date: Sun, 8 Jan 2006 01:04:25 -0800 Subject: [PATCH] modules: prevent overriding of symbols Ensure that an exported symbol does not already exist in the kernel or in some other module's exported symbol table. This is done by checking the symbol tables for the exported symbol at the time of loading the module. Currently this is done after the relocation of the symbol. Signed-off-by: Ashutosh Naik Signed-off-by: Anand Krishnan Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/module.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/kernel/module.c b/kernel/module.c index 5d9078d6f0fa..fb6f091f5940 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1204,6 +1204,39 @@ void *__symbol_get(const char *symbol) } EXPORT_SYMBOL_GPL(__symbol_get); +/* + * Ensure that an exported symbol [global namespace] does not already exist + * in the Kernel or in some other modules exported symbol table. + */ +static int verify_export_symbols(struct module *mod) +{ + const char *name = NULL; + unsigned long i, ret = 0; + struct module *owner; + const unsigned long *crc; + + for (i = 0; i < mod->num_syms; i++) + if (__find_symbol(mod->syms[i].name, &owner, &crc, 1)) { + name = mod->syms[i].name; + ret = -ENOEXEC; + goto dup; + } + + for (i = 0; i < mod->num_gpl_syms; i++) + if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) { + name = mod->gpl_syms[i].name; + ret = -ENOEXEC; + goto dup; + } + +dup: + if (ret) + printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n", + mod->name, name, module_name(owner)); + + return ret; +} + /* Change all symbols so that sh_value encodes the pointer directly. */ static int simplify_symbols(Elf_Shdr *sechdrs, unsigned int symindex, @@ -1772,6 +1805,12 @@ static struct module *load_module(void __user *umod, goto cleanup; } + /* Find duplicate symbols */ + err = verify_export_symbols(mod); + + if (err < 0) + goto cleanup; + /* Set up and sort exception table */ mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); mod->extable = extable = (void *)sechdrs[exindex].sh_addr; -- cgit v1.2.3 From fb1697933a03ec47d794b38e2a4e3ccc2463fd22 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 8 Jan 2006 01:04:29 -0800 Subject: [PATCH] modules: mark TAINT_FORCED_RMMOD correctly Currently TAINT_FORCED_RMMOD is totally unused. Because it is marked as TAINT_FORCED_MODULE instead when user forced a module unload. This patch marks it correctly Signed-off-by: Akinobu Mita Cc: Rusty Russell Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/module.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index fb6f091f5940..f368812ac0e8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -496,15 +496,15 @@ static void module_unload_free(struct module *mod) } #ifdef CONFIG_MODULE_FORCE_UNLOAD -static inline int try_force(unsigned int flags) +static inline int try_force_unload(unsigned int flags) { int ret = (flags & O_TRUNC); if (ret) - add_taint(TAINT_FORCED_MODULE); + add_taint(TAINT_FORCED_RMMOD); return ret; } #else -static inline int try_force(unsigned int flags) +static inline int try_force_unload(unsigned int flags) { return 0; } @@ -524,7 +524,7 @@ static int __try_stop_module(void *_sref) /* If it's not unused, quit unless we are told to block. */ if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) { - if (!(*sref->forced = try_force(sref->flags))) + if (!(*sref->forced = try_force_unload(sref->flags))) return -EWOULDBLOCK; } @@ -609,7 +609,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags) /* If it has an init func, it must have an exit func to unload */ if ((mod->init != NULL && mod->exit == NULL) || mod->unsafe) { - forced = try_force(flags); + forced = try_force_unload(flags); if (!forced) { /* This module can't be removed */ ret = -EBUSY; -- cgit v1.2.3 From 59d9136b9844d3a0376d93c945ab280decedb323 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Sun, 8 Jan 2006 01:04:34 -0800 Subject: [PATCH] aio: reorder kiocb structure elements to make sync iocb setup faster Reorder members of the kiocb structure to make sync kiocb setup faster. By setting the elements sequentially, the write combining buffers on the CPU are able to combine the writes into a single burst, which results in fewer cache cycles being consumed, freeing them up for other code. This results in a 10-20KB/s[*] increase on the bw_unix part of LMbench on my test system. * The improvement varies based on what other patches are in the system, as there are a number of bottlenecks, so this number is not absolutely accurate. Signed-off-by: Benjamin LaHaise Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/aio.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/aio.h b/include/linux/aio.h index 49fd37629ee4..00c8efa95cc3 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -94,26 +94,27 @@ struct kiocb { ssize_t (*ki_retry)(struct kiocb *); void (*ki_dtor)(struct kiocb *); - struct list_head ki_list; /* the aio core uses this - * for cancellation */ - union { void __user *user; struct task_struct *tsk; } ki_obj; + __u64 ki_user_data; /* user's data for completion */ + wait_queue_t ki_wait; loff_t ki_pos; + + void *private; /* State that we remember to be able to restart/retry */ unsigned short ki_opcode; size_t ki_nbytes; /* copy of iocb->aio_nbytes */ char __user *ki_buf; /* remaining iocb->aio_buf */ size_t ki_left; /* remaining bytes */ - wait_queue_t ki_wait; long ki_retried; /* just for testing */ long ki_kicked; /* just for testing */ long ki_queued; /* just for testing */ - void *private; + struct list_head ki_list; /* the aio core uses this + * for cancellation */ }; #define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY) @@ -126,6 +127,7 @@ struct kiocb { (x)->ki_filp = (filp); \ (x)->ki_ctx = NULL; \ (x)->ki_cancel = NULL; \ + (x)->ki_retry = NULL; \ (x)->ki_dtor = NULL; \ (x)->ki_obj.tsk = tsk; \ (x)->ki_user_data = 0; \ -- cgit v1.2.3 From 349aef0bc4c7f07d685c977e12d0e2d0b5d0e6db Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:04:36 -0800 Subject: [PATCH] shrink struct page Reduce the size of the pageframe for NR_CPUS>4, CONFIG_PREEMPT back to the minimal size by unionising both ->private and ->mapping with the pagetable lock. It uses an anonymous struct and hence requires gcc-3.x. Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 7ff54242c5d7..df80e63903b5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -223,24 +223,27 @@ struct page { * & limit reverse map searches. */ union { - unsigned long private; /* Mapping-private opaque data: - * usually used for buffer_heads - * if PagePrivate set; used for - * swp_entry_t if PageSwapCache - * When page is free, this indicates - * order in the buddy system. - */ + struct { + unsigned long private; /* Mapping-private opaque data: + * usually used for buffer_heads + * if PagePrivate set; used for + * swp_entry_t if PageSwapCache. + * When page is free, this + * indicates order in the buddy + * system. + */ + struct address_space *mapping; /* If low bit clear, points to + * inode address_space, or NULL. + * If page mapped as anonymous + * memory, low bit is set, and + * it points to anon_vma object: + * see PAGE_MAPPING_ANON below. + */ + }; #if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS - spinlock_t ptl; + spinlock_t ptl; #endif - } u; - struct address_space *mapping; /* If low bit clear, points to - * inode address_space, or NULL. - * If page mapped as anonymous - * memory, low bit is set, and - * it points to anon_vma object: - * see PAGE_MAPPING_ANON below. - */ + }; pgoff_t index; /* Our offset within mapping. */ struct list_head lru; /* Pageout list, eg. active_list * protected by zone->lru_lock ! @@ -261,8 +264,8 @@ struct page { #endif /* WANT_PAGE_VIRTUAL */ }; -#define page_private(page) ((page)->u.private) -#define set_page_private(page, v) ((page)->u.private = (v)) +#define page_private(page) ((page)->private) +#define set_page_private(page, v) ((page)->private = (v)) /* * FIXME: take this include out, include page-flags.h in @@ -815,7 +818,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a * overflow into the next struct page (as it might with DEBUG_SPINLOCK). * When freeing, reset page->mapping so free_pages_check won't complain. */ -#define __pte_lockptr(page) &((page)->u.ptl) +#define __pte_lockptr(page) &((page)->ptl) #define pte_lock_init(_page) do { \ spin_lock_init(__pte_lockptr(_page)); \ } while (0) -- cgit v1.2.3 From eb46996f90a0826921f1a0d81535537a9c7f91b0 Mon Sep 17 00:00:00 2001 From: Ashutosh Naik Date: Sun, 8 Jan 2006 01:04:37 -0800 Subject: [PATCH] kernel/module.c: remove redundant spinlock in resolve_symbol() Remove the redundant spinlock in the function resolve_symbol() as we are not altering the module list, and we already hold the semaphore. Signed-off-by: Ashutosh Naik Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/module.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index f368812ac0e8..e4276046a1b6 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -958,7 +958,6 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, unsigned long ret; const unsigned long *crc; - spin_lock_irq(&modlist_lock); ret = __find_symbol(name, &owner, &crc, mod->license_gplok); if (ret) { /* use_module can fail due to OOM, or module unloading */ @@ -966,7 +965,6 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, !use_module(mod, owner)) ret = 0; } - spin_unlock_irq(&modlist_lock); return ret; } -- cgit v1.2.3 From a12dea7af93ae83bd868c0dc09367090ead7cc1e Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sun, 8 Jan 2006 01:04:49 -0800 Subject: [PATCH] PTRACE_SYSEMU is only for i386 and clashes with other ptrace codes of other archs PTRACE_SYSEMU{,_SINGLESTEP} is actually arch specific, for now, and the current allocated number clashes with a ptrace code of frv, i.e. PTRACE_GETFDPIC. I should have submitted this much earlier, anyway we get no breakage for this. CC: Daniel Jacobowitz Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-i386/ptrace.h | 3 +++ include/linux/ptrace.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h index 7e0f2945d17d..f324c53b6f9a 100644 --- a/include/asm-i386/ptrace.h +++ b/include/asm-i386/ptrace.h @@ -54,6 +54,9 @@ struct pt_regs { #define PTRACE_GET_THREAD_AREA 25 #define PTRACE_SET_THREAD_AREA 26 +#define PTRACE_SYSEMU 31 +#define PTRACE_SYSEMU_SINGLESTEP 32 + #ifdef __KERNEL__ #include diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 864791996b5f..9d5cd106b344 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -20,8 +20,6 @@ #define PTRACE_DETACH 0x11 #define PTRACE_SYSCALL 24 -#define PTRACE_SYSEMU 31 -#define PTRACE_SYSEMU_SINGLESTEP 32 /* 0x4200-0x4300 are reserved for architecture-independent additions. */ #define PTRACE_SETOPTIONS 0x4200 -- cgit v1.2.3 From ac34dd052400b1e63aa8e711a13c0670943296fd Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sun, 8 Jan 2006 01:04:50 -0800 Subject: [PATCH] fs/smbfs/proc.c: fix data corruption in smb_proc_setattr_unix() This patch fixes a data corruption in smb_proc_setattr_unix() (smb_filetype_from_mode() returns an u32, and there are only four bytes reserved for it in data. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/smbfs/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 38ab558835c4..d6baec0f24ad 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -3113,7 +3113,7 @@ smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, LSET(data, 32, SMB_TIME_NO_CHANGE); LSET(data, 40, SMB_UID_NO_CHANGE); LSET(data, 48, SMB_GID_NO_CHANGE); - LSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); + DSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); LSET(data, 60, major); LSET(data, 68, minor); LSET(data, 76, 0); -- cgit v1.2.3 From 15b2fe3931831891a62bad9cafd403c169ae087c Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Sun, 8 Jan 2006 01:04:51 -0800 Subject: [PATCH] UFS: inode->i_sem is not released in error path Signed-off-by: Evgeniy Polyakov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ufs/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 54828ebcf1ba..2ba11a9aa995 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1296,8 +1296,10 @@ static ssize_t ufs_quota_write(struct super_block *sb, int type, blk++; } out: - if (len == towrite) + if (len == towrite) { + up(&inode->i_sem); return err; + } if (inode->i_size < off+len-towrite) i_size_write(inode, off+len-towrite); inode->i_version++; -- cgit v1.2.3 From 58591e8a1f4de2e53fdd09b2aa86948687106c07 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 8 Jan 2006 01:04:52 -0800 Subject: [PATCH] SubmittingPatches: diffstat options Add desired 'diffstat' options to use for kernel patches. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/SubmittingPatches | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 3c12fc146940..6198e5ebcf65 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -386,6 +386,9 @@ a diffstat, to show what files have changed, and the number of inserted and deleted lines per file. A diffstat is especially useful on bigger patches. Other comments relevant only to the moment or the maintainer, not suitable for the permanent changelog, should also go here. +Use diffstat options "-p 1 -w 70" so that filenames are listed from the +top of the kernel source tree and don't use too much horizontal space +(easily fit in 80 columns, maybe with some indentation). See more details on the proper patch format in the following references. -- cgit v1.2.3 From 389cd6ec086e9b5421fe479d14d20a1faf74848d Mon Sep 17 00:00:00 2001 From: Eugene Surovegin Date: Sun, 8 Jan 2006 01:04:53 -0800 Subject: [PATCH] CREDITS update: Eugene Surovegin Add EMAC to my CREDITS entry. Signed-off-by: Eugene Surovegin Signed-off-by: Linus Torvalds --- CREDITS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CREDITS b/CREDITS index 521f00d1b549..8e577ce4abeb 100644 --- a/CREDITS +++ b/CREDITS @@ -3203,7 +3203,7 @@ N: Eugene Surovegin E: ebs@ebshome.net W: http://kernel.ebshome.net/ P: 1024D/AE5467F1 FF22 39F1 6728 89F6 6E6C 2365 7602 F33D AE54 67F1 -D: Embedded PowerPC 4xx: I2C, PIC and random hacks/fixes +D: Embedded PowerPC 4xx: EMAC, I2C, PIC and random hacks/fixes S: Sunnyvale, California 94085 S: USA -- cgit v1.2.3 From 7e7f358c8f8f836c504faa293fda0c1c0733b63c Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Sun, 8 Jan 2006 01:04:54 -0800 Subject: [PATCH] Split out screen_info from tty.h This makes it possible for boot code to use screen_info without dragging in all of tty.h. Signed-off-by: Brian Gerst Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/boot/compressed/misc.c | 2 +- arch/x86_64/boot/compressed/misc.c | 2 +- arch/x86_64/boot/compressed/miscsetup.h | 39 ----------------- include/linux/screen_info.h | 77 +++++++++++++++++++++++++++++++++ include/linux/tty.h | 72 +----------------------------- 5 files changed, 80 insertions(+), 112 deletions(-) delete mode 100644 arch/x86_64/boot/compressed/miscsetup.h create mode 100644 include/linux/screen_info.h diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c index 82a807f9f5e6..f19f3a7492a5 100644 --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index 0e10fd84c7cc..cf4b88c416dc 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c @@ -9,7 +9,7 @@ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ -#include "miscsetup.h" +#include #include #include diff --git a/arch/x86_64/boot/compressed/miscsetup.h b/arch/x86_64/boot/compressed/miscsetup.h deleted file mode 100644 index bb1620531703..000000000000 --- a/arch/x86_64/boot/compressed/miscsetup.h +++ /dev/null @@ -1,39 +0,0 @@ -#define NULL 0 -//typedef unsigned int size_t; - - -struct screen_info { - unsigned char orig_x; /* 0x00 */ - unsigned char orig_y; /* 0x01 */ - unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */ - unsigned short orig_video_page; /* 0x04 */ - unsigned char orig_video_mode; /* 0x06 */ - unsigned char orig_video_cols; /* 0x07 */ - unsigned short unused2; /* 0x08 */ - unsigned short orig_video_ega_bx; /* 0x0a */ - unsigned short unused3; /* 0x0c */ - unsigned char orig_video_lines; /* 0x0e */ - unsigned char orig_video_isVGA; /* 0x0f */ - unsigned short orig_video_points; /* 0x10 */ - - /* VESA graphic mode -- linear frame buffer */ - unsigned short lfb_width; /* 0x12 */ - unsigned short lfb_height; /* 0x14 */ - unsigned short lfb_depth; /* 0x16 */ - unsigned long lfb_base; /* 0x18 */ - unsigned long lfb_size; /* 0x1c */ - unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */ - unsigned short lfb_linelength; /* 0x24 */ - unsigned char red_size; /* 0x26 */ - unsigned char red_pos; /* 0x27 */ - unsigned char green_size; /* 0x28 */ - unsigned char green_pos; /* 0x29 */ - unsigned char blue_size; /* 0x2a */ - unsigned char blue_pos; /* 0x2b */ - unsigned char rsvd_size; /* 0x2c */ - unsigned char rsvd_pos; /* 0x2d */ - unsigned short vesapm_seg; /* 0x2e */ - unsigned short vesapm_off; /* 0x30 */ - unsigned short pages; /* 0x32 */ - /* 0x34 -- 0x3f reserved for future expansion */ -}; diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h new file mode 100644 index 000000000000..76850b75b3f6 --- /dev/null +++ b/include/linux/screen_info.h @@ -0,0 +1,77 @@ +#ifndef _SCREEN_INFO_H +#define _SCREEN_INFO_H + +#include + +/* + * These are set up by the setup-routine at boot-time: + */ + +struct screen_info { + u8 orig_x; /* 0x00 */ + u8 orig_y; /* 0x01 */ + u16 dontuse1; /* 0x02 -- EXT_MEM_K sits here */ + u16 orig_video_page; /* 0x04 */ + u8 orig_video_mode; /* 0x06 */ + u8 orig_video_cols; /* 0x07 */ + u16 unused2; /* 0x08 */ + u16 orig_video_ega_bx; /* 0x0a */ + u16 unused3; /* 0x0c */ + u8 orig_video_lines; /* 0x0e */ + u8 orig_video_isVGA; /* 0x0f */ + u16 orig_video_points; /* 0x10 */ + + /* VESA graphic mode -- linear frame buffer */ + u16 lfb_width; /* 0x12 */ + u16 lfb_height; /* 0x14 */ + u16 lfb_depth; /* 0x16 */ + u32 lfb_base; /* 0x18 */ + u32 lfb_size; /* 0x1c */ + u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */ + u16 lfb_linelength; /* 0x24 */ + u8 red_size; /* 0x26 */ + u8 red_pos; /* 0x27 */ + u8 green_size; /* 0x28 */ + u8 green_pos; /* 0x29 */ + u8 blue_size; /* 0x2a */ + u8 blue_pos; /* 0x2b */ + u8 rsvd_size; /* 0x2c */ + u8 rsvd_pos; /* 0x2d */ + u16 vesapm_seg; /* 0x2e */ + u16 vesapm_off; /* 0x30 */ + u16 pages; /* 0x32 */ + u16 vesa_attributes; /* 0x34 */ + u32 capabilities; /* 0x36 */ + /* 0x3a -- 0x3f reserved for future expansion */ +}; + +extern struct screen_info screen_info; + +#define ORIG_X (screen_info.orig_x) +#define ORIG_Y (screen_info.orig_y) +#define ORIG_VIDEO_MODE (screen_info.orig_video_mode) +#define ORIG_VIDEO_COLS (screen_info.orig_video_cols) +#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx) +#define ORIG_VIDEO_LINES (screen_info.orig_video_lines) +#define ORIG_VIDEO_ISVGA (screen_info.orig_video_isVGA) +#define ORIG_VIDEO_POINTS (screen_info.orig_video_points) + +#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ +#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ +#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */ +#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */ +#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */ + +#define VIDEO_TYPE_PICA_S3 0x30 /* ACER PICA-61 local S3 video */ +#define VIDEO_TYPE_MIPS_G364 0x31 /* MIPS Magnum 4000 G364 video */ +#define VIDEO_TYPE_SGI 0x33 /* Various SGI graphics hardware */ + +#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */ + +#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */ +#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */ + +#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */ + +#endif /* _SCREEN_INFO_H */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 1267f88ece6e..57449704a47b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -36,77 +37,6 @@ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ #define NR_LDISCS 16 -/* - * These are set up by the setup-routine at boot-time: - */ - -struct screen_info { - u8 orig_x; /* 0x00 */ - u8 orig_y; /* 0x01 */ - u16 dontuse1; /* 0x02 -- EXT_MEM_K sits here */ - u16 orig_video_page; /* 0x04 */ - u8 orig_video_mode; /* 0x06 */ - u8 orig_video_cols; /* 0x07 */ - u16 unused2; /* 0x08 */ - u16 orig_video_ega_bx; /* 0x0a */ - u16 unused3; /* 0x0c */ - u8 orig_video_lines; /* 0x0e */ - u8 orig_video_isVGA; /* 0x0f */ - u16 orig_video_points; /* 0x10 */ - - /* VESA graphic mode -- linear frame buffer */ - u16 lfb_width; /* 0x12 */ - u16 lfb_height; /* 0x14 */ - u16 lfb_depth; /* 0x16 */ - u32 lfb_base; /* 0x18 */ - u32 lfb_size; /* 0x1c */ - u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */ - u16 lfb_linelength; /* 0x24 */ - u8 red_size; /* 0x26 */ - u8 red_pos; /* 0x27 */ - u8 green_size; /* 0x28 */ - u8 green_pos; /* 0x29 */ - u8 blue_size; /* 0x2a */ - u8 blue_pos; /* 0x2b */ - u8 rsvd_size; /* 0x2c */ - u8 rsvd_pos; /* 0x2d */ - u16 vesapm_seg; /* 0x2e */ - u16 vesapm_off; /* 0x30 */ - u16 pages; /* 0x32 */ - u16 vesa_attributes; /* 0x34 */ - u32 capabilities; /* 0x36 */ - /* 0x3a -- 0x3f reserved for future expansion */ -}; - -extern struct screen_info screen_info; - -#define ORIG_X (screen_info.orig_x) -#define ORIG_Y (screen_info.orig_y) -#define ORIG_VIDEO_MODE (screen_info.orig_video_mode) -#define ORIG_VIDEO_COLS (screen_info.orig_video_cols) -#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx) -#define ORIG_VIDEO_LINES (screen_info.orig_video_lines) -#define ORIG_VIDEO_ISVGA (screen_info.orig_video_isVGA) -#define ORIG_VIDEO_POINTS (screen_info.orig_video_points) - -#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ -#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ -#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ -#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */ -#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */ -#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */ - -#define VIDEO_TYPE_PICA_S3 0x30 /* ACER PICA-61 local S3 video */ -#define VIDEO_TYPE_MIPS_G364 0x31 /* MIPS Magnum 4000 G364 video */ -#define VIDEO_TYPE_SGI 0x33 /* Various SGI graphics hardware */ - -#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */ - -#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */ -#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */ - -#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */ - /* * This character is the same as _POSIX_VDISABLE: it cannot be used as * a c_cc[] character, but indicates that a particular special character -- cgit v1.2.3 From f5ef3c105bee3a52486d7b55cef3330fcde9bca6 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Sun, 8 Jan 2006 01:04:56 -0800 Subject: [PATCH] v9fs: fix fd_close If a 9pfs server crashes, v9fs_fd_close() is called. Subsequently, in cleaning up by performing a umount() on the FS that was provided by this server v9fs_fd_close() is called again, and uses the old, freed valus of trans->priv. This patch ensures that trans->priv can be freed only once, otherwise this function bails early. Signed-off-by: Michal Ostrowski Signed-off-by: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/trans_fd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c index 63b58ce98ff4..b7ffb9859588 100644 --- a/fs/9p/trans_fd.c +++ b/fs/9p/trans_fd.c @@ -148,12 +148,12 @@ static void v9fs_fd_close(struct v9fs_transport *trans) if (!trans) return; - trans->status = Disconnected; - ts = trans->priv; + ts = xchg(&trans->priv, NULL); if (!ts) return; + trans->status = Disconnected; if (ts->in_file) fput(ts->in_file); -- cgit v1.2.3 From 3cf6429a26da5c4d7b795e6d0f8f56ed2e4fdfc0 Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Sun, 8 Jan 2006 01:04:58 -0800 Subject: [PATCH] v9fs: new multiplexer implementation New multiplexer implementation. Decreases the number of kernel threads required. Better handling when the user process receives a signal. Signed-off-by: Latchesar Ionkov Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/9p.c | 68 +++- fs/9p/9p.h | 9 +- fs/9p/conv.c | 86 ++-- fs/9p/conv.h | 13 +- fs/9p/fid.c | 2 +- fs/9p/mux.c | 1122 +++++++++++++++++++++++++++++++++++++--------------- fs/9p/mux.h | 40 +- fs/9p/trans_fd.c | 49 ++- fs/9p/trans_sock.c | 161 +++++--- fs/9p/transport.h | 4 +- fs/9p/v9fs.c | 41 +- fs/9p/v9fs.h | 17 +- fs/9p/vfs_dentry.c | 13 +- fs/9p/vfs_dir.c | 17 +- fs/9p/vfs_inode.c | 89 ++--- fs/9p/vfs_super.c | 3 +- 16 files changed, 1172 insertions(+), 562 deletions(-) diff --git a/fs/9p/9p.c b/fs/9p/9p.c index e847f504a47c..a3a1ac610723 100644 --- a/fs/9p/9p.c +++ b/fs/9p/9p.c @@ -52,10 +52,11 @@ v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version); msg.id = TVERSION; + msg.tag = ~0; msg.params.tversion.msize = msize; msg.params.tversion.version = version; - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); } /** @@ -83,7 +84,30 @@ v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, msg.params.tattach.uname = uname; msg.params.tattach.aname = aname; - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); +} + +static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, + struct v9fs_fcall *rc, int err) +{ + int fid; + struct v9fs_session_info *v9ses; + + if (err) + return; + + fid = tc->params.tclunk.fid; + kfree(tc); + + if (!rc) + return; + + dprintk(DEBUG_9P, "tcall id %d rcall id %d\n", tc->id, rc->id); + v9ses = a; + if (rc->id == RCLUNK) + v9fs_put_idpool(fid, &v9ses->fidpool); + + kfree(rc); } /** @@ -93,18 +117,24 @@ v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, * @fcall: pointer to response fcall pointer * */ - int -v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid, - struct v9fs_fcall **fcall) +v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid) { - struct v9fs_fcall msg; + int err; + struct v9fs_fcall *tc, *rc; + + tc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL); dprintk(DEBUG_9P, "fid %d\n", fid); - msg.id = TCLUNK; - msg.params.tclunk.fid = fid; + tc->id = TCLUNK; + tc->params.tclunk.fid = fid; - return v9fs_mux_rpc(v9ses, &msg, fcall); + err = v9fs_mux_rpc(v9ses->mux, tc, &rc); + if (err >= 0) { + v9fs_t_clunk_cb(v9ses, tc, rc, 0); + } + + return err; } /** @@ -121,7 +151,7 @@ int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag) dprintk(DEBUG_9P, "oldtag %d\n", tag); msg.id = TFLUSH; msg.params.tflush.oldtag = tag; - return v9fs_mux_rpc(v9ses, &msg, NULL); + return v9fs_mux_rpc(v9ses->mux, &msg, NULL); } /** @@ -143,7 +173,7 @@ v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall) msg.id = TSTAT; msg.params.tstat.fid = fid; - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); } /** @@ -166,7 +196,7 @@ v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, msg.params.twstat.fid = fid; msg.params.twstat.stat = stat; - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); } /** @@ -199,7 +229,7 @@ v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, msg.params.twalk.nwname = 0; } - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); } /** @@ -217,14 +247,14 @@ v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, struct v9fs_fcall **fcall) { struct v9fs_fcall msg; - long errorno = -1; + int errorno = -1; dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode); msg.id = TOPEN; msg.params.topen.fid = fid; msg.params.topen.mode = mode; - errorno = v9fs_mux_rpc(v9ses, &msg, fcall); + errorno = v9fs_mux_rpc(v9ses->mux, &msg, fcall); return errorno; } @@ -246,7 +276,7 @@ v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, dprintk(DEBUG_9P, "fid %d\n", fid); msg.id = TREMOVE; msg.params.tremove.fid = fid; - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); } /** @@ -275,7 +305,7 @@ v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, msg.params.tcreate.perm = perm; msg.params.tcreate.mode = mode; - return v9fs_mux_rpc(v9ses, &msg, fcall); + return v9fs_mux_rpc(v9ses->mux, &msg, fcall); } /** @@ -302,7 +332,7 @@ v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, msg.params.tread.fid = fid; msg.params.tread.offset = offset; msg.params.tread.count = count; - errorno = v9fs_mux_rpc(v9ses, &msg, &rc); + errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc); if (!errorno) { errorno = rc->params.rread.count; @@ -345,7 +375,7 @@ v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, msg.params.twrite.count = count; msg.params.twrite.data = data; - errorno = v9fs_mux_rpc(v9ses, &msg, &rc); + errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc); if (!errorno) errorno = rc->params.rwrite.count; diff --git a/fs/9p/9p.h b/fs/9p/9p.h index f55424216be2..6355392786e2 100644 --- a/fs/9p/9p.h +++ b/fs/9p/9p.h @@ -100,6 +100,9 @@ enum { V9FS_QTFILE = 0x00, }; +#define V9FS_NOTAG (u16)(~0) +#define V9FS_NOFID (u32)(~0) + /* ample room for Twrite/Rread header (iounit) */ #define V9FS_IOHDRSZ 24 @@ -303,6 +306,9 @@ struct v9fs_fcall { } params; }; +#define V9FS_FCALLHDRSZ (sizeof(struct v9fs_fcall) + \ + sizeof(struct v9fs_stat) + 16*sizeof(struct v9fs_qid) + 16) + #define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "") int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, @@ -311,8 +317,7 @@ int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, u32 fid, u32 afid, struct v9fs_fcall **rcall); -int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid, - struct v9fs_fcall **rcall); +int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid); int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag); diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 18121af99d3e..1b9b15dfeaf0 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -208,7 +208,7 @@ static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) len = buf_get_int16(buf); if (!buf_check_overflow(buf) && buf_check_size(buf, len) && - buf_check_size(sbuf, len+1)) { + buf_check_size(sbuf, len + 1)) { memcpy(sbuf->p, buf->p, len); sbuf->p[len] = 0; @@ -252,13 +252,12 @@ static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, /** * v9fs_size_stat - calculate the size of a variable length stat struct - * @v9ses: session information * @stat: metadata (stat) structure + * @extended: non-zero if 9P2000.u * */ -static int v9fs_size_stat(struct v9fs_session_info *v9ses, - struct v9fs_stat *stat) +static int v9fs_size_stat(struct v9fs_stat *stat, int extended) { int size = 0; @@ -288,7 +287,7 @@ static int v9fs_size_stat(struct v9fs_session_info *v9ses, if (stat->muid) size += strlen(stat->muid); - if (v9ses->extended) { + if (extended) { size += 4 + /* n_uid[4] */ 4 + /* n_gid[4] */ 4 + /* n_muid[4] */ @@ -302,15 +301,14 @@ static int v9fs_size_stat(struct v9fs_session_info *v9ses, /** * serialize_stat - safely format a stat structure for transmission - * @v9ses: session info * @stat: metadata (stat) structure * @bufp: buffer to serialize structure into + * @extended: non-zero if 9P2000.u * */ static int -serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat, - struct cbuf *bufp) +serialize_stat(struct v9fs_stat *stat, struct cbuf *bufp, int extended) { buf_put_int16(bufp, stat->size); buf_put_int16(bufp, stat->type); @@ -328,7 +326,7 @@ serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat, buf_put_string(bufp, stat->gid); buf_put_string(bufp, stat->muid); - if (v9ses->extended) { + if (extended) { buf_put_string(bufp, stat->extension); buf_put_int32(bufp, stat->n_uid); buf_put_int32(bufp, stat->n_gid); @@ -343,16 +341,16 @@ serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat, /** * deserialize_stat - safely decode a recieved metadata (stat) structure - * @v9ses: session info * @bufp: buffer to deserialize * @stat: metadata (stat) structure * @dbufp: buffer to deserialize variable strings into + * @extended: non-zero if 9P2000.u * */ static inline int -deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, - struct v9fs_stat *stat, struct cbuf *dbufp) +deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat, + struct cbuf *dbufp, int extended) { stat->size = buf_get_int16(bufp); @@ -370,7 +368,7 @@ deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, stat->gid = buf_get_stringb(bufp, dbufp); stat->muid = buf_get_stringb(bufp, dbufp); - if (v9ses->extended) { + if (extended) { stat->extension = buf_get_stringb(bufp, dbufp); stat->n_uid = buf_get_int32(bufp); stat->n_gid = buf_get_int32(bufp); @@ -385,20 +383,20 @@ deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, /** * deserialize_statb - wrapper for decoding a received metadata structure - * @v9ses: session info * @bufp: buffer to deserialize * @dbufp: buffer to deserialize variable strings into + * @extended: non-zero if 9P2000.u * */ -static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info - *v9ses, struct cbuf *bufp, - struct cbuf *dbufp) +static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp, + struct cbuf *dbufp, + int extended) { struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat)); if (ret) { - int n = deserialize_stat(v9ses, bufp, ret, dbufp); + int n = deserialize_stat(bufp, ret, dbufp, extended); if (n <= 0) return NULL; } @@ -408,17 +406,16 @@ static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info /** * v9fs_deserialize_stat - decode a received metadata structure - * @v9ses: session info * @buf: buffer to deserialize * @buflen: length of received buffer * @stat: metadata structure to decode into * @statlen: length of destination metadata structure + * @extended: non-zero if 9P2000.u * */ -int -v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf, - u32 buflen, struct v9fs_stat *stat, u32 statlen) +int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, + u32 statlen, int extended) { struct cbuf buffer; struct cbuf *bufp = &buffer; @@ -429,11 +426,10 @@ v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf, buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), statlen - sizeof(struct v9fs_stat)); - return deserialize_stat(v9ses, bufp, stat, dbufp); + return deserialize_stat(bufp, stat, dbufp, extended); } -static inline int -v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall) +static inline int v9fs_size_fcall(struct v9fs_fcall *fcall, int extended) { int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */ int i = 0; @@ -485,7 +481,7 @@ v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall) break; case TWSTAT: /* fid[4] stat[n] */ fcall->params.twstat.stat->size = - v9fs_size_stat(v9ses, fcall->params.twstat.stat); + v9fs_size_stat(fcall->params.twstat.stat, extended); size += 4 + 2 + 2 + fcall->params.twstat.stat->size; } return size; @@ -493,16 +489,16 @@ v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall) /* * v9fs_serialize_fcall - marshall fcall struct into a packet - * @v9ses: session information * @fcall: structure to convert * @data: buffer to serialize fcall into * @datalen: length of buffer to serialize fcall into + * @extended: non-zero if 9P2000.u * */ int -v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall, - void *data, u32 datalen) +v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen, + int extended) { int i = 0; struct v9fs_stat *stat = NULL; @@ -516,7 +512,7 @@ v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall, return -EINVAL; } - fcall->size = v9fs_size_fcall(v9ses, fcall); + fcall->size = v9fs_size_fcall(fcall, extended); buf_put_int32(bufp, fcall->size); buf_put_int8(bufp, fcall->id); @@ -591,31 +587,31 @@ v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall, stat = fcall->params.twstat.stat; buf_put_int16(bufp, stat->size + 2); - serialize_stat(v9ses, stat, bufp); + serialize_stat(stat, bufp, extended); break; } - if (buf_check_overflow(bufp)) + if (buf_check_overflow(bufp)) { + dprintk(DEBUG_ERROR, "buffer overflow\n"); return -EIO; + } return fcall->size; } /** * deserialize_fcall - unmarshal a response - * @v9ses: session information - * @msgsize: size of rcall message * @buf: recieved buffer * @buflen: length of received buffer * @rcall: fcall structure to populate * @rcalllen: length of fcall structure to populate + * @extended: non-zero if 9P2000.u * */ int -v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, - void *buf, u32 buflen, struct v9fs_fcall *rcall, - int rcalllen) +v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, + int rcalllen, int extended) { struct cbuf buffer; @@ -628,7 +624,7 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall), rcalllen - sizeof(struct v9fs_fcall)); - rcall->size = msgsize; + rcall->size = buf_get_int32(bufp); rcall->id = buf_get_int8(bufp); rcall->tag = buf_get_int16(bufp); @@ -651,6 +647,12 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, break; case RWALK: rcall->params.rwalk.nwqid = buf_get_int16(bufp); + if (rcall->params.rwalk.nwqid > 16) { + eprintk(KERN_ERR, "Rwalk with more than 16 qids: %d\n", + rcall->params.rwalk.nwqid); + return -EPROTO; + } + rcall->params.rwalk.wqids = buf_alloc(dbufp, rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); if (rcall->params.rwalk.wqids) @@ -690,19 +692,21 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, case RSTAT: buf_get_int16(bufp); rcall->params.rstat.stat = - deserialize_statb(v9ses, bufp, dbufp); + deserialize_statb(bufp, dbufp, extended); break; case RWSTAT: break; case RERROR: rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); - if (v9ses->extended) + if (extended) rcall->params.rerror.errno = buf_get_int16(bufp); break; } - if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) + if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) { + dprintk(DEBUG_ERROR, "buffer overflow\n"); return -EIO; + } return rcall->size; } diff --git a/fs/9p/conv.h b/fs/9p/conv.h index ee849613c61a..d5e33e17a685 100644 --- a/fs/9p/conv.h +++ b/fs/9p/conv.h @@ -24,13 +24,12 @@ * */ -int v9fs_deserialize_stat(struct v9fs_session_info *, void *buf, - u32 buflen, struct v9fs_stat *stat, u32 statlen); -int v9fs_serialize_fcall(struct v9fs_session_info *, struct v9fs_fcall *tcall, - void *buf, u32 buflen); -int v9fs_deserialize_fcall(struct v9fs_session_info *, u32 msglen, - void *buf, u32 buflen, struct v9fs_fcall *rcall, - int rcalllen); +int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, + u32 statlen, int extended); +int v9fs_serialize_fcall(struct v9fs_fcall *tcall, void *buf, u32 buflen, + int extended); +int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, + int rcalllen, int extended); /* this one is actually in error.c right now */ int v9fs_errstr2errno(char *errstr); diff --git a/fs/9p/fid.c b/fs/9p/fid.c index d95f8626d170..60ef8aba757a 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -164,7 +164,7 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) return v9fs_fid_create(dentry, v9ses, fidnum, 0); clunk_fid: - v9fs_t_clunk(v9ses, fidnum, NULL); + v9fs_t_clunk(v9ses, fidnum); return ERR_PTR(err); } diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 8835b576f744..62b6ad0767e1 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -4,7 +4,7 @@ * Protocol Multiplexer * * Copyright (C) 2004 by Eric Van Hensbergen - * Copyright (C) 2004 by Latchesar Ionkov + * Copyright (C) 2004-2005 by Latchesar Ionkov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -38,438 +39,903 @@ #include "conv.h" #include "mux.h" -/** - * dprintcond - print condition of session info - * @v9ses: session info structure - * @req: RPC request structure - * - */ +#define ERREQFLUSH 1 +#define SCHED_TIMEOUT 10 +#define MAXPOLLWADDR 2 + +enum { + Rworksched = 1, /* read work scheduled or running */ + Rpending = 2, /* can read */ + Wworksched = 4, /* write work scheduled or running */ + Wpending = 8, /* can write */ +}; + +struct v9fs_mux_poll_task; + +struct v9fs_req { + int tag; + struct v9fs_fcall *tcall; + struct v9fs_fcall *rcall; + int err; + v9fs_mux_req_callback cb; + void *cba; + struct list_head req_list; +}; + +struct v9fs_mux_data { + spinlock_t lock; + struct list_head mux_list; + struct v9fs_mux_poll_task *poll_task; + int msize; + unsigned char *extended; + struct v9fs_transport *trans; + struct v9fs_idpool tidpool; + int err; + wait_queue_head_t equeue; + struct list_head req_list; + struct list_head unsent_req_list; + int rpos; + char *rbuf; + int wpos; + int wsize; + char *wbuf; + wait_queue_t poll_wait[MAXPOLLWADDR]; + wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; + poll_table pt; + struct work_struct rq; + struct work_struct wq; + unsigned long wsched; +}; + +struct v9fs_mux_poll_task { + struct task_struct *task; + struct list_head mux_list; + int muxnum; +}; + +struct v9fs_mux_rpc { + struct v9fs_mux_data *m; + struct v9fs_req *req; + int err; + struct v9fs_fcall *rcall; + wait_queue_head_t wqueue; +}; + +static int v9fs_poll_proc(void *); +static void v9fs_read_work(void *); +static void v9fs_write_work(void *); +static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, + poll_table * p); + +static DECLARE_MUTEX(v9fs_mux_task_lock); +static struct workqueue_struct *v9fs_mux_wq; + +static int v9fs_mux_num; +static int v9fs_mux_poll_task_num; +static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100]; + +void v9fs_mux_global_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) + v9fs_mux_poll_tasks[i].task = NULL; + + v9fs_mux_wq = create_workqueue("v9fs"); +} -static inline int -dprintcond(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) +void v9fs_mux_global_exit(void) { - dprintk(DEBUG_MUX, "condition: %d, %p\n", v9ses->transport->status, - req->rcall); - return 0; + destroy_workqueue(v9fs_mux_wq); } /** - * xread - force read of a certain number of bytes - * @v9ses: session info structure - * @ptr: pointer to buffer - * @sz: number of bytes to read + * v9fs_mux_calc_poll_procs - calculates the number of polling procs + * based on the number of mounted v9fs filesystems. * - * Chuck Cranor CS-533 project1 + * The current implementation returns sqrt of the number of mounts. */ +inline int v9fs_mux_calc_poll_procs(int muxnum) +{ + int n; + + if (v9fs_mux_poll_task_num) + n = muxnum / v9fs_mux_poll_task_num + + (muxnum % v9fs_mux_poll_task_num ? 1 : 0); + else + n = 1; + + if (n > ARRAY_SIZE(v9fs_mux_poll_tasks)) + n = ARRAY_SIZE(v9fs_mux_poll_tasks); -static int xread(struct v9fs_session_info *v9ses, void *ptr, unsigned long sz) + return n; +} + +static void v9fs_mux_poll_start(struct v9fs_mux_data *m) { - int rd = 0; - int ret = 0; - while (rd < sz) { - ret = v9ses->transport->read(v9ses->transport, ptr, sz - rd); - if (ret <= 0) { - dprintk(DEBUG_ERROR, "xread errno %d\n", ret); - return ret; + int i, n; + struct v9fs_mux_poll_task *vpt, *vptlast; + + dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num, + v9fs_mux_poll_task_num); + up(&v9fs_mux_task_lock); + + n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1); + if (n > v9fs_mux_poll_task_num) { + for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { + if (v9fs_mux_poll_tasks[i].task == NULL) { + vpt = &v9fs_mux_poll_tasks[i]; + dprintk(DEBUG_MUX, "create proc %p\n", vpt); + vpt->task = kthread_create(v9fs_poll_proc, + vpt, "v9fs-poll"); + INIT_LIST_HEAD(&vpt->mux_list); + vpt->muxnum = 0; + v9fs_mux_poll_task_num++; + wake_up_process(vpt->task); + break; + } } - rd += ret; - ptr += ret; - } - return (rd); -} -/** - * read_message - read a full 9P2000 fcall packet - * @v9ses: session info structure - * @rcall: fcall structure to read into - * @rcalllen: size of fcall buffer - * - */ + if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) + dprintk(DEBUG_ERROR, "warning: no free poll slots\n"); + } -static int -read_message(struct v9fs_session_info *v9ses, - struct v9fs_fcall *rcall, int rcalllen) -{ - unsigned char buf[4]; - void *data; - int size = 0; - int res = 0; - - res = xread(v9ses, buf, sizeof(buf)); - if (res < 0) { - dprintk(DEBUG_ERROR, - "Reading of count field failed returned: %d\n", res); - return res; + n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num + + ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0); + + vptlast = NULL; + for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { + vpt = &v9fs_mux_poll_tasks[i]; + if (vpt->task != NULL) { + vptlast = vpt; + if (vpt->muxnum < n) { + dprintk(DEBUG_MUX, "put in proc %d\n", i); + list_add(&m->mux_list, &vpt->mux_list); + vpt->muxnum++; + m->poll_task = vpt; + memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); + init_poll_funcptr(&m->pt, v9fs_pollwait); + break; + } + } } - if (res < 4) { - dprintk(DEBUG_ERROR, - "Reading of count field failed returned: %d\n", res); - return -EIO; + if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) { + dprintk(DEBUG_MUX, "put in proc %d\n", i); + list_add(&m->mux_list, &vptlast->mux_list); + vptlast->muxnum++; + m->poll_task = vpt; + memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); + init_poll_funcptr(&m->pt, v9fs_pollwait); } - size = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - dprintk(DEBUG_MUX, "got a packet count: %d\n", size); + v9fs_mux_num++; + down(&v9fs_mux_task_lock); +} - /* adjust for the four bytes of size */ - size -= 4; +static void v9fs_mux_poll_stop(struct v9fs_mux_data *m) +{ + int i; + struct v9fs_mux_poll_task *vpt; + + up(&v9fs_mux_task_lock); + vpt = m->poll_task; + list_del(&m->mux_list); + for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { + if (m->poll_waddr[i] != NULL) { + remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); + m->poll_waddr[i] = NULL; + } + } + vpt->muxnum--; + if (!vpt->muxnum) { + dprintk(DEBUG_MUX, "destroy proc %p\n", vpt); + send_sig(SIGKILL, vpt->task, 1); + vpt->task = NULL; + v9fs_mux_poll_task_num--; + } + v9fs_mux_num--; + down(&v9fs_mux_task_lock); +} - if (size > v9ses->maxdata) { - dprintk(DEBUG_ERROR, "packet too big: %d\n", size); - return -E2BIG; +/** + * v9fs_mux_init - allocate and initialize the per-session mux data + * Creates the polling task if this is the first session. + * + * @trans - transport structure + * @msize - maximum message size + * @extended - pointer to the extended flag + */ +struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, + unsigned char *extended) +{ + int i, n; + struct v9fs_mux_data *m, *mtmp; + + dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); + m = kmalloc(sizeof(struct v9fs_mux_data) + 2 * msize, GFP_KERNEL); + if (!m) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&m->lock); + INIT_LIST_HEAD(&m->mux_list); + m->msize = msize; + m->extended = extended; + m->trans = trans; + idr_init(&m->tidpool.pool); + init_MUTEX(&m->tidpool.lock); + m->err = 0; + init_waitqueue_head(&m->equeue); + INIT_LIST_HEAD(&m->req_list); + INIT_LIST_HEAD(&m->unsent_req_list); + m->rpos = 0; + m->rbuf = (char *)m + sizeof(struct v9fs_mux_data); + m->wpos = m->wsize = 0; + m->wbuf = m->rbuf + msize; + INIT_WORK(&m->rq, v9fs_read_work, m); + INIT_WORK(&m->wq, v9fs_write_work, m); + m->wsched = 0; + memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); + v9fs_mux_poll_start(m); + + n = trans->poll(trans, &m->pt); + if (n & POLLIN) { + dprintk(DEBUG_MUX, "mux %p can read\n", m); + set_bit(Rpending, &m->wsched); } - data = kmalloc(size, GFP_KERNEL); - if (!data) { - eprintk(KERN_WARNING, "out of memory\n"); - return -ENOMEM; + if (n & POLLOUT) { + dprintk(DEBUG_MUX, "mux %p can write\n", m); + set_bit(Wpending, &m->wsched); } - res = xread(v9ses, data, size); - if (res < size) { - dprintk(DEBUG_ERROR, "Reading of fcall failed returned: %d\n", - res); - kfree(data); - return res; + for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { + if (IS_ERR(m->poll_waddr[i])) { + v9fs_mux_poll_stop(m); + mtmp = (void *)m->poll_waddr; /* the error code */ + kfree(m); + m = mtmp; + break; + } } - /* we now have an in-memory string that is the reply. - * deserialize it. There is very little to go wrong at this point - * save for v9fs_alloc errors. - */ - res = v9fs_deserialize_fcall(v9ses, size, data, v9ses->maxdata, - rcall, rcalllen); + return m; +} - kfree(data); +/** + * v9fs_mux_destroy - cancels all pending requests and frees mux resources + */ +void v9fs_mux_destroy(struct v9fs_mux_data *m) +{ + dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m, + m->mux_list.prev, m->mux_list.next); + v9fs_mux_cancel(m, -ECONNRESET); + + if (!list_empty(&m->req_list)) { + /* wait until all processes waiting on this session exit */ + dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n", + m); + wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000); + dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m, + list_empty(&m->req_list)); + } - if (res < 0) - return res; + v9fs_mux_poll_stop(m); + m->trans = NULL; - return 0; + kfree(m); } /** - * v9fs_recv - receive an RPC response for a particular tag - * @v9ses: session info structure - * @req: RPC request structure - * + * v9fs_pollwait - called by files poll operation to add v9fs-poll task + * to files wait queue */ - -static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) +static void +v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, + poll_table * p) { - int ret = 0; - - dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag); - ret = wait_event_interruptible(v9ses->read_wait, - ((v9ses->transport->status != Connected) || - (req->rcall != 0) || (req->err < 0) || - dprintcond(v9ses, req))); + int i; + struct v9fs_mux_data *m; - dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall); + m = container_of(p, struct v9fs_mux_data, pt); + for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) + if (m->poll_waddr[i] == NULL) + break; - spin_lock(&v9ses->muxlock); - list_del(&req->next); - spin_unlock(&v9ses->muxlock); + if (i >= ARRAY_SIZE(m->poll_waddr)) { + dprintk(DEBUG_ERROR, "not enough wait_address slots\n"); + return; + } - if (req->err < 0) - return req->err; + m->poll_waddr[i] = wait_address; - if (v9ses->transport->status == Disconnected) - return -ECONNRESET; + if (!wait_address) { + dprintk(DEBUG_ERROR, "no wait_address\n"); + m->poll_waddr[i] = ERR_PTR(-EIO); + return; + } - return ret; + init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); + add_wait_queue(wait_address, &m->poll_wait[i]); } /** - * v9fs_send - send a 9P request - * @v9ses: session info structure - * @req: RPC request to send - * + * v9fs_poll_mux - polls a mux and schedules read or write works if necessary */ - -static int v9fs_send(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) +static inline void v9fs_poll_mux(struct v9fs_mux_data *m) { - int ret = -1; - void *data = NULL; - struct v9fs_fcall *tcall = req->tcall; - - data = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL); - if (!data) - return -ENOMEM; - - tcall->size = 0; /* enforce size recalculation */ - ret = - v9fs_serialize_fcall(v9ses, tcall, data, - v9ses->maxdata + V9FS_IOHDRSZ); - if (ret < 0) - goto free_data; - - spin_lock(&v9ses->muxlock); - list_add(&req->next, &v9ses->mux_fcalls); - spin_unlock(&v9ses->muxlock); - - dprintk(DEBUG_MUX, "sending message: tag %d size %d\n", tcall->tag, - tcall->size); - ret = v9ses->transport->write(v9ses->transport, data, tcall->size); - - if (ret != tcall->size) { - spin_lock(&v9ses->muxlock); - list_del(&req->next); - kfree(req->rcall); + int n; - spin_unlock(&v9ses->muxlock); - if (ret >= 0) - ret = -EREMOTEIO; - } else - ret = 0; + if (m->err < 0) + return; + + n = m->trans->poll(m->trans, NULL); + if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { + dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n); + if (n >= 0) + n = -ECONNRESET; + v9fs_mux_cancel(m, n); + } + + if (n & POLLIN) { + set_bit(Rpending, &m->wsched); + dprintk(DEBUG_MUX, "mux %p can read\n", m); + if (!test_and_set_bit(Rworksched, &m->wsched)) { + dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); + queue_work(v9fs_mux_wq, &m->rq); + } + } - free_data: - kfree(data); - return ret; + if (n & POLLOUT) { + set_bit(Wpending, &m->wsched); + dprintk(DEBUG_MUX, "mux %p can write\n", m); + if ((m->wsize || !list_empty(&m->unsent_req_list)) + && !test_and_set_bit(Wworksched, &m->wsched)) { + dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); + queue_work(v9fs_mux_wq, &m->wq); + } + } } /** - * v9fs_mux_rpc - send a request, receive a response - * @v9ses: session info structure - * @tcall: fcall to send - * @rcall: buffer to place response into - * + * v9fs_poll_proc - polls all v9fs transports for new events and queues + * the appropriate work to the work queue */ - -long -v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, - struct v9fs_fcall **rcall) +static int v9fs_poll_proc(void *a) { - int tid = -1; - struct v9fs_fcall *fcall = NULL; - struct v9fs_rpcreq req; - int ret = -1; + struct v9fs_mux_data *m, *mtmp; + struct v9fs_mux_poll_task *vpt; - if (!v9ses) - return -EINVAL; + vpt = a; + dprintk(DEBUG_MUX, "start %p %p\n", current, vpt); + allow_signal(SIGKILL); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) + break; - if (!v9ses->transport || v9ses->transport->status != Connected) - return -EIO; + list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { + v9fs_poll_mux(m); + } + + dprintk(DEBUG_MUX, "sleeping...\n"); + schedule_timeout(SCHED_TIMEOUT * HZ); + } - if (rcall) - *rcall = NULL; + __set_current_state(TASK_RUNNING); + dprintk(DEBUG_MUX, "finish\n"); + return 0; +} - if (tcall->id != TVERSION) { - tid = v9fs_get_idpool(&v9ses->tidpool); - if (tid < 0) - return -ENOMEM; +static inline int v9fs_write_req(struct v9fs_mux_data *m, struct v9fs_req *req) +{ + int n; + + list_move_tail(&req->req_list, &m->req_list); + n = v9fs_serialize_fcall(req->tcall, m->wbuf, m->msize, *m->extended); + if (n < 0) { + req->err = n; + list_del(&req->req_list); + if (req->cb) { + spin_unlock(&m->lock); + (*req->cb) (req->cba, req->tcall, req->rcall, req->err); + req->cb = NULL; + spin_lock(&m->lock); + } else + kfree(req->rcall); + + kfree(req); } - tcall->tag = tid; + return n; +} - req.tcall = tcall; - req.err = 0; - req.rcall = NULL; +/** + * v9fs_write_work - called when a transport can send some data + */ +static void v9fs_write_work(void *a) +{ + int n, err; + struct v9fs_mux_data *m; + struct v9fs_req *req, *rtmp; - ret = v9fs_send(v9ses, &req); + m = a; - if (ret < 0) { - if (tcall->id != TVERSION) - v9fs_put_idpool(tid, &v9ses->tidpool); - dprintk(DEBUG_MUX, "error %d\n", ret); - return ret; + if (m->err < 0) { + clear_bit(Wworksched, &m->wsched); + return; } - ret = v9fs_recv(v9ses, &req); - - fcall = req.rcall; - - dprintk(DEBUG_MUX, "received: tag=%x, ret=%d\n", tcall->tag, ret); - if (ret == -ERESTARTSYS) { - if (v9ses->transport->status != Disconnected - && tcall->id != TFLUSH) { - unsigned long flags; - - dprintk(DEBUG_MUX, "flushing the tag: %d\n", - tcall->tag); - clear_thread_flag(TIF_SIGPENDING); - v9fs_t_flush(v9ses, tcall->tag); - spin_lock_irqsave(¤t->sighand->siglock, flags); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, - flags); - dprintk(DEBUG_MUX, "flushing done\n"); + if (!m->wsize) { + if (list_empty(&m->unsent_req_list)) { + clear_bit(Wworksched, &m->wsched); + return; } - goto release_req; - } else if (ret < 0) - goto release_req; - - if (!fcall) - ret = -EIO; - else { - if (fcall->id == RERROR) { - ret = v9fs_errstr2errno(fcall->params.rerror.error); - if (ret == 0) { /* string match failed */ - if (fcall->params.rerror.errno) - ret = -(fcall->params.rerror.errno); - else - ret = -ESERVERFAULT; - } - } else if (fcall->id != tcall->id + 1) { - dprintk(DEBUG_ERROR, - "fcall mismatch: expected %d, got %d\n", - tcall->id + 1, fcall->id); - ret = -EIO; + err = 0; + spin_lock(&m->lock); + list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, + req_list) { + err = v9fs_write_req(m, req); + if (err > 0) + break; } + + m->wsize = err; + m->wpos = 0; + spin_unlock(&m->lock); } - release_req: - if (tcall->id != TVERSION) - v9fs_put_idpool(tid, &v9ses->tidpool); - if (rcall) - *rcall = fcall; - else - kfree(fcall); + dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); + clear_bit(Wpending, &m->wsched); + err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); + dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err); + if (err == -EAGAIN) { + clear_bit(Wworksched, &m->wsched); + return; + } + + if (err <= 0) + goto error; + + m->wpos += err; + if (m->wpos == m->wsize) + m->wpos = m->wsize = 0; + + if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { + if (test_and_clear_bit(Wpending, &m->wsched)) + n = POLLOUT; + else + n = m->trans->poll(m->trans, NULL); + + if (n & POLLOUT) { + dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); + queue_work(v9fs_mux_wq, &m->wq); + } else + clear_bit(Wworksched, &m->wsched); + } else + clear_bit(Wworksched, &m->wsched); - return ret; + return; + + error: + v9fs_mux_cancel(m, err); + clear_bit(Wworksched, &m->wsched); } -/** - * v9fs_mux_cancel_requests - cancels all pending requests - * - * @v9ses: session info structure - * @err: error code to return to the requests - */ -void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err) +static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) { - struct v9fs_rpcreq *rptr; - struct v9fs_rpcreq *rreq; + int ecode, tag; + char *ename; + + tag = req->tag; + if (req->rcall->id == RERROR && !req->err) { + ecode = req->rcall->params.rerror.errno; + ename = req->rcall->params.rerror.error; - dprintk(DEBUG_MUX, " %d\n", err); - spin_lock(&v9ses->muxlock); - list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { - rreq->err = err; + dprintk(DEBUG_MUX, "Rerror %s\n", ename); + + if (*m->extended) + req->err = -ecode; + + if (!req->err) { + req->err = v9fs_errstr2errno(ename); + + if (!req->err) { /* string match failed */ + dprintk(DEBUG_ERROR, "unknown error: %s\n", + ename); + } + + if (!req->err) + req->err = -ESERVERFAULT; + } + } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { + dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n", + req->tcall->id + 1, req->rcall->id); + if (!req->err) + req->err = -EIO; } - spin_unlock(&v9ses->muxlock); - wake_up_all(&v9ses->read_wait); + + if (req->cb && req->err != ERREQFLUSH) { + dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n", + req->tcall, req->rcall); + + (*req->cb) (req->cba, req->tcall, req->rcall, req->err); + req->cb = NULL; + } else + kfree(req->rcall); + + if (tag != V9FS_NOTAG) + v9fs_put_idpool(tag, &m->tidpool); + + wake_up(&m->equeue); + kfree(req); } /** - * v9fs_recvproc - kproc to handle demultiplexing responses - * @data: session info structure - * + * v9fs_read_work - called when there is some data to be read from a transport */ - -static int v9fs_recvproc(void *data) +static void v9fs_read_work(void *a) { - struct v9fs_session_info *v9ses = (struct v9fs_session_info *)data; - struct v9fs_fcall *rcall = NULL; - struct v9fs_rpcreq *rptr; - struct v9fs_rpcreq *req; - struct v9fs_rpcreq *rreq; - int err = 0; + int n, err, rcallen; + struct v9fs_mux_data *m; + struct v9fs_req *req, *rptr, *rreq; + struct v9fs_fcall *rcall; + + m = a; + + if (m->err < 0) + return; + + rcall = NULL; + dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); + clear_bit(Rpending, &m->wsched); + err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); + dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); + if (err == -EAGAIN) { + clear_bit(Rworksched, &m->wsched); + return; + } - allow_signal(SIGKILL); - set_current_state(TASK_INTERRUPTIBLE); - complete(&v9ses->proccmpl); - while (!kthread_should_stop() && err >= 0) { - req = rptr = rreq = NULL; + if (err <= 0) + goto error; - rcall = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL); - if (!rcall) { - eprintk(KERN_ERR, "no memory for buffers\n"); + m->rpos += err; + while (m->rpos > 4) { + n = le32_to_cpu(*(__le32 *) m->rbuf); + if (n >= m->msize) { + dprintk(DEBUG_ERROR, + "requested packet size too big: %d\n", n); + err = -EIO; + goto error; + } + + if (m->rpos < n) break; + + rcallen = n + V9FS_FCALLHDRSZ; + rcall = kmalloc(rcallen, GFP_KERNEL); + if (!rcall) { + err = -ENOMEM; + goto error; } - err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ); - spin_lock(&v9ses->muxlock); + dump_data(m->rbuf, n); + err = v9fs_deserialize_fcall(m->rbuf, n, rcall, rcallen, + *m->extended); if (err < 0) { - list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { - rreq->err = err; - } - if(err != -ERESTARTSYS) - eprintk(KERN_ERR, - "Transport error while reading message %d\n", err); - } else { - list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { - if (rreq->tcall->tag == rcall->tag) { - req = rreq; - req->rcall = rcall; - break; - } - } + kfree(rcall); + goto error; } - if (req && (req->tcall->id == TFLUSH)) { - struct v9fs_rpcreq *treq = NULL; - list_for_each_entry_safe(treq, rptr, &v9ses->mux_fcalls, next) { - if (treq->tcall->tag == - req->tcall->params.tflush.oldtag) { - list_del(&rptr->next); - kfree(treq->rcall); - break; - } + dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, + rcall->tag); + + req = NULL; + spin_lock(&m->lock); + list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { + if (rreq->tag == rcall->tag) { + req = rreq; + req->rcall = rcall; + list_del(&req->req_list); + spin_unlock(&m->lock); + process_request(m, req); + break; } } - spin_unlock(&v9ses->muxlock); - if (!req) { - if (err >= 0) + spin_unlock(&m->lock); + if (err >= 0 && rcall->id != RFLUSH) dprintk(DEBUG_ERROR, - "unexpected response: id %d tag %d\n", - rcall->id, rcall->tag); - + "unexpected response mux %p id %d tag %d\n", + m, rcall->id, rcall->tag); kfree(rcall); } - wake_up_all(&v9ses->read_wait); - set_current_state(TASK_INTERRUPTIBLE); + if (m->rpos > n) + memmove(m->rbuf, m->rbuf + n, m->rpos - n); + m->rpos -= n; } - v9ses->transport->close(v9ses->transport); - - /* Inform all pending processes about the failure */ - wake_up_all(&v9ses->read_wait); - - if (signal_pending(current)) - complete(&v9ses->proccmpl); + if (!list_empty(&m->req_list)) { + if (test_and_clear_bit(Rpending, &m->wsched)) + n = POLLIN; + else + n = m->trans->poll(m->trans, NULL); + + if (n & POLLIN) { + dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); + queue_work(v9fs_mux_wq, &m->rq); + } else + clear_bit(Rworksched, &m->wsched); + } else + clear_bit(Rworksched, &m->wsched); - dprintk(DEBUG_MUX, "recvproc: end\n"); - v9ses->recvproc = NULL; + return; - return err >= 0; + error: + v9fs_mux_cancel(m, err); + clear_bit(Rworksched, &m->wsched); } /** - * v9fs_mux_init - initialize multiplexer (spawn kproc) - * @v9ses: session info structure - * @dev_name: mount device information (to create unique kproc) + * v9fs_send_request - send 9P request + * The function can sleep until the request is scheduled for sending. + * The function can be interrupted. Return from the function is not + * a guarantee that the request is sent succesfully. Can return errors + * that can be retrieved by PTR_ERR macros. * + * @m: mux data + * @tc: request to be sent + * @cb: callback function to call when response is received + * @cba: parameter to pass to the callback function */ +static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, + struct v9fs_fcall *tc, + v9fs_mux_req_callback cb, void *cba) +{ + int n; + struct v9fs_req *req; + + dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, + tc, tc->id); + if (m->err < 0) + return ERR_PTR(m->err); + + req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL); + if (!req) + return ERR_PTR(-ENOMEM); -int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name) + if (tc->id == TVERSION) + n = V9FS_NOTAG; + else + n = v9fs_get_idpool(&m->tidpool); + + if (n < 0) + return ERR_PTR(-ENOMEM); + + tc->tag = n; + req->tag = n; + req->tcall = tc; + req->rcall = NULL; + req->err = 0; + req->cb = cb; + req->cba = cba; + + spin_lock(&m->lock); + list_add_tail(&req->req_list, &m->unsent_req_list); + spin_unlock(&m->lock); + + if (test_and_clear_bit(Wpending, &m->wsched)) + n = POLLOUT; + else + n = m->trans->poll(m->trans, NULL); + + if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) + queue_work(v9fs_mux_wq, &m->wq); + + return req; +} + +static inline void +v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, + int err) { - char procname[60]; - - strncpy(procname, dev_name, sizeof(procname)); - procname[sizeof(procname) - 1] = 0; - - init_waitqueue_head(&v9ses->read_wait); - init_completion(&v9ses->fcread); - init_completion(&v9ses->proccmpl); - spin_lock_init(&v9ses->muxlock); - INIT_LIST_HEAD(&v9ses->mux_fcalls); - v9ses->recvproc = NULL; - v9ses->curfcall = NULL; - - v9ses->recvproc = kthread_create(v9fs_recvproc, v9ses, - "v9fs_recvproc %s", procname); - - if (IS_ERR(v9ses->recvproc)) { - eprintk(KERN_ERR, "cannot create receiving thread\n"); - v9fs_session_close(v9ses); - return -ECONNABORTED; + v9fs_mux_req_callback cb; + int tag; + struct v9fs_mux_data *m; + struct v9fs_req *req, *rptr; + + m = a; + dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, tc, + rc, err, tc->params.tflush.oldtag); + + spin_lock(&m->lock); + cb = NULL; + tag = tc->params.tflush.oldtag; + list_for_each_entry_safe(req, rptr, &m->req_list, req_list) { + if (req->tag == tag) { + list_del(&req->req_list); + if (req->cb) { + cb = req->cb; + req->cb = NULL; + spin_unlock(&m->lock); + (*cb) (req->cba, req->tcall, req->rcall, + req->err); + } + kfree(req); + wake_up(&m->equeue); + break; + } + } + + if (!cb) + spin_unlock(&m->lock); + + if (v9fs_check_idpool(tag, &m->tidpool)) + v9fs_put_idpool(tag, &m->tidpool); + + kfree(tc); + kfree(rc); +} + +static void +v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) +{ + struct v9fs_fcall *fc; + + dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); + + fc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL); + fc->id = TFLUSH; + fc->params.tflush.oldtag = req->tag; + + v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); +} + +static void +v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err) +{ + struct v9fs_mux_rpc *r; + + if (err == ERREQFLUSH) { + dprintk(DEBUG_MUX, "err req flush\n"); + return; + } + + r = a; + dprintk(DEBUG_MUX, "mux %p req %p tc %p rc %p err %d\n", r->m, r->req, + tc, rc, err); + r->rcall = rc; + r->err = err; + wake_up(&r->wqueue); +} + +/** + * v9fs_mux_rpc - sends 9P request and waits until a response is available. + * The function can be interrupted. + * @m: mux data + * @tc: request to be sent + * @rc: pointer where a pointer to the response is stored + */ +int +v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, + struct v9fs_fcall **rc) +{ + int err; + unsigned long flags; + struct v9fs_req *req; + struct v9fs_mux_rpc r; + + r.err = 0; + r.rcall = NULL; + r.m = m; + init_waitqueue_head(&r.wqueue); + + if (rc) + *rc = NULL; + + req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r); + if (IS_ERR(req)) { + err = PTR_ERR(req); + dprintk(DEBUG_MUX, "error %d\n", err); + return PTR_ERR(req); + } + + r.req = req; + dprintk(DEBUG_MUX, "mux %p tc %p tag %d rpc %p req %p\n", m, tc, + req->tag, &r, req); + err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); + if (r.err < 0) + err = r.err; + + if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) { + spin_lock(&m->lock); + req->tcall = NULL; + req->err = ERREQFLUSH; + spin_unlock(&m->lock); + + clear_thread_flag(TIF_SIGPENDING); + v9fs_mux_flush_request(m, req); + spin_lock_irqsave(¤t->sighand->siglock, flags); + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); } - wake_up_process(v9ses->recvproc); - wait_for_completion(&v9ses->proccmpl); + if (!err) { + if (r.rcall) + dprintk(DEBUG_MUX, "got response id %d tag %d\n", + r.rcall->id, r.rcall->tag); + + if (rc) + *rc = r.rcall; + else + kfree(r.rcall); + } else { + kfree(r.rcall); + dprintk(DEBUG_MUX, "got error %d\n", err); + if (err > 0) + err = -EIO; + } + + return err; +} + +/** + * v9fs_mux_rpcnb - sends 9P request without waiting for response. + * @m: mux data + * @tc: request to be sent + * @cb: callback function to be called when response arrives + * @cba: value to pass to the callback function + */ +int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc, + v9fs_mux_req_callback cb, void *a) +{ + int err; + struct v9fs_req *req; + + req = v9fs_send_request(m, tc, cb, a); + if (IS_ERR(req)) { + err = PTR_ERR(req); + dprintk(DEBUG_MUX, "error %d\n", err); + return PTR_ERR(req); + } + dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); return 0; } + +/** + * v9fs_mux_cancel - cancel all pending requests with error + * @m: mux data + * @err: error code + */ +void v9fs_mux_cancel(struct v9fs_mux_data *m, int err) +{ + struct v9fs_req *req, *rtmp; + LIST_HEAD(cancel_list); + + dprintk(DEBUG_MUX, "mux %p err %d\n", m, err); + m->err = err; + spin_lock(&m->lock); + list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { + list_move(&req->req_list, &cancel_list); + } + spin_unlock(&m->lock); + + list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { + list_del(&req->req_list); + if (!req->err) + req->err = err; + + if (req->cb) + (*req->cb) (req->cba, req->tcall, req->rcall, req->err); + else + kfree(req->rcall); + + kfree(req); + } + + wake_up(&m->equeue); +} diff --git a/fs/9p/mux.h b/fs/9p/mux.h index 4994cb10badf..02b13b14b05b 100644 --- a/fs/9p/mux.h +++ b/fs/9p/mux.h @@ -3,6 +3,7 @@ * * Multiplexer Definitions * + * Copyright (C) 2005 by Latchesar Ionkov * Copyright (C) 2004 by Eric Van Hensbergen * * This program is free software; you can redistribute it and/or modify @@ -23,19 +24,34 @@ * */ -/* structure to manage each RPC transaction */ +struct v9fs_mux_data; -struct v9fs_rpcreq { - struct v9fs_fcall *tcall; - struct v9fs_fcall *rcall; - int err; /* error code if response failed */ +/** + * v9fs_mux_req_callback - callback function that is called when the + * response of a request is received. The callback is called from + * a workqueue and shouldn't block. + * + * @a - the pointer that was specified when the request was send to be + * passed to the callback + * @tc - request call + * @rc - response call + * @err - error code (non-zero if error occured) + */ +typedef void (*v9fs_mux_req_callback)(void *a, struct v9fs_fcall *tc, + struct v9fs_fcall *rc, int err); + +void v9fs_mux_global_init(void); +void v9fs_mux_global_exit(void); - /* XXX - could we put scatter/gather buffers here? */ +struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, + unsigned char *extended); +void v9fs_mux_destroy(struct v9fs_mux_data *); - struct list_head next; -}; +int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc); +struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m); +int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc); +int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc, + v9fs_mux_req_callback cb, void *a); -int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name); -long v9fs_mux_rpc(struct v9fs_session_info *v9ses, - struct v9fs_fcall *tcall, struct v9fs_fcall **rcall); -void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err); +void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush); +void v9fs_mux_cancel(struct v9fs_mux_data *m, int err); diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c index b7ffb9859588..1a28ef97a3d1 100644 --- a/fs/9p/trans_fd.c +++ b/fs/9p/trans_fd.c @@ -3,6 +3,7 @@ * * File Descriptor Transport Layer * + * Copyright (C) 2005 by Latchesar Ionkov * Copyright (C) 2005 by Eric Van Hensbergen * * This program is free software; you can redistribute it and/or modify @@ -106,9 +107,6 @@ v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data) return -ENOPROTOOPT; } - sema_init(&trans->writelock, 1); - sema_init(&trans->readlock, 1); - ts = kmalloc(sizeof(struct v9fs_trans_fd), GFP_KERNEL); if (!ts) @@ -163,10 +161,55 @@ static void v9fs_fd_close(struct v9fs_transport *trans) kfree(ts); } +static unsigned int +v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt) +{ + int ret, n; + struct v9fs_trans_fd *ts; + mm_segment_t oldfs; + + if (!trans) + return -EIO; + + ts = trans->priv; + if (trans->status != Connected || !ts) + return -EIO; + + oldfs = get_fs(); + set_fs(get_ds()); + + if (!ts->in_file->f_op || !ts->in_file->f_op->poll) { + ret = -EIO; + goto end; + } + + ret = ts->in_file->f_op->poll(ts->in_file, pt); + + if (ts->out_file != ts->in_file) { + if (!ts->out_file->f_op || !ts->out_file->f_op->poll) { + ret = -EIO; + goto end; + } + + n = ts->out_file->f_op->poll(ts->out_file, pt); + + ret &= ~POLLOUT; + n &= ~POLLIN; + + ret |= n; + } + +end: + set_fs(oldfs); + return ret; +} + + struct v9fs_transport v9fs_trans_fd = { .init = v9fs_fd_init, .write = v9fs_fd_send, .read = v9fs_fd_recv, .close = v9fs_fd_close, + .poll = v9fs_fd_poll, }; diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c index 6a9a75d40f73..9ef404c75c8f 100644 --- a/fs/9p/trans_sock.c +++ b/fs/9p/trans_sock.c @@ -3,6 +3,7 @@ * * Socket Transport Layer * + * Copyright (C) 2004-2005 by Latchesar Ionkov * Copyright (C) 2004 by Eric Van Hensbergen * Copyright (C) 1997-2002 by Ron Minnich * Copyright (C) 1995, 1996 by Olaf Kirch @@ -36,6 +37,7 @@ #include #include #include +#include #include "debug.h" #include "v9fs.h" @@ -45,6 +47,7 @@ struct v9fs_trans_sock { struct socket *s; + struct file *filp; }; /** @@ -57,41 +60,26 @@ struct v9fs_trans_sock { static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len) { - struct msghdr msg; - struct kvec iov; - int result; - mm_segment_t oldfs; - struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + int ret; + struct v9fs_trans_sock *ts; - if (trans->status == Disconnected) + if (!trans || trans->status == Disconnected) { + dprintk(DEBUG_ERROR, "disconnected ...\n"); return -EREMOTEIO; + } - result = -EINVAL; - - oldfs = get_fs(); - set_fs(get_ds()); - - iov.iov_base = v; - iov.iov_len = len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_namelen = 0; - msg.msg_flags = MSG_NOSIGNAL; - - result = kernel_recvmsg(ts->s, &msg, &iov, 1, len, 0); + ts = trans->priv; - dprintk(DEBUG_TRANS, "socket state %d\n", ts->s->state); - set_fs(oldfs); + if (!(ts->filp->f_flags & O_NONBLOCK)) + dprintk(DEBUG_ERROR, "blocking read ...\n"); - if (result <= 0) { - if (result != -ERESTARTSYS) + ret = kernel_read(ts->filp, ts->filp->f_pos, v, len); + if (ret <= 0) { + if (ret != -ERESTARTSYS && ret != -EAGAIN) trans->status = Disconnected; } - return result; + return ret; } /** @@ -104,40 +92,73 @@ static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len) static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len) { - struct kvec iov; - struct msghdr msg; - int result = -1; + int ret; mm_segment_t oldfs; - struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + struct v9fs_trans_sock *ts; - dprintk(DEBUG_TRANS, "Sending packet size %d (%x)\n", len, len); - dump_data(v, len); + if (!trans || trans->status == Disconnected) { + dprintk(DEBUG_ERROR, "disconnected ...\n"); + return -EREMOTEIO; + } + + ts = trans->priv; + if (!ts) { + dprintk(DEBUG_ERROR, "no transport ...\n"); + return -EREMOTEIO; + } - down(&trans->writelock); + if (!(ts->filp->f_flags & O_NONBLOCK)) + dprintk(DEBUG_ERROR, "blocking write ...\n"); + dump_data(v, len); oldfs = get_fs(); set_fs(get_ds()); - iov.iov_base = v; - iov.iov_len = len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_namelen = 0; - msg.msg_flags = MSG_NOSIGNAL; - result = kernel_sendmsg(ts->s, &msg, &iov, 1, len); + ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos); set_fs(oldfs); - if (result < 0) { - if (result != -ERESTARTSYS) + if (ret < 0) { + if (ret != -ERESTARTSYS) trans->status = Disconnected; } - up(&trans->writelock); - return result; + return ret; +} + +static unsigned int v9fs_sock_poll(struct v9fs_transport *trans, + struct poll_table_struct *pt) { + + int ret; + struct v9fs_trans_sock *ts; + mm_segment_t oldfs; + + if (!trans) { + dprintk(DEBUG_ERROR, "no transport\n"); + return -EIO; + } + + ts = trans->priv; + if (trans->status != Connected || !ts) { + dprintk(DEBUG_ERROR, "transport disconnected: %d\n", trans->status); + return -EIO; + } + + oldfs = get_fs(); + set_fs(get_ds()); + + if (!ts->filp->f_op || !ts->filp->f_op->poll) { + dprintk(DEBUG_ERROR, "no poll operation\n"); + ret = -EIO; + goto end; + } + + ret = ts->filp->f_op->poll(ts->filp, pt); + +end: + set_fs(oldfs); + return ret; } + /** * v9fs_tcp_init - initialize TCP socket * @v9ses: session information @@ -154,9 +175,9 @@ v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data) int rc = 0; struct v9fs_trans_sock *ts = NULL; struct v9fs_transport *trans = v9ses->transport; + int fd; - sema_init(&trans->writelock, 1); - sema_init(&trans->readlock, 1); + trans->status = Disconnected; ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL); @@ -165,6 +186,7 @@ v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data) trans->priv = ts; ts->s = NULL; + ts->filp = NULL; if (!addr) return -EINVAL; @@ -185,7 +207,18 @@ v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data) return rc; } csocket->sk->sk_allocation = GFP_NOIO; + + fd = sock_map_fd(csocket); + if (fd < 0) { + sock_release(csocket); + kfree(ts); + trans->priv = NULL; + return fd; + } + ts->s = csocket; + ts->filp = fget(fd); + ts->filp->f_flags |= O_NONBLOCK; trans->status = Connected; return 0; @@ -203,7 +236,7 @@ static int v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, char *data) { - int rc; + int rc, fd; struct socket *csocket; struct sockaddr_un sun_server; struct v9fs_transport *trans; @@ -213,6 +246,8 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, csocket = NULL; trans = v9ses->transport; + trans->status = Disconnected; + if (strlen(dev_name) > UNIX_PATH_MAX) { eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n", dev_name); @@ -225,9 +260,7 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, trans->priv = ts; ts->s = NULL; - - sema_init(&trans->writelock, 1); - sema_init(&trans->readlock, 1); + ts->filp = NULL; sun_server.sun_family = PF_UNIX; strcpy(sun_server.sun_path, dev_name); @@ -241,7 +274,18 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, return rc; } csocket->sk->sk_allocation = GFP_NOIO; + + fd = sock_map_fd(csocket); + if (fd < 0) { + sock_release(csocket); + kfree(ts); + trans->priv = NULL; + return fd; + } + ts->s = csocket; + ts->filp = fget(fd); + ts->filp->f_flags |= O_NONBLOCK; trans->status = Connected; return 0; @@ -262,12 +306,11 @@ static void v9fs_sock_close(struct v9fs_transport *trans) ts = trans->priv; - if ((ts) && (ts->s)) { - dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s); - sock_release(ts->s); + if ((ts) && (ts->filp)) { + fput(ts->filp); + ts->filp = NULL; ts->s = NULL; trans->status = Disconnected; - dprintk(DEBUG_TRANS, "socket closed\n"); } kfree(ts); @@ -280,6 +323,7 @@ struct v9fs_transport v9fs_trans_tcp = { .write = v9fs_sock_send, .read = v9fs_sock_recv, .close = v9fs_sock_close, + .poll = v9fs_sock_poll, }; struct v9fs_transport v9fs_trans_unix = { @@ -287,4 +331,5 @@ struct v9fs_transport v9fs_trans_unix = { .write = v9fs_sock_send, .read = v9fs_sock_recv, .close = v9fs_sock_close, + .poll = v9fs_sock_poll, }; diff --git a/fs/9p/transport.h b/fs/9p/transport.h index 9e9cd418efd5..91fcdb94b361 100644 --- a/fs/9p/transport.h +++ b/fs/9p/transport.h @@ -3,6 +3,7 @@ * * Transport Definition * + * Copyright (C) 2005 by Latchesar Ionkov * Copyright (C) 2004 by Eric Van Hensbergen * * This program is free software; you can redistribute it and/or modify @@ -31,14 +32,13 @@ enum v9fs_transport_status { struct v9fs_transport { enum v9fs_transport_status status; - struct semaphore writelock; - struct semaphore readlock; void *priv; int (*init) (struct v9fs_session_info *, const char *, char *); int (*write) (struct v9fs_transport *, void *, int); int (*read) (struct v9fs_transport *, void *, int); void (*close) (struct v9fs_transport *); + unsigned int (*poll)(struct v9fs_transport *, struct poll_table_struct *); }; extern struct v9fs_transport v9fs_trans_tcp; diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 418c3743fdee..5e0f79355fdf 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -213,7 +213,8 @@ retry: return -1; } - error = idr_get_new(&p->pool, NULL, &i); + /* no need to store exactly p, we just need something non-null */ + error = idr_get_new(&p->pool, p, &i); up(&p->lock); if (error == -EAGAIN) @@ -242,6 +243,16 @@ void v9fs_put_idpool(int id, struct v9fs_idpool *p) up(&p->lock); } +/** + * v9fs_check_idpool - check if the specified id is available + * @id - id to check + * @p - pool + */ +int v9fs_check_idpool(int id, struct v9fs_idpool *p) +{ + return idr_find(&p->pool, id) != NULL; +} + /** * v9fs_session_init - initialize session * @v9ses: session information structure @@ -281,9 +292,6 @@ v9fs_session_init(struct v9fs_session_info *v9ses, /* id pools that are session-dependent: FIDs and TIDs */ idr_init(&v9ses->fidpool.pool); init_MUTEX(&v9ses->fidpool.lock); - idr_init(&v9ses->tidpool.pool); - init_MUTEX(&v9ses->tidpool.lock); - switch (v9ses->proto) { case PROTO_TCP: @@ -320,7 +328,12 @@ v9fs_session_init(struct v9fs_session_info *v9ses, v9ses->shutdown = 0; v9ses->session_hung = 0; - if ((retval = v9fs_mux_init(v9ses, dev_name)) < 0) { + v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ, + &v9ses->extended); + + if (IS_ERR(v9ses->mux)) { + retval = PTR_ERR(v9ses->mux); + v9ses->mux = NULL; dprintk(DEBUG_ERROR, "problem initializing mux\n"); goto SessCleanUp; } @@ -381,7 +394,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses, } if (v9ses->afid != ~0) { - if (v9fs_t_clunk(v9ses, v9ses->afid, NULL)) + if (v9fs_t_clunk(v9ses, v9ses->afid)) dprintk(DEBUG_ERROR, "clunk failed\n"); } @@ -403,13 +416,16 @@ v9fs_session_init(struct v9fs_session_info *v9ses, void v9fs_session_close(struct v9fs_session_info *v9ses) { - if (v9ses->recvproc) { - send_sig(SIGKILL, v9ses->recvproc, 1); - wait_for_completion(&v9ses->proccmpl); + if (v9ses->mux) { + v9fs_mux_destroy(v9ses->mux); + v9ses->mux = NULL; } - if (v9ses->transport) + if (v9ses->transport) { v9ses->transport->close(v9ses->transport); + kfree(v9ses->transport); + v9ses->transport = NULL; + } __putname(v9ses->name); __putname(v9ses->remotename); @@ -420,8 +436,9 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) * and cancel all pending requests. */ void v9fs_session_cancel(struct v9fs_session_info *v9ses) { + dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses); v9ses->transport->status = Disconnected; - v9fs_mux_cancel_requests(v9ses, -EIO); + v9fs_mux_cancel(v9ses->mux, -EIO); } extern int v9fs_error_init(void); @@ -437,6 +454,7 @@ static int __init init_v9fs(void) printk(KERN_INFO "Installing v9fs 9P2000 file system support\n"); + v9fs_mux_global_init(); return register_filesystem(&v9fs_fs_type); } @@ -447,6 +465,7 @@ static int __init init_v9fs(void) static void __exit exit_v9fs(void) { + v9fs_mux_global_exit(); unregister_filesystem(&v9fs_fs_type); } diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 45dcef42bdd6..f337da7a0eec 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -57,24 +57,14 @@ struct v9fs_session_info { /* book keeping */ struct v9fs_idpool fidpool; /* The FID pool for file descriptors */ - struct v9fs_idpool tidpool; /* The TID pool for transactions ids */ - /* transport information */ struct v9fs_transport *transport; + struct v9fs_mux_data *mux; int inprogress; /* session in progress => true */ int shutdown; /* session shutting down. no more attaches. */ unsigned char session_hung; - - /* mux private data */ - struct v9fs_fcall *curfcall; - wait_queue_head_t read_wait; - struct completion fcread; - struct completion proccmpl; - struct task_struct *recvproc; - - spinlock_t muxlock; - struct list_head mux_fcalls; + struct dentry *debugfs_dir; }; /* possible values of ->proto */ @@ -84,11 +74,14 @@ enum { PROTO_FD, }; +extern struct dentry *v9fs_debugfs_root; + int v9fs_session_init(struct v9fs_session_info *, const char *, char *); struct v9fs_session_info *v9fs_inode2v9ses(struct inode *); void v9fs_session_close(struct v9fs_session_info *v9ses); int v9fs_get_idpool(struct v9fs_idpool *p); void v9fs_put_idpool(int id, struct v9fs_idpool *p); +int v9fs_check_idpool(int id, struct v9fs_idpool *p); void v9fs_session_cancel(struct v9fs_session_info *v9ses); #define V9FS_MAGIC 0x01021997 diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index a6aa947de0f9..4887df767394 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -95,24 +95,21 @@ static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) void v9fs_dentry_release(struct dentry *dentry) { + int err; + dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); if (dentry->d_fsdata != NULL) { struct list_head *fid_list = dentry->d_fsdata; struct v9fs_fid *temp = NULL; struct v9fs_fid *current_fid = NULL; - struct v9fs_fcall *fcall = NULL; list_for_each_entry_safe(current_fid, temp, fid_list, list) { - if (v9fs_t_clunk - (current_fid->v9ses, current_fid->fid, &fcall)) - dprintk(DEBUG_ERROR, "clunk failed: %s\n", - FCALL_ERROR(fcall)); + err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid); - v9fs_put_idpool(current_fid->fid, - ¤t_fid->v9ses->fidpool); + if (err < 0) + dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); - kfree(fcall); v9fs_fid_destroy(current_fid); } diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 17089d1905ff..3893dd307ddb 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -74,7 +74,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) struct inode *inode = filp->f_dentry->d_inode; struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); struct v9fs_fid *file = filp->private_data; - unsigned int i, n; + unsigned int i, n, s; int fid = -1; int ret = 0; struct v9fs_stat *mi = NULL; @@ -97,9 +97,9 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) n = file->rdir_fcall->params.rread.count; i = file->rdir_fpos; while (i < n) { - int s = v9fs_deserialize_stat(v9ses, - file->rdir_fcall->params.rread.data + i, - n - i, mi, v9ses->maxdata); + s = v9fs_deserialize_stat( + file->rdir_fcall->params.rread.data + i, + n - i, mi, v9ses->maxdata, v9ses->extended); if (s == 0) { dprintk(DEBUG_ERROR, @@ -141,9 +141,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) n = ret; i = 0; while (i < n) { - int s = v9fs_deserialize_stat(v9ses, - fcall->params.rread.data + i, n - i, mi, - v9ses->maxdata); + s = v9fs_deserialize_stat(fcall->params.rread.data + i, + n - i, mi, v9ses->maxdata, v9ses->extended); if (s == 0) { dprintk(DEBUG_ERROR, @@ -199,11 +198,9 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, fid->fid); - if (v9fs_t_clunk(v9ses, fidnum, NULL)) + if (v9fs_t_clunk(v9ses, fidnum)) dprintk(DEBUG_ERROR, "clunk failed\n"); - v9fs_put_idpool(fid->fid, &v9ses->fidpool); - kfree(fid->rdir_fcall); kfree(fid); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 0ea965c3bb7d..466002a1fe32 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -318,6 +318,7 @@ v9fs_create(struct inode *dir, int result = 0; unsigned int iounit = 0; int wfidno = -1; + int err; perm = unixmode2p9mode(v9ses, perm); @@ -356,6 +357,7 @@ v9fs_create(struct inode *dir, } kfree(fcall); + fcall = NULL; result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, perm, open_mode, &fcall); @@ -369,16 +371,23 @@ v9fs_create(struct inode *dir, iounit = fcall->params.rcreate.iounit; qid = fcall->params.rcreate.qid; kfree(fcall); + fcall = NULL; - fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); - dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); - if (!fid) { - result = -ENOMEM; - goto CleanUpFid; - } + if (!(perm&V9FS_DMDIR)) { + fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); + dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); + if (!fid) { + result = -ENOMEM; + goto CleanUpFid; + } - fid->qid = qid; - fid->iounit = iounit; + fid->qid = qid; + fid->iounit = iounit; + } else { + err = v9fs_t_clunk(v9ses, newfid); + if (err < 0) + dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err); + } /* walk to the newly created file and put the fid in the dentry */ wfidno = v9fs_get_idpool(&v9ses->fidpool); @@ -388,18 +397,19 @@ v9fs_create(struct inode *dir, } result = v9fs_t_walk(v9ses, dirfidnum, wfidno, - (char *) file_dentry->d_name.name, NULL); + (char *) file_dentry->d_name.name, &fcall); if (result < 0) { dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); v9fs_put_idpool(wfidno, &v9ses->fidpool); wfidno = -1; goto CleanUpFid; } + kfree(fcall); + fcall = NULL; if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { - if (!v9fs_t_clunk(v9ses, newfid, &fcall)) { - v9fs_put_idpool(wfidno, &v9ses->fidpool); - } + v9fs_t_clunk(v9ses, newfid); + v9fs_put_idpool(wfidno, &v9ses->fidpool); goto CleanUpFid; } @@ -431,40 +441,21 @@ v9fs_create(struct inode *dir, file_dentry->d_op = &v9fs_dentry_operations; d_instantiate(file_dentry, file_inode); - if (perm & V9FS_DMDIR) { - if (!v9fs_t_clunk(v9ses, newfid, &fcall)) - v9fs_put_idpool(newfid, &v9ses->fidpool); - else - dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", - FCALL_ERROR(fcall)); - kfree(fcall); - fid->fidopen = 0; - fid->fidcreate = 0; - d_drop(file_dentry); - } - return 0; CleanUpFid: kfree(fcall); + fcall = NULL; if (newfid >= 0) { - if (!v9fs_t_clunk(v9ses, newfid, &fcall)) - v9fs_put_idpool(newfid, &v9ses->fidpool); - else - dprintk(DEBUG_ERROR, "clunk failed: %s\n", - FCALL_ERROR(fcall)); - - kfree(fcall); + err = v9fs_t_clunk(v9ses, newfid); + if (err < 0) + dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); } if (wfidno >= 0) { - if (!v9fs_t_clunk(v9ses, wfidno, &fcall)) - v9fs_put_idpool(wfidno, &v9ses->fidpool); - else - dprintk(DEBUG_ERROR, "clunk failed: %s\n", - FCALL_ERROR(fcall)); - - kfree(fcall); + err = v9fs_t_clunk(v9ses, wfidno); + if (err < 0) + dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); } return result; } @@ -972,6 +963,7 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); struct v9fs_fcall *fcall = NULL; struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + int err; dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, symname); @@ -1004,9 +996,9 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) kfree(fcall); - if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { - dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", - FCALL_ERROR(fcall)); + err = v9fs_t_clunk(v9ses, newfid->fid); + if (err < 0) { + dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); goto FreeFcall; } @@ -1180,6 +1172,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); struct v9fs_fid *newfid = NULL; char *symname = __getname(); + int err; dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, old_dentry->d_name.name); @@ -1216,9 +1209,10 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, kfree(fcall); - if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { - dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", - FCALL_ERROR(fcall)); + err = v9fs_t_clunk(v9ses, newfid->fid); + + if (err < 0) { + dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); goto FreeMem; } @@ -1252,6 +1246,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) struct v9fs_fcall *fcall = NULL; struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); char *symname = __getname(); + int err; dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); @@ -1310,9 +1305,9 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) /* need to update dcache so we show up */ kfree(fcall); - if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { - dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", - FCALL_ERROR(fcall)); + err = v9fs_t_clunk(v9ses, newfid->fid); + if (err < 0) { + dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); goto FreeMem; } diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 82c5b0084079..83b6edd0988a 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -129,6 +129,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { dprintk(DEBUG_ERROR, "problem initiating session\n"); + kfree(v9ses); return ERR_PTR(newfid); } @@ -157,7 +158,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type stat_result = v9fs_t_stat(v9ses, newfid, &fcall); if (stat_result < 0) { dprintk(DEBUG_ERROR, "stat error\n"); - v9fs_t_clunk(v9ses, newfid, NULL); + v9fs_t_clunk(v9ses, newfid); v9fs_put_idpool(newfid, &v9ses->fidpool); } else { /* Setup the Root Inode */ -- cgit v1.2.3 From d8da097afb765654c866062148fd98b11db9003e Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Sun, 8 Jan 2006 01:04:59 -0800 Subject: [PATCH] v9fs: fix fid management in v9fs_create v9fs_create doesn't manage correctly the fids when it is called to create a directory.. The fid created by the create 9P call (newfid) and the one created by walking to already created file (wfidno) are not used consistently. This patch cleans up the usage of newfid and wfidno. Signed-off-by: Latchesar Ionkov Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/vfs_inode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 466002a1fe32..f11edde6432e 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -385,13 +385,14 @@ v9fs_create(struct inode *dir, fid->iounit = iounit; } else { err = v9fs_t_clunk(v9ses, newfid); + newfid = -1; if (err < 0) dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err); } /* walk to the newly created file and put the fid in the dentry */ wfidno = v9fs_get_idpool(&v9ses->fidpool); - if (newfid < 0) { + if (wfidno < 0) { eprintk(KERN_WARNING, "no free fids available\n"); return -ENOSPC; } @@ -408,7 +409,6 @@ v9fs_create(struct inode *dir, fcall = NULL; if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { - v9fs_t_clunk(v9ses, newfid); v9fs_put_idpool(wfidno, &v9ses->fidpool); goto CleanUpFid; @@ -419,7 +419,7 @@ v9fs_create(struct inode *dir, (perm & V9FS_DMDEVICE)) return 0; - result = v9fs_t_stat(v9ses, newfid, &fcall); + result = v9fs_t_stat(v9ses, wfidno, &fcall); if (result < 0) { dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall), result); -- cgit v1.2.3 From 42650d8c9060a2658a79d4e30a5790b23d7753e0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 20 Dec 2005 18:43:52 +1100 Subject: powerpc: Fix some #ifndef __KERNEL__ that should be #ifdef Grrr.... Signed-off-by: Paul Mackerras --- include/asm-powerpc/heathrow.h | 2 +- include/asm-powerpc/ohare.h | 2 +- include/asm-powerpc/seccomp.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-powerpc/heathrow.h b/include/asm-powerpc/heathrow.h index 470ab7be20a2..93f54958a9d1 100644 --- a/include/asm-powerpc/heathrow.h +++ b/include/asm-powerpc/heathrow.h @@ -1,6 +1,6 @@ #ifndef _ASM_POWERPC_HEATHROW_H #define _ASM_POWERPC_HEATHROW_H -#ifndef __KERNEL__ +#ifdef __KERNEL__ /* * heathrow.h: definitions for using the "Heathrow" I/O controller chip. * diff --git a/include/asm-powerpc/ohare.h b/include/asm-powerpc/ohare.h index b42037cf4ad0..0d030f9dea24 100644 --- a/include/asm-powerpc/ohare.h +++ b/include/asm-powerpc/ohare.h @@ -1,6 +1,6 @@ #ifndef _ASM_POWERPC_OHARE_H #define _ASM_POWERPC_OHARE_H -#ifndef __KERNEL__ +#ifdef __KERNEL__ /* * ohare.h: definitions for using the "O'Hare" I/O controller chip. * diff --git a/include/asm-powerpc/seccomp.h b/include/asm-powerpc/seccomp.h index cc8137b77b90..853765eb1f65 100644 --- a/include/asm-powerpc/seccomp.h +++ b/include/asm-powerpc/seccomp.h @@ -1,7 +1,7 @@ #ifndef _ASM_POWERPC_SECCOMP_H #define _ASM_POWERPC_SECCOMP_H -#ifndef __KERNEL__ +#ifdef __KERNEL__ #include #endif -- cgit v1.2.3 From 531b1094b74365dcc55fa464d28a9a2497ae825d Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Sun, 8 Jan 2006 01:05:00 -0800 Subject: [PATCH] v9fs: zero copy implementation Performance enhancement reducing the number of copies in the data and stat paths. Signed-off-by: Latchesar Ionkov Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/9p.c | 302 ++++++++++-------- fs/9p/9p.h | 75 +++-- fs/9p/Makefile | 10 +- fs/9p/conv.c | 895 +++++++++++++++++++++++++++++++---------------------- fs/9p/conv.h | 28 +- fs/9p/debug.h | 23 +- fs/9p/error.c | 10 +- fs/9p/error.h | 3 +- fs/9p/fid.c | 3 - fs/9p/mux.c | 157 +++++----- fs/9p/trans_sock.c | 1 - fs/9p/v9fs.c | 3 +- fs/9p/v9fs_vfs.h | 5 +- fs/9p/vfs_dentry.c | 4 +- fs/9p/vfs_dir.c | 31 +- fs/9p/vfs_file.c | 25 +- fs/9p/vfs_inode.c | 545 +++++++++++--------------------- fs/9p/vfs_super.c | 10 +- 18 files changed, 1083 insertions(+), 1047 deletions(-) diff --git a/fs/9p/9p.c b/fs/9p/9p.c index a3a1ac610723..dc3ce44ec836 100644 --- a/fs/9p/9p.c +++ b/fs/9p/9p.c @@ -1,8 +1,9 @@ /* * linux/fs/9p/9p.c * - * This file contains functions 9P2000 functions + * This file contains functions to perform synchronous 9P calls * + * Copyright (C) 2004 by Latchesar Ionkov * Copyright (C) 2004 by Eric Van Hensbergen * Copyright (C) 2002 by Ron Minnich * @@ -33,6 +34,7 @@ #include "debug.h" #include "v9fs.h" #include "9p.h" +#include "conv.h" #include "mux.h" /** @@ -46,17 +48,21 @@ int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, - char *version, struct v9fs_fcall **fcall) + char *version, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version); - msg.id = TVERSION; - msg.tag = ~0; - msg.params.tversion.msize = msize; - msg.params.tversion.version = version; + tc = v9fs_create_tversion(msize, version); - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } /** @@ -72,19 +78,23 @@ v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, - u32 fid, u32 afid, struct v9fs_fcall **fcall) + u32 fid, u32 afid, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall* tc; dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname, aname, fid, afid); - msg.id = TATTACH; - msg.params.tattach.fid = fid; - msg.params.tattach.afid = afid; - msg.params.tattach.uname = uname; - msg.params.tattach.aname = aname; - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + ret = -ENOMEM; + tc = v9fs_create_tattach(fid, afid, uname, aname); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, @@ -117,24 +127,28 @@ static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc, * @fcall: pointer to response fcall pointer * */ + int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid) { - int err; + int ret; struct v9fs_fcall *tc, *rc; - tc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL); - dprintk(DEBUG_9P, "fid %d\n", fid); - tc->id = TCLUNK; - tc->params.tclunk.fid = fid; - err = v9fs_mux_rpc(v9ses->mux, tc, &rc); - if (err >= 0) { - v9fs_t_clunk_cb(v9ses, tc, rc, 0); - } + ret = -ENOMEM; + rc = NULL; + tc = v9fs_create_tclunk(fid); + if (!IS_ERR(tc)) + ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); + else + ret = PTR_ERR(tc); + + if (ret) + dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret); - return err; + v9fs_t_clunk_cb(v9ses, tc, rc, ret); + return ret; } /** @@ -144,14 +158,22 @@ v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid) * */ -int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag) +int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; - dprintk(DEBUG_9P, "oldtag %d\n", tag); - msg.id = TFLUSH; - msg.params.tflush.oldtag = tag; - return v9fs_mux_rpc(v9ses->mux, &msg, NULL); + dprintk(DEBUG_9P, "oldtag %d\n", oldtag); + + ret = -ENOMEM; + tc = v9fs_create_tflush(oldtag); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, NULL); + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } /** @@ -163,17 +185,22 @@ int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag) */ int -v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall) +v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; dprintk(DEBUG_9P, "fid %d\n", fid); - if (fcall) - *fcall = NULL; - msg.id = TSTAT; - msg.params.tstat.fid = fid; - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + ret = -ENOMEM; + tc = v9fs_create_tstat(fid); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } /** @@ -187,16 +214,22 @@ v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall) int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, - struct v9fs_stat *stat, struct v9fs_fcall **fcall) + struct v9fs_wstat *wstat, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; - dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length); - msg.id = TWSTAT; - msg.params.twstat.fid = fid; - msg.params.twstat.stat = stat; + dprintk(DEBUG_9P, "fid %d\n", fid); + + ret = -ENOMEM; + tc = v9fs_create_twstat(fid, wstat, v9ses->extended); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + return ret; } /** @@ -213,23 +246,28 @@ v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, - char *name, struct v9fs_fcall **fcall) + char *name, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; + int nwname; dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name); - msg.id = TWALK; - msg.params.twalk.fid = fid; - msg.params.twalk.newfid = newfid; - - if (name) { - msg.params.twalk.nwname = 1; - msg.params.twalk.wnames = &name; - } else { - msg.params.twalk.nwname = 0; - } - - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + + if (name) + nwname = 1; + else + nwname = 0; + + ret = -ENOMEM; + tc = v9fs_create_twalk(fid, newfid, nwname, &name); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } /** @@ -244,19 +282,22 @@ v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, - struct v9fs_fcall **fcall) + struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; - int errorno = -1; + int ret; + struct v9fs_fcall *tc; dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode); - msg.id = TOPEN; - msg.params.topen.fid = fid; - msg.params.topen.mode = mode; - errorno = v9fs_mux_rpc(v9ses->mux, &msg, fcall); + ret = -ENOMEM; + tc = v9fs_create_topen(fid, mode); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); - return errorno; + return ret; } /** @@ -269,14 +310,22 @@ v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, - struct v9fs_fcall **fcall) + struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; dprintk(DEBUG_9P, "fid %d\n", fid); - msg.id = TREMOVE; - msg.params.tremove.fid = fid; - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + + ret = -ENOMEM; + tc = v9fs_create_tremove(fid); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } /** @@ -292,20 +341,23 @@ v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, - u32 perm, u8 mode, struct v9fs_fcall **fcall) + u32 perm, u8 mode, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; + int ret; + struct v9fs_fcall *tc; dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n", fid, name, perm, mode); - msg.id = TCREATE; - msg.params.tcreate.fid = fid; - msg.params.tcreate.name = name; - msg.params.tcreate.perm = perm; - msg.params.tcreate.mode = mode; + ret = -ENOMEM; + tc = v9fs_create_tcreate(fid, name, perm, mode); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); + kfree(tc); + } else + ret = PTR_ERR(tc); - return v9fs_mux_rpc(v9ses->mux, &msg, fcall); + return ret; } /** @@ -320,31 +372,30 @@ v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, - u32 count, struct v9fs_fcall **fcall) + u32 count, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; - struct v9fs_fcall *rc = NULL; - long errorno = -1; - - dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid, - (long unsigned int)offset, count); - msg.id = TREAD; - msg.params.tread.fid = fid; - msg.params.tread.offset = offset; - msg.params.tread.count = count; - errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc); - - if (!errorno) { - errorno = rc->params.rread.count; - dump_data(rc->params.rread.data, rc->params.rread.count); - } - - if (fcall) - *fcall = rc; - else - kfree(rc); + int ret; + struct v9fs_fcall *tc, *rc; - return errorno; + dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid, + (long long unsigned) offset, count); + + ret = -ENOMEM; + tc = v9fs_create_tread(fid, offset, count); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); + if (!ret) + ret = rc->params.rread.count; + if (rcp) + *rcp = rc; + else + kfree(rc); + + kfree(tc); + } else + ret = PTR_ERR(tc); + + return ret; } /** @@ -358,32 +409,31 @@ v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, */ int -v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, - u64 offset, u32 count, void *data, struct v9fs_fcall **fcall) +v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count, + const char __user *data, struct v9fs_fcall **rcp) { - struct v9fs_fcall msg; - struct v9fs_fcall *rc = NULL; - long errorno = -1; + int ret; + struct v9fs_fcall *tc, *rc; - dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid, - (unsigned long long)offset, count); - dump_data(data, count); + dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid, + (long long unsigned) offset, count); - msg.id = TWRITE; - msg.params.twrite.fid = fid; - msg.params.twrite.offset = offset; - msg.params.twrite.count = count; - msg.params.twrite.data = data; + ret = -ENOMEM; + tc = v9fs_create_twrite(fid, offset, count, data); + if (!IS_ERR(tc)) { + ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); - errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc); + if (!ret) + ret = rc->params.rwrite.count; + if (rcp) + *rcp = rc; + else + kfree(rc); - if (!errorno) - errorno = rc->params.rwrite.count; + kfree(tc); + } else + ret = PTR_ERR(tc); - if (fcall) - *fcall = rc; - else - kfree(rc); - - return errorno; + return ret; } + diff --git a/fs/9p/9p.h b/fs/9p/9p.h index 6355392786e2..007ff639777d 100644 --- a/fs/9p/9p.h +++ b/fs/9p/9p.h @@ -3,6 +3,7 @@ * * 9P protocol definitions. * + * Copyright (C) 2005 by Latchesar Ionkov * Copyright (C) 2004 by Eric Van Hensbergen * Copyright (C) 2002 by Ron Minnich * @@ -102,10 +103,16 @@ enum { #define V9FS_NOTAG (u16)(~0) #define V9FS_NOFID (u32)(~0) +#define V9FS_MAXWELEM 16 /* ample room for Twrite/Rread header (iounit) */ #define V9FS_IOHDRSZ 24 +struct v9fs_str { + u16 len; + char *str; +}; + /* qids are the unique ID for a file (like an inode */ struct v9fs_qid { u8 type; @@ -115,6 +122,29 @@ struct v9fs_qid { /* Plan 9 file metadata (stat) structure */ struct v9fs_stat { + u16 size; + u16 type; + u32 dev; + struct v9fs_qid qid; + u32 mode; + u32 atime; + u32 mtime; + u64 length; + struct v9fs_str name; + struct v9fs_str uid; + struct v9fs_str gid; + struct v9fs_str muid; + struct v9fs_str extension; /* 9p2000.u extensions */ + u32 n_uid; /* 9p2000.u extensions */ + u32 n_gid; /* 9p2000.u extensions */ + u32 n_muid; /* 9p2000.u extensions */ +}; + +/* file metadata (stat) structure used to create Twstat message + The is similar to v9fs_stat, but the strings don't point to + the same memory block and should be freed separately +*/ +struct v9fs_wstat { u16 size; u16 type; u32 dev; @@ -131,25 +161,24 @@ struct v9fs_stat { u32 n_uid; /* 9p2000.u extensions */ u32 n_gid; /* 9p2000.u extensions */ u32 n_muid; /* 9p2000.u extensions */ - char data[0]; }; /* Structures for Protocol Operations */ struct Tversion { u32 msize; - char *version; + struct v9fs_str version; }; struct Rversion { u32 msize; - char *version; + struct v9fs_str version; }; struct Tauth { u32 afid; - char *uname; - char *aname; + struct v9fs_str uname; + struct v9fs_str aname; }; struct Rauth { @@ -157,12 +186,12 @@ struct Rauth { }; struct Rerror { - char *error; + struct v9fs_str error; u32 errno; /* 9p2000.u extension */ }; struct Tflush { - u32 oldtag; + u16 oldtag; }; struct Rflush { @@ -171,8 +200,8 @@ struct Rflush { struct Tattach { u32 fid; u32 afid; - char *uname; - char *aname; + struct v9fs_str uname; + struct v9fs_str aname; }; struct Rattach { @@ -182,13 +211,13 @@ struct Rattach { struct Twalk { u32 fid; u32 newfid; - u32 nwname; - char **wnames; + u16 nwname; + struct v9fs_str wnames[16]; }; struct Rwalk { - u32 nwqid; - struct v9fs_qid *wqids; + u16 nwqid; + struct v9fs_qid wqids[16]; }; struct Topen { @@ -203,7 +232,7 @@ struct Ropen { struct Tcreate { u32 fid; - char *name; + struct v9fs_str name; u32 perm; u8 mode; }; @@ -254,12 +283,12 @@ struct Tstat { }; struct Rstat { - struct v9fs_stat *stat; + struct v9fs_stat stat; }; struct Twstat { u32 fid; - struct v9fs_stat *stat; + struct v9fs_stat stat; }; struct Rwstat { @@ -274,6 +303,7 @@ struct v9fs_fcall { u32 size; u8 id; u16 tag; + void *sdata; union { struct Tversion tversion; @@ -306,10 +336,12 @@ struct v9fs_fcall { } params; }; -#define V9FS_FCALLHDRSZ (sizeof(struct v9fs_fcall) + \ - sizeof(struct v9fs_stat) + 16*sizeof(struct v9fs_qid) + 16) +#define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \ + fcall?fcall->params.rerror.error.len:0, \ + fcall?fcall->params.rerror.error.str:""); -#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "") +char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str); +int v9fs_str_compare(char *buf, struct v9fs_str *str); int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, char *version, struct v9fs_fcall **rcall); @@ -325,7 +357,7 @@ int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcall); int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, - struct v9fs_stat *stat, struct v9fs_fcall **rcall); + struct v9fs_wstat *wstat, struct v9fs_fcall **rcall); int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, char *name, struct v9fs_fcall **rcall); @@ -343,4 +375,5 @@ int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count, struct v9fs_fcall **rcall); int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, - u32 count, void *data, struct v9fs_fcall **rcall); + u32 count, const char __user * data, + struct v9fs_fcall **rcall); diff --git a/fs/9p/Makefile b/fs/9p/Makefile index e4e4ffe5a7dc..3d023089707e 100644 --- a/fs/9p/Makefile +++ b/fs/9p/Makefile @@ -1,17 +1,17 @@ obj-$(CONFIG_9P_FS) := 9p2000.o 9p2000-objs := \ + trans_fd.o \ + trans_sock.o \ + mux.o \ + 9p.o \ + conv.o \ vfs_super.o \ vfs_inode.o \ vfs_file.o \ vfs_dir.o \ vfs_dentry.o \ error.o \ - mux.o \ - trans_fd.o \ - trans_sock.o \ - 9p.o \ - conv.o \ v9fs.o \ fid.o diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 1b9b15dfeaf0..f62434d435b3 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -30,7 +30,7 @@ #include #include #include - +#include #include "debug.h" #include "v9fs.h" #include "9p.h" @@ -45,6 +45,37 @@ struct cbuf { unsigned char *ep; }; +char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str) +{ + int n; + + if (buflen < str->len) + n = buflen; + else + n = str->len; + + memmove(buf, str->str, n - 1); + + return buf; +} + +int v9fs_str_compare(char *buf, struct v9fs_str *str) +{ + int n, ret; + + ret = strncmp(buf, str->str, str->len); + + if (!ret) { + n = strlen(buf); + if (n < str->len) + ret = -1; + else if (n > str->len) + ret = 1; + } + + return ret; +} + static inline void buf_init(struct cbuf *buf, void *data, int datalen) { buf->sp = buf->p = data; @@ -58,12 +89,12 @@ static inline int buf_check_overflow(struct cbuf *buf) static inline int buf_check_size(struct cbuf *buf, int len) { - if (buf->p+len > buf->ep) { - if (buf->p < buf->ep) { - eprintk(KERN_ERR, "buffer overflow\n"); - buf->p = buf->ep + 1; - return 0; - } + if (buf->p + len > buf->ep && buf->p < buf->ep) { + eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", + len, (int)(buf->ep - buf->p)); + dump_stack(); + buf->p = buf->ep + 1; + return 0; } return 1; @@ -127,14 +158,6 @@ static inline void buf_put_string(struct cbuf *buf, const char *s) buf_put_stringn(buf, s, strlen(s)); } -static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) -{ - if (buf_check_size(buf, datalen)) { - memcpy(buf->p, data, datalen); - buf->p += datalen; - } -} - static inline u8 buf_get_int8(struct cbuf *buf) { u8 ret = 0; @@ -183,85 +206,37 @@ static inline u64 buf_get_int64(struct cbuf *buf) return ret; } -static inline int -buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) -{ - u16 len = 0; - - len = buf_get_int16(buf); - if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) { - memcpy(data, buf->p, len); - data[len] = 0; - buf->p += len; - len++; - } - - return len; -} - -static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) -{ - char *ret; - u16 len; - - ret = NULL; - len = buf_get_int16(buf); - - if (!buf_check_overflow(buf) && buf_check_size(buf, len) && - buf_check_size(sbuf, len + 1)) { - - memcpy(sbuf->p, buf->p, len); - sbuf->p[len] = 0; - ret = sbuf->p; - buf->p += len; - sbuf->p += len + 1; - } - - return ret; -} - -static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) +static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr) { - int ret = 0; - - if (buf_check_size(buf, datalen)) { - memcpy(data, buf->p, datalen); - buf->p += datalen; - ret = datalen; + vstr->len = buf_get_int16(buf); + if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { + vstr->str = buf->p; + buf->p += vstr->len; + } else { + vstr->len = 0; + vstr->str = NULL; } - - return ret; } -static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, - int datalen) +static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid) { - char *ret = NULL; - int n = 0; - - if (buf_check_size(dbuf, datalen)) { - n = buf_get_data(buf, dbuf->p, datalen); - if (n > 0) { - ret = dbuf->p; - dbuf->p += n; - } - } - - return ret; + qid->type = buf_get_int8(bufp); + qid->version = buf_get_int32(bufp); + qid->path = buf_get_int64(bufp); } /** - * v9fs_size_stat - calculate the size of a variable length stat struct + * v9fs_size_wstat - calculate the size of a variable length stat struct * @stat: metadata (stat) structure * @extended: non-zero if 9P2000.u * */ -static int v9fs_size_stat(struct v9fs_stat *stat, int extended) +static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended) { int size = 0; - if (stat == NULL) { + if (wstat == NULL) { eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); return 0; } @@ -278,81 +253,38 @@ static int v9fs_size_stat(struct v9fs_stat *stat, int extended) 8 + /* length[8] */ 8; /* minimum sum of string lengths */ - if (stat->name) - size += strlen(stat->name); - if (stat->uid) - size += strlen(stat->uid); - if (stat->gid) - size += strlen(stat->gid); - if (stat->muid) - size += strlen(stat->muid); + if (wstat->name) + size += strlen(wstat->name); + if (wstat->uid) + size += strlen(wstat->uid); + if (wstat->gid) + size += strlen(wstat->gid); + if (wstat->muid) + size += strlen(wstat->muid); if (extended) { size += 4 + /* n_uid[4] */ 4 + /* n_gid[4] */ 4 + /* n_muid[4] */ 2; /* string length of extension[4] */ - if (stat->extension) - size += strlen(stat->extension); + if (wstat->extension) + size += strlen(wstat->extension); } return size; } /** - * serialize_stat - safely format a stat structure for transmission - * @stat: metadata (stat) structure - * @bufp: buffer to serialize structure into - * @extended: non-zero if 9P2000.u - * - */ - -static int -serialize_stat(struct v9fs_stat *stat, struct cbuf *bufp, int extended) -{ - buf_put_int16(bufp, stat->size); - buf_put_int16(bufp, stat->type); - buf_put_int32(bufp, stat->dev); - buf_put_int8(bufp, stat->qid.type); - buf_put_int32(bufp, stat->qid.version); - buf_put_int64(bufp, stat->qid.path); - buf_put_int32(bufp, stat->mode); - buf_put_int32(bufp, stat->atime); - buf_put_int32(bufp, stat->mtime); - buf_put_int64(bufp, stat->length); - - buf_put_string(bufp, stat->name); - buf_put_string(bufp, stat->uid); - buf_put_string(bufp, stat->gid); - buf_put_string(bufp, stat->muid); - - if (extended) { - buf_put_string(bufp, stat->extension); - buf_put_int32(bufp, stat->n_uid); - buf_put_int32(bufp, stat->n_gid); - buf_put_int32(bufp, stat->n_muid); - } - - if (buf_check_overflow(bufp)) - return 0; - - return stat->size; -} - -/** - * deserialize_stat - safely decode a recieved metadata (stat) structure + * buf_get_stat - safely decode a recieved metadata (stat) structure * @bufp: buffer to deserialize * @stat: metadata (stat) structure - * @dbufp: buffer to deserialize variable strings into * @extended: non-zero if 9P2000.u * */ -static inline int -deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat, - struct cbuf *dbufp, int extended) +static inline void +buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended) { - stat->size = buf_get_int16(bufp); stat->type = buf_get_int16(bufp); stat->dev = buf_get_int32(bufp); @@ -363,45 +295,17 @@ deserialize_stat(struct cbuf *bufp, struct v9fs_stat *stat, stat->atime = buf_get_int32(bufp); stat->mtime = buf_get_int32(bufp); stat->length = buf_get_int64(bufp); - stat->name = buf_get_stringb(bufp, dbufp); - stat->uid = buf_get_stringb(bufp, dbufp); - stat->gid = buf_get_stringb(bufp, dbufp); - stat->muid = buf_get_stringb(bufp, dbufp); + buf_get_str(bufp, &stat->name); + buf_get_str(bufp, &stat->uid); + buf_get_str(bufp, &stat->gid); + buf_get_str(bufp, &stat->muid); if (extended) { - stat->extension = buf_get_stringb(bufp, dbufp); + buf_get_str(bufp, &stat->extension); stat->n_uid = buf_get_int32(bufp); stat->n_gid = buf_get_int32(bufp); stat->n_muid = buf_get_int32(bufp); } - - if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) - return 0; - - return stat->size + 2; -} - -/** - * deserialize_statb - wrapper for decoding a received metadata structure - * @bufp: buffer to deserialize - * @dbufp: buffer to deserialize variable strings into - * @extended: non-zero if 9P2000.u - * - */ - -static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp, - struct cbuf *dbufp, - int extended) -{ - struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat)); - - if (ret) { - int n = deserialize_stat(bufp, ret, dbufp, extended); - if (n <= 0) - return NULL; - } - - return ret; } /** @@ -409,194 +313,27 @@ static inline struct v9fs_stat *deserialize_statb(struct cbuf *bufp, * @buf: buffer to deserialize * @buflen: length of received buffer * @stat: metadata structure to decode into - * @statlen: length of destination metadata structure * @extended: non-zero if 9P2000.u * + * Note: stat will point to the buf region. */ -int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, - u32 statlen, int extended) +int +v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, + int extended) { struct cbuf buffer; struct cbuf *bufp = &buffer; - struct cbuf dbuffer; - struct cbuf *dbufp = &dbuffer; + unsigned char *p; buf_init(bufp, buf, buflen); - buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), - statlen - sizeof(struct v9fs_stat)); - - return deserialize_stat(bufp, stat, dbufp, extended); -} - -static inline int v9fs_size_fcall(struct v9fs_fcall *fcall, int extended) -{ - int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */ - int i = 0; + p = bufp->p; + buf_get_stat(bufp, stat, extended); - switch (fcall->id) { - default: - eprintk(KERN_ERR, "bad msg type %d\n", fcall->id); + if (buf_check_overflow(bufp)) return 0; - case TVERSION: /* msize[4] version[s] */ - size += 4 + 2 + strlen(fcall->params.tversion.version); - break; - case TAUTH: /* afid[4] uname[s] aname[s] */ - size += 4 + 2 + strlen(fcall->params.tauth.uname) + - 2 + strlen(fcall->params.tauth.aname); - break; - case TFLUSH: /* oldtag[2] */ - size += 2; - break; - case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */ - size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) + - 2 + strlen(fcall->params.tattach.aname); - break; - case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ - size += 4 + 4 + 2; - /* now compute total for the array of names */ - for (i = 0; i < fcall->params.twalk.nwname; i++) - size += 2 + strlen(fcall->params.twalk.wnames[i]); - break; - case TOPEN: /* fid[4] mode[1] */ - size += 4 + 1; - break; - case TCREATE: /* fid[4] name[s] perm[4] mode[1] */ - size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1; - break; - case TREAD: /* fid[4] offset[8] count[4] */ - size += 4 + 8 + 4; - break; - case TWRITE: /* fid[4] offset[8] count[4] data[count] */ - size += 4 + 8 + 4 + fcall->params.twrite.count; - break; - case TCLUNK: /* fid[4] */ - size += 4; - break; - case TREMOVE: /* fid[4] */ - size += 4; - break; - case TSTAT: /* fid[4] */ - size += 4; - break; - case TWSTAT: /* fid[4] stat[n] */ - fcall->params.twstat.stat->size = - v9fs_size_stat(fcall->params.twstat.stat, extended); - size += 4 + 2 + 2 + fcall->params.twstat.stat->size; - } - return size; -} - -/* - * v9fs_serialize_fcall - marshall fcall struct into a packet - * @fcall: structure to convert - * @data: buffer to serialize fcall into - * @datalen: length of buffer to serialize fcall into - * @extended: non-zero if 9P2000.u - * - */ - -int -v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen, - int extended) -{ - int i = 0; - struct v9fs_stat *stat = NULL; - struct cbuf buffer; - struct cbuf *bufp = &buffer; - - buf_init(bufp, data, datalen); - - if (!fcall) { - eprintk(KERN_ERR, "no fcall\n"); - return -EINVAL; - } - - fcall->size = v9fs_size_fcall(fcall, extended); - - buf_put_int32(bufp, fcall->size); - buf_put_int8(bufp, fcall->id); - buf_put_int16(bufp, fcall->tag); - - dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id, - fcall->tag); - - /* now encode it */ - switch (fcall->id) { - default: - eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id); - return -EPROTO; - case TVERSION: - buf_put_int32(bufp, fcall->params.tversion.msize); - buf_put_string(bufp, fcall->params.tversion.version); - break; - case TAUTH: - buf_put_int32(bufp, fcall->params.tauth.afid); - buf_put_string(bufp, fcall->params.tauth.uname); - buf_put_string(bufp, fcall->params.tauth.aname); - break; - case TFLUSH: - buf_put_int16(bufp, fcall->params.tflush.oldtag); - break; - case TATTACH: - buf_put_int32(bufp, fcall->params.tattach.fid); - buf_put_int32(bufp, fcall->params.tattach.afid); - buf_put_string(bufp, fcall->params.tattach.uname); - buf_put_string(bufp, fcall->params.tattach.aname); - break; - case TWALK: - buf_put_int32(bufp, fcall->params.twalk.fid); - buf_put_int32(bufp, fcall->params.twalk.newfid); - buf_put_int16(bufp, fcall->params.twalk.nwname); - for (i = 0; i < fcall->params.twalk.nwname; i++) - buf_put_string(bufp, fcall->params.twalk.wnames[i]); - break; - case TOPEN: - buf_put_int32(bufp, fcall->params.topen.fid); - buf_put_int8(bufp, fcall->params.topen.mode); - break; - case TCREATE: - buf_put_int32(bufp, fcall->params.tcreate.fid); - buf_put_string(bufp, fcall->params.tcreate.name); - buf_put_int32(bufp, fcall->params.tcreate.perm); - buf_put_int8(bufp, fcall->params.tcreate.mode); - break; - case TREAD: - buf_put_int32(bufp, fcall->params.tread.fid); - buf_put_int64(bufp, fcall->params.tread.offset); - buf_put_int32(bufp, fcall->params.tread.count); - break; - case TWRITE: - buf_put_int32(bufp, fcall->params.twrite.fid); - buf_put_int64(bufp, fcall->params.twrite.offset); - buf_put_int32(bufp, fcall->params.twrite.count); - buf_put_data(bufp, fcall->params.twrite.data, - fcall->params.twrite.count); - break; - case TCLUNK: - buf_put_int32(bufp, fcall->params.tclunk.fid); - break; - case TREMOVE: - buf_put_int32(bufp, fcall->params.tremove.fid); - break; - case TSTAT: - buf_put_int32(bufp, fcall->params.tstat.fid); - break; - case TWSTAT: - buf_put_int32(bufp, fcall->params.twstat.fid); - stat = fcall->params.twstat.stat; - - buf_put_int16(bufp, stat->size + 2); - serialize_stat(stat, bufp, extended); - break; - } - - if (buf_check_overflow(bufp)) { - dprintk(DEBUG_ERROR, "buffer overflow\n"); - return -EIO; - } - - return fcall->size; + else + return bufp->p - p; } /** @@ -611,18 +348,14 @@ v9fs_serialize_fcall(struct v9fs_fcall *fcall, void *data, u32 datalen, int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, - int rcalllen, int extended) + int extended) { struct cbuf buffer; struct cbuf *bufp = &buffer; - struct cbuf dbuffer; - struct cbuf *dbufp = &dbuffer; int i = 0; buf_init(bufp, buf, buflen); - buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall), - rcalllen - sizeof(struct v9fs_fcall)); rcall->size = buf_get_int32(bufp); rcall->id = buf_get_int8(bufp); @@ -630,13 +363,14 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, rcall->tag); + switch (rcall->id) { default: eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); return -EPROTO; case RVERSION: rcall->params.rversion.msize = buf_get_int32(bufp); - rcall->params.rversion.version = buf_get_stringb(bufp, dbufp); + buf_get_str(bufp, &rcall->params.rversion.version); break; case RFLUSH: break; @@ -647,40 +381,27 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, break; case RWALK: rcall->params.rwalk.nwqid = buf_get_int16(bufp); - if (rcall->params.rwalk.nwqid > 16) { - eprintk(KERN_ERR, "Rwalk with more than 16 qids: %d\n", - rcall->params.rwalk.nwqid); + if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) { + eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n", + V9FS_MAXWELEM, rcall->params.rwalk.nwqid); return -EPROTO; } - rcall->params.rwalk.wqids = buf_alloc(dbufp, - rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); - if (rcall->params.rwalk.wqids) - for (i = 0; i < rcall->params.rwalk.nwqid; i++) { - rcall->params.rwalk.wqids[i].type = - buf_get_int8(bufp); - rcall->params.rwalk.wqids[i].version = - buf_get_int16(bufp); - rcall->params.rwalk.wqids[i].path = - buf_get_int64(bufp); - } + for (i = 0; i < rcall->params.rwalk.nwqid; i++) + buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); break; case ROPEN: - rcall->params.ropen.qid.type = buf_get_int8(bufp); - rcall->params.ropen.qid.version = buf_get_int32(bufp); - rcall->params.ropen.qid.path = buf_get_int64(bufp); + buf_get_qid(bufp, &rcall->params.ropen.qid); rcall->params.ropen.iounit = buf_get_int32(bufp); break; case RCREATE: - rcall->params.rcreate.qid.type = buf_get_int8(bufp); - rcall->params.rcreate.qid.version = buf_get_int32(bufp); - rcall->params.rcreate.qid.path = buf_get_int64(bufp); + buf_get_qid(bufp, &rcall->params.rcreate.qid); rcall->params.rcreate.iounit = buf_get_int32(bufp); break; case RREAD: rcall->params.rread.count = buf_get_int32(bufp); - rcall->params.rread.data = buf_get_datab(bufp, dbufp, - rcall->params.rread.count); + rcall->params.rread.data = bufp->p; + buf_check_size(bufp, rcall->params.rread.count); break; case RWRITE: rcall->params.rwrite.count = buf_get_int32(bufp); @@ -691,22 +412,442 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, break; case RSTAT: buf_get_int16(bufp); - rcall->params.rstat.stat = - deserialize_statb(bufp, dbufp, extended); + buf_get_stat(bufp, &rcall->params.rstat.stat, extended); break; case RWSTAT: break; case RERROR: - rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); + buf_get_str(bufp, &rcall->params.rerror.error); if (extended) rcall->params.rerror.errno = buf_get_int16(bufp); break; } - if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) { + if (buf_check_overflow(bufp)) { dprintk(DEBUG_ERROR, "buffer overflow\n"); return -EIO; } - return rcall->size; + return bufp->p - bufp->sp; +} + +static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p) +{ + *p = val; + buf_put_int8(bufp, val); +} + +static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p) +{ + *p = val; + buf_put_int16(bufp, val); +} + +static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p) +{ + *p = val; + buf_put_int32(bufp, val); +} + +static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p) +{ + *p = val; + buf_put_int64(bufp, val); +} + +static inline void +v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str) +{ + if (data) { + str->len = strlen(data); + str->str = bufp->p; + } else { + str->len = 0; + str->str = NULL; + } + + buf_put_stringn(bufp, data, str->len); +} + +static inline int +v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count, + unsigned char **pdata) +{ + *pdata = buf_alloc(bufp, count); + return copy_from_user(*pdata, data, count); +} + +static void +v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat, + struct v9fs_stat *stat, int statsz, int extended) +{ + v9fs_put_int16(bufp, statsz, &stat->size); + v9fs_put_int16(bufp, wstat->type, &stat->type); + v9fs_put_int32(bufp, wstat->dev, &stat->dev); + v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type); + v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version); + v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path); + v9fs_put_int32(bufp, wstat->mode, &stat->mode); + v9fs_put_int32(bufp, wstat->atime, &stat->atime); + v9fs_put_int32(bufp, wstat->mtime, &stat->mtime); + v9fs_put_int64(bufp, wstat->length, &stat->length); + + v9fs_put_str(bufp, wstat->name, &stat->name); + v9fs_put_str(bufp, wstat->uid, &stat->uid); + v9fs_put_str(bufp, wstat->gid, &stat->gid); + v9fs_put_str(bufp, wstat->muid, &stat->muid); + + if (extended) { + v9fs_put_str(bufp, wstat->extension, &stat->extension); + v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid); + v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid); + v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid); + } +} + +static struct v9fs_fcall * +v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) +{ + struct v9fs_fcall *fc; + + size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ + fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL); + if (!fc) + return ERR_PTR(-ENOMEM); + + fc->sdata = (char *)fc + sizeof(*fc); + + buf_init(bufp, (char *)fc->sdata, size); + v9fs_put_int32(bufp, size, &fc->size); + v9fs_put_int8(bufp, id, &fc->id); + v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag); + + return fc; +} + +void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) +{ + *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); +} + +struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 2 + strlen(version); /* msize[4] version[s] */ + fc = v9fs_create_common(bufp, size, TVERSION); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, msize, &fc->params.tversion.msize); + v9fs_put_str(bufp, version, &fc->params.tversion.version); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */ + fc = v9fs_create_common(bufp, size, TAUTH); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, afid, &fc->params.tauth.afid); + v9fs_put_str(bufp, uname, &fc->params.tauth.uname); + v9fs_put_str(bufp, aname, &fc->params.tauth.aname); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall * +v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */ + fc = v9fs_create_common(bufp, size, TATTACH); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.tattach.fid); + v9fs_put_int32(bufp, afid, &fc->params.tattach.afid); + v9fs_put_str(bufp, uname, &fc->params.tattach.uname); + v9fs_put_str(bufp, aname, &fc->params.tattach.aname); + + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tflush(u16 oldtag) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 2; /* oldtag[2] */ + fc = v9fs_create_common(bufp, size, TFLUSH); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, + char **wnames) +{ + int i, size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + if (nwname > V9FS_MAXWELEM) { + dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM); + return NULL; + } + + size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ + for (i = 0; i < nwname; i++) { + size += 2 + strlen(wnames[i]); /* wname[s] */ + } + + fc = v9fs_create_common(bufp, size, TWALK); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.twalk.fid); + v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid); + v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname); + for (i = 0; i < nwname; i++) { + v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); + } + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 1; /* fid[4] mode[1] */ + fc = v9fs_create_common(bufp, size, TOPEN); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.topen.fid); + v9fs_put_int8(bufp, mode, &fc->params.topen.mode); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */ + fc = v9fs_create_common(bufp, size, TCREATE); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid); + v9fs_put_str(bufp, name, &fc->params.tcreate.name); + v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm); + v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ + fc = v9fs_create_common(bufp, size, TREAD); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.tread.fid); + v9fs_put_int64(bufp, offset, &fc->params.tread.offset); + v9fs_put_int32(bufp, count, &fc->params.tread.count); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, + const char __user * data) +{ + int size, err; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */ + fc = v9fs_create_common(bufp, size, TWRITE); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.twrite.fid); + v9fs_put_int64(bufp, offset, &fc->params.twrite.offset); + v9fs_put_int32(bufp, count, &fc->params.twrite.count); + err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data); + if (err) { + kfree(fc); + fc = ERR_PTR(err); + } + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tclunk(u32 fid) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4; /* fid[4] */ + fc = v9fs_create_common(bufp, size, TCLUNK); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tremove(u32 fid) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4; /* fid[4] */ + fc = v9fs_create_common(bufp, size, TREMOVE); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.tremove.fid); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_tstat(u32 fid) +{ + int size; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + size = 4; /* fid[4] */ + fc = v9fs_create_common(bufp, size, TSTAT); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.tstat.fid); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; +} + +struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, + int extended) +{ + int size, statsz; + struct v9fs_fcall *fc; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + statsz = v9fs_size_wstat(wstat, extended); + size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ + fc = v9fs_create_common(bufp, size, TWSTAT); + if (IS_ERR(fc)) + goto error; + + v9fs_put_int32(bufp, fid, &fc->params.twstat.fid); + buf_put_int16(bufp, statsz + 2); + v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended); + + if (buf_check_overflow(bufp)) { + kfree(fc); + fc = ERR_PTR(-ENOMEM); + } + error: + return fc; } diff --git a/fs/9p/conv.h b/fs/9p/conv.h index d5e33e17a685..26a736e4a2e7 100644 --- a/fs/9p/conv.h +++ b/fs/9p/conv.h @@ -1,8 +1,9 @@ /* * linux/fs/9p/conv.h * - * 9P protocol conversion definitions + * 9P protocol conversion definitions. * + * Copyright (C) 2005 by Latchesar Ionkov * Copyright (C) 2004 by Eric Van Hensbergen * Copyright (C) 2002 by Ron Minnich * @@ -25,11 +26,26 @@ */ int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat, - u32 statlen, int extended); -int v9fs_serialize_fcall(struct v9fs_fcall *tcall, void *buf, u32 buflen, int extended); int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall, - int rcalllen, int extended); + int extended); + +void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag); -/* this one is actually in error.c right now */ -int v9fs_errstr2errno(char *errstr); +struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version); +struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname); +struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname, + char *aname); +struct v9fs_fcall *v9fs_create_tflush(u16 oldtag); +struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname, + char **wnames); +struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode); +struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode); +struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count); +struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count, + const char __user *data); +struct v9fs_fcall *v9fs_create_tclunk(u32 fid); +struct v9fs_fcall *v9fs_create_tremove(u32 fid); +struct v9fs_fcall *v9fs_create_tstat(u32 fid); +struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat, + int extended); diff --git a/fs/9p/debug.h b/fs/9p/debug.h index 4445f06919d9..fe551032788b 100644 --- a/fs/9p/debug.h +++ b/fs/9p/debug.h @@ -51,16 +51,23 @@ do { \ #if DEBUG_DUMP_PKT static inline void dump_data(const unsigned char *data, unsigned int datalen) { - int i, j; - int len = datalen; + int i, n; + char buf[5*8]; - printk(KERN_DEBUG "data "); - for (i = 0; i < len; i += 4) { - for (j = 0; (j < 4) && (i + j < len); j++) - printk(KERN_DEBUG "%02x", data[i + j]); - printk(KERN_DEBUG " "); + n = 0; + i = 0; + while (i < datalen) { + n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]); + if (i%4 == 0) + n += snprintf(buf+n, sizeof(buf)-n, " "); + + if (i%16 == 0) { + dprintk(DEBUG_ERROR, "%s\n", buf); + n = 0; + } } - printk(KERN_DEBUG "\n"); + + dprintk(DEBUG_ERROR, "%s\n", buf); } #else /* DEBUG_DUMP_PKT */ static inline void dump_data(const unsigned char *data, unsigned int datalen) diff --git a/fs/9p/error.c b/fs/9p/error.c index 834cb179e388..e4b6f8f38b6f 100644 --- a/fs/9p/error.c +++ b/fs/9p/error.c @@ -33,7 +33,6 @@ #include #include -#include #include "debug.h" #include "error.h" @@ -55,7 +54,8 @@ int v9fs_error_init(void) /* load initial error map into hash table */ for (c = errmap; c->name != NULL; c++) { - bucket = jhash(c->name, strlen(c->name), 0) % ERRHASHSZ; + c->namelen = strlen(c->name); + bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ; INIT_HLIST_NODE(&c->list); hlist_add_head(&c->list, &hash_errmap[bucket]); } @@ -69,15 +69,15 @@ int v9fs_error_init(void) * */ -int v9fs_errstr2errno(char *errstr) +int v9fs_errstr2errno(char *errstr, int len) { int errno = 0; struct hlist_node *p = NULL; struct errormap *c = NULL; - int bucket = jhash(errstr, strlen(errstr), 0) % ERRHASHSZ; + int bucket = jhash(errstr, len, 0) % ERRHASHSZ; hlist_for_each_entry(c, p, &hash_errmap[bucket], list) { - if (!strcmp(c->name, errstr)) { + if (c->namelen==len && !memcmp(c->name, errstr, len)) { errno = c->val; break; } diff --git a/fs/9p/error.h b/fs/9p/error.h index 78f89acf7c9a..8b3176b3f658 100644 --- a/fs/9p/error.h +++ b/fs/9p/error.h @@ -36,6 +36,7 @@ struct errormap { char *name; int val; + int namelen; struct hlist_node list; }; @@ -175,4 +176,4 @@ static struct errormap errmap[] = { }; extern int v9fs_error_init(void); -extern int v9fs_errstr2errno(char *errstr); +extern int v9fs_errstr2errno(char *errstr, int len); diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 60ef8aba757a..eda449778fa5 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -31,9 +31,6 @@ #include "v9fs.h" #include "9p.h" #include "v9fs_vfs.h" -#include "transport.h" -#include "mux.h" -#include "conv.h" #include "fid.h" /** diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 62b6ad0767e1..f21cf5083973 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -35,8 +35,8 @@ #include "debug.h" #include "v9fs.h" #include "9p.h" -#include "transport.h" #include "conv.h" +#include "transport.h" #include "mux.h" #define ERREQFLUSH 1 @@ -74,6 +74,7 @@ struct v9fs_mux_data { wait_queue_head_t equeue; struct list_head req_list; struct list_head unsent_req_list; + struct v9fs_fcall *rcall; int rpos; char *rbuf; int wpos; @@ -101,11 +102,15 @@ struct v9fs_mux_rpc { wait_queue_head_t wqueue; }; +extern int v9fs_errstr2errno(char *str, int len); + static int v9fs_poll_proc(void *); static void v9fs_read_work(void *); static void v9fs_write_work(void *); static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, poll_table * p); +static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); +static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16); static DECLARE_MUTEX(v9fs_mux_task_lock); static struct workqueue_struct *v9fs_mux_wq; @@ -166,8 +171,9 @@ static void v9fs_mux_poll_start(struct v9fs_mux_data *m) if (v9fs_mux_poll_tasks[i].task == NULL) { vpt = &v9fs_mux_poll_tasks[i]; dprintk(DEBUG_MUX, "create proc %p\n", vpt); - vpt->task = kthread_create(v9fs_poll_proc, - vpt, "v9fs-poll"); + vpt->task = + kthread_create(v9fs_poll_proc, vpt, + "v9fs-poll"); INIT_LIST_HEAD(&vpt->mux_list); vpt->muxnum = 0; v9fs_mux_poll_task_num++; @@ -253,7 +259,7 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, struct v9fs_mux_data *m, *mtmp; dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); - m = kmalloc(sizeof(struct v9fs_mux_data) + 2 * msize, GFP_KERNEL); + m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL); if (!m) return ERR_PTR(-ENOMEM); @@ -268,10 +274,11 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, init_waitqueue_head(&m->equeue); INIT_LIST_HEAD(&m->req_list); INIT_LIST_HEAD(&m->unsent_req_list); + m->rcall = NULL; m->rpos = 0; - m->rbuf = (char *)m + sizeof(struct v9fs_mux_data); + m->rbuf = NULL; m->wpos = m->wsize = 0; - m->wbuf = m->rbuf + msize; + m->wbuf = NULL; INIT_WORK(&m->rq, v9fs_read_work, m); INIT_WORK(&m->wq, v9fs_write_work, m); m->wsched = 0; @@ -427,29 +434,6 @@ static int v9fs_poll_proc(void *a) return 0; } -static inline int v9fs_write_req(struct v9fs_mux_data *m, struct v9fs_req *req) -{ - int n; - - list_move_tail(&req->req_list, &m->req_list); - n = v9fs_serialize_fcall(req->tcall, m->wbuf, m->msize, *m->extended); - if (n < 0) { - req->err = n; - list_del(&req->req_list); - if (req->cb) { - spin_unlock(&m->lock); - (*req->cb) (req->cba, req->tcall, req->rcall, req->err); - req->cb = NULL; - spin_lock(&m->lock); - } else - kfree(req->rcall); - - kfree(req); - } - - return n; -} - /** * v9fs_write_work - called when a transport can send some data */ @@ -457,7 +441,7 @@ static void v9fs_write_work(void *a) { int n, err; struct v9fs_mux_data *m; - struct v9fs_req *req, *rtmp; + struct v9fs_req *req; m = a; @@ -472,17 +456,15 @@ static void v9fs_write_work(void *a) return; } - err = 0; spin_lock(&m->lock); - list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, - req_list) { - err = v9fs_write_req(m, req); - if (err > 0) - break; - } - - m->wsize = err; + req = + list_entry(m->unsent_req_list.next, struct v9fs_req, + req_list); + list_move_tail(&req->req_list, &m->req_list); + m->wbuf = req->tcall->sdata; + m->wsize = req->tcall->size; m->wpos = 0; + dump_data(m->wbuf, m->wsize); spin_unlock(&m->lock); } @@ -526,24 +508,23 @@ static void v9fs_write_work(void *a) static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) { int ecode, tag; - char *ename; + struct v9fs_str *ename; tag = req->tag; if (req->rcall->id == RERROR && !req->err) { ecode = req->rcall->params.rerror.errno; - ename = req->rcall->params.rerror.error; + ename = &req->rcall->params.rerror.error; - dprintk(DEBUG_MUX, "Rerror %s\n", ename); + dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); if (*m->extended) req->err = -ecode; if (!req->err) { - req->err = v9fs_errstr2errno(ename); + req->err = v9fs_errstr2errno(ename->str, ename->len); if (!req->err) { /* string match failed */ - dprintk(DEBUG_ERROR, "unknown error: %s\n", - ename); + PRINT_FCALL_ERROR("unknown error", req->rcall); } if (!req->err) @@ -565,8 +546,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) } else kfree(req->rcall); - if (tag != V9FS_NOTAG) - v9fs_put_idpool(tag, &m->tidpool); + v9fs_mux_put_tag(m, tag); wake_up(&m->equeue); kfree(req); @@ -577,10 +557,11 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) */ static void v9fs_read_work(void *a) { - int n, err, rcallen; + int n, err; struct v9fs_mux_data *m; struct v9fs_req *req, *rptr, *rreq; struct v9fs_fcall *rcall; + char *rbuf; m = a; @@ -589,6 +570,19 @@ static void v9fs_read_work(void *a) rcall = NULL; dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); + + if (!m->rcall) { + m->rcall = + kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL); + if (!m->rcall) { + err = -ENOMEM; + goto error; + } + + m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); + m->rpos = 0; + } + clear_bit(Rpending, &m->wsched); err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); @@ -613,21 +607,32 @@ static void v9fs_read_work(void *a) if (m->rpos < n) break; - rcallen = n + V9FS_FCALLHDRSZ; - rcall = kmalloc(rcallen, GFP_KERNEL); - if (!rcall) { - err = -ENOMEM; - goto error; - } - dump_data(m->rbuf, n); - err = v9fs_deserialize_fcall(m->rbuf, n, rcall, rcallen, - *m->extended); + err = + v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended); if (err < 0) { - kfree(rcall); goto error; } + rcall = m->rcall; + rbuf = m->rbuf; + if (m->rpos > n) { + m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize, + GFP_KERNEL); + if (!m->rcall) { + err = -ENOMEM; + goto error; + } + + m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); + memmove(m->rbuf, rbuf + n, m->rpos - n); + m->rpos -= n; + } else { + m->rcall = NULL; + m->rbuf = NULL; + m->rpos = 0; + } + dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, rcall->tag); @@ -642,6 +647,7 @@ static void v9fs_read_work(void *a) process_request(m, req); break; } + } if (!req) { @@ -652,10 +658,6 @@ static void v9fs_read_work(void *a) m, rcall->id, rcall->tag); kfree(rcall); } - - if (m->rpos > n) - memmove(m->rbuf, m->rbuf + n, m->rpos - n); - m->rpos -= n; } if (!list_empty(&m->req_list)) { @@ -710,12 +712,13 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, if (tc->id == TVERSION) n = V9FS_NOTAG; else - n = v9fs_get_idpool(&m->tidpool); + n = v9fs_mux_get_tag(m); if (n < 0) return ERR_PTR(-ENOMEM); - tc->tag = n; + v9fs_set_tag(tc, n); + req->tag = n; req->tcall = tc; req->rcall = NULL; @@ -773,9 +776,7 @@ v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, if (!cb) spin_unlock(&m->lock); - if (v9fs_check_idpool(tag, &m->tidpool)) - v9fs_put_idpool(tag, &m->tidpool); - + v9fs_mux_put_tag(m, tag); kfree(tc); kfree(rc); } @@ -787,10 +788,7 @@ v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); - fc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL); - fc->id = TFLUSH; - fc->params.tflush.oldtag = req->tag; - + fc = v9fs_create_tflush(req->tag); v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); } @@ -939,3 +937,20 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err) wake_up(&m->equeue); } + +static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m) +{ + int tag; + + tag = v9fs_get_idpool(&m->tidpool); + if (tag < 0) + return V9FS_NOTAG; + else + return (u16) tag; +} + +static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag) +{ + if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tidpool)) + v9fs_put_idpool(tag, &m->tidpool); +} diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c index 9ef404c75c8f..44e830697acb 100644 --- a/fs/9p/trans_sock.c +++ b/fs/9p/trans_sock.c @@ -110,7 +110,6 @@ static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len) if (!(ts->filp->f_flags & O_NONBLOCK)) dprintk(DEBUG_ERROR, "blocking write ...\n"); - dump_data(v, len); oldfs = get_fs(); set_fs(get_ds()); ret = vfs_write(ts->filp, (void __user *)v, len, &ts->filp->f_pos); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 5e0f79355fdf..519b21d8b15b 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -37,7 +37,6 @@ #include "v9fs_vfs.h" #include "transport.h" #include "mux.h" -#include "conv.h" /* TODO: sysfs or debugfs interface */ int v9fs_debug_level = 0; /* feature-rific global debug level */ @@ -353,7 +352,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses, } /* Really should check for 9P1 and report error */ - if (!strcmp(fcall->params.rversion.version, "9P2000.u")) { + if (!v9fs_str_compare("9P2000.u", &fcall->params.rversion.version)) { dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); v9ses->extended = 1; } else { diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 2f2cea7ee3e7..c78502ad00ed 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -45,9 +45,8 @@ extern struct dentry_operations v9fs_dentry_operations; struct inode *v9fs_get_inode(struct super_block *sb, int mode); ino_t v9fs_qid2ino(struct v9fs_qid *qid); -void v9fs_mistat2inode(struct v9fs_stat *, struct inode *, - struct super_block *); +void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *); int v9fs_dir_release(struct inode *inode, struct file *filp); int v9fs_file_open(struct inode *inode, struct file *file); -void v9fs_inode2mistat(struct inode *inode, struct v9fs_stat *mistat); +void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); void v9fs_dentry_release(struct dentry *); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 4887df767394..2dd806dac9f1 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -40,7 +40,6 @@ #include "v9fs.h" #include "9p.h" #include "v9fs_vfs.h" -#include "conv.h" #include "fid.h" /** @@ -108,7 +107,8 @@ void v9fs_dentry_release(struct dentry *dentry) err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid); if (err < 0) - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); + dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n", + err, dentry->d_iname); v9fs_fid_destroy(current_fid); } diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 3893dd307ddb..ae6d032b9b59 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -37,8 +37,8 @@ #include "debug.h" #include "v9fs.h" #include "9p.h" -#include "v9fs_vfs.h" #include "conv.h" +#include "v9fs_vfs.h" #include "fid.h" /** @@ -77,17 +77,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) unsigned int i, n, s; int fid = -1; int ret = 0; - struct v9fs_stat *mi = NULL; + struct v9fs_stat stat; int over = 0; dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name); fid = file->fid; - mi = kmalloc(v9ses->maxdata, GFP_KERNEL); - if (!mi) - return -ENOMEM; - if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) { kfree(file->rdir_fcall); file->rdir_fcall = NULL; @@ -99,18 +95,18 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) while (i < n) { s = v9fs_deserialize_stat( file->rdir_fcall->params.rread.data + i, - n - i, mi, v9ses->maxdata, v9ses->extended); + n - i, &stat, v9ses->extended); if (s == 0) { dprintk(DEBUG_ERROR, - "error while deserializing mistat\n"); + "error while deserializing stat\n"); ret = -EIO; goto FreeStructs; } - over = filldir(dirent, mi->name, strlen(mi->name), - filp->f_pos, v9fs_qid2ino(&mi->qid), - dt_type(mi)); + over = filldir(dirent, stat.name.str, stat.name.len, + filp->f_pos, v9fs_qid2ino(&stat.qid), + dt_type(&stat)); if (over) { file->rdir_fpos = i; @@ -130,7 +126,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) while (!over) { ret = v9fs_t_read(v9ses, fid, filp->f_pos, - v9ses->maxdata-V9FS_IOHDRSZ, &fcall); + v9ses->maxdata-V9FS_IOHDRSZ, &fcall); if (ret < 0) { dprintk(DEBUG_ERROR, "error while reading: %d: %p\n", ret, fcall); @@ -142,17 +138,17 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) i = 0; while (i < n) { s = v9fs_deserialize_stat(fcall->params.rread.data + i, - n - i, mi, v9ses->maxdata, v9ses->extended); + n - i, &stat, v9ses->extended); if (s == 0) { dprintk(DEBUG_ERROR, - "error while deserializing mistat\n"); + "error while deserializing stat\n"); return -EIO; } - over = filldir(dirent, mi->name, strlen(mi->name), - filp->f_pos, v9fs_qid2ino(&mi->qid), - dt_type(mi)); + over = filldir(dirent, stat.name.str, stat.name.len, + filp->f_pos, v9fs_qid2ino(&stat.qid), + dt_type(&stat)); if (over) { file->rdir_fcall = fcall; @@ -171,7 +167,6 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) FreeStructs: kfree(fcall); - kfree(mi); return ret; } diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index e13577da9130..6852f0eb96ed 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -117,9 +118,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); if (result < 0) { - dprintk(DEBUG_ERROR, - "open failed, open_mode 0x%x: %s\n", open_mode, - FCALL_ERROR(fcall)); + PRINT_FCALL_ERROR("open failed", fcall); kfree(fcall); return result; } @@ -256,7 +255,6 @@ v9fs_file_write(struct file *filp, const char __user * data, int result = -EIO; int rsize = 0; int total = 0; - char *buf; dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, (int)*offset); @@ -264,28 +262,14 @@ v9fs_file_write(struct file *filp, const char __user * data, if (v9fid->iounit != 0 && rsize > v9fid->iounit) rsize = v9fid->iounit; - buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL); - if (!buf) - return -ENOMEM; - do { if (count < rsize) rsize = count; - result = copy_from_user(buf, data, rsize); - if (result) { - dprintk(DEBUG_ERROR, "Problem copying from user\n"); - kfree(buf); - return -EFAULT; - } - - dump_data(buf, rsize); - result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall); + result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall); if (result < 0) { - eprintk(KERN_ERR, "error while writing: %s(%d)\n", - FCALL_ERROR(fcall), result); + PRINT_FCALL_ERROR("error while writing", fcall); kfree(fcall); - kfree(buf); return result; } else *offset += result; @@ -305,7 +289,6 @@ v9fs_file_write(struct file *filp, const char __user * data, total += result; } while (count); - kfree(buf); return total; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index f11edde6432e..742bcd0dc4a7 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -40,7 +40,6 @@ #include "v9fs.h" #include "9p.h" #include "v9fs_vfs.h" -#include "conv.h" #include "fid.h" static struct inode_operations v9fs_dir_inode_operations; @@ -127,100 +126,32 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) } /** - * v9fs_blank_mistat - helper function to setup a 9P stat structure + * v9fs_blank_wstat - helper function to setup a 9P stat structure * @v9ses: 9P session info (for determining extended mode) - * @mistat: structure to initialize + * @wstat: structure to initialize * */ static void -v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) +v9fs_blank_wstat(struct v9fs_wstat *wstat) { - mistat->type = ~0; - mistat->dev = ~0; - mistat->qid.type = ~0; - mistat->qid.version = ~0; - *((long long *)&mistat->qid.path) = ~0; - mistat->mode = ~0; - mistat->atime = ~0; - mistat->mtime = ~0; - mistat->length = ~0; - mistat->name = mistat->data; - mistat->uid = mistat->data; - mistat->gid = mistat->data; - mistat->muid = mistat->data; - if (v9ses->extended) { - mistat->n_uid = ~0; - mistat->n_gid = ~0; - mistat->n_muid = ~0; - mistat->extension = mistat->data; - } - *mistat->data = 0; -} - -/** - * v9fs_mistat2unix - convert mistat to unix stat - * @mistat: Plan 9 metadata (mistat) structure - * @buf: unix metadata (stat) structure to populate - * @sb: superblock - * - */ - -static void -v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf, - struct super_block *sb) -{ - struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL; - - buf->st_nlink = 1; - - buf->st_atime = mistat->atime; - buf->st_mtime = mistat->mtime; - buf->st_ctime = mistat->mtime; - - buf->st_uid = (unsigned short)-1; - buf->st_gid = (unsigned short)-1; - - if (v9ses && v9ses->extended) { - /* TODO: string to uid mapping via user-space daemon */ - if (mistat->n_uid != -1) - sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid); - - if (mistat->n_gid != -1) - sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid); - } - - if (buf->st_uid == (unsigned short)-1) - buf->st_uid = v9ses->uid; - if (buf->st_gid == (unsigned short)-1) - buf->st_gid = v9ses->gid; - - buf->st_mode = p9mode2unixmode(v9ses, mistat->mode); - if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) { - char type = 0; - int major = -1; - int minor = -1; - sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); - switch (type) { - case 'c': - buf->st_mode &= ~S_IFBLK; - buf->st_mode |= S_IFCHR; - break; - case 'b': - break; - default: - dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", - type, mistat->extension); - }; - buf->st_rdev = MKDEV(major, minor); - } else - buf->st_rdev = 0; - - buf->st_size = mistat->length; - - buf->st_blksize = sb->s_blocksize; - buf->st_blocks = - (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits; + wstat->type = ~0; + wstat->dev = ~0; + wstat->qid.type = ~0; + wstat->qid.version = ~0; + *((long long *)&wstat->qid.path) = ~0; + wstat->mode = ~0; + wstat->atime = ~0; + wstat->mtime = ~0; + wstat->length = ~0; + wstat->name = NULL; + wstat->uid = NULL; + wstat->gid = NULL; + wstat->muid = NULL; + wstat->n_uid = ~0; + wstat->n_gid = ~0; + wstat->n_muid = ~0; + wstat->extension = NULL; } /** @@ -312,7 +243,6 @@ v9fs_create(struct inode *dir, struct inode *file_inode = NULL; struct v9fs_fcall *fcall = NULL; struct v9fs_qid qid; - struct stat newstat; int dirfidnum = -1; long newfid = -1; int result = 0; @@ -350,7 +280,7 @@ v9fs_create(struct inode *dir, result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); if (result < 0) { - dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); + PRINT_FCALL_ERROR("clone error", fcall); v9fs_put_idpool(newfid, &v9ses->fidpool); newfid = -1; goto CleanUpFid; @@ -362,9 +292,7 @@ v9fs_create(struct inode *dir, result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, perm, open_mode, &fcall); if (result < 0) { - dprintk(DEBUG_ERROR, "create fails: %s(%d)\n", - FCALL_ERROR(fcall), result); - + PRINT_FCALL_ERROR("create fails", fcall); goto CleanUpFid; } @@ -400,7 +328,7 @@ v9fs_create(struct inode *dir, result = v9fs_t_walk(v9ses, dirfidnum, wfidno, (char *) file_dentry->d_name.name, &fcall); if (result < 0) { - dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); + PRINT_FCALL_ERROR("clone error", fcall); v9fs_put_idpool(wfidno, &v9ses->fidpool); wfidno = -1; goto CleanUpFid; @@ -421,21 +349,21 @@ v9fs_create(struct inode *dir, result = v9fs_t_stat(v9ses, wfidno, &fcall); if (result < 0) { - dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall), - result); + PRINT_FCALL_ERROR("stat error", fcall); goto CleanUpFid; } - v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); - file_inode = v9fs_get_inode(sb, newstat.st_mode); + file_inode = v9fs_get_inode(sb, + p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode)); + if ((!file_inode) || IS_ERR(file_inode)) { dprintk(DEBUG_ERROR, "create inode failed\n"); result = -EBADF; goto CleanUpFid; } - v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb); + v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb); kfree(fcall); fcall = NULL; file_dentry->d_op = &v9fs_dentry_operations; @@ -500,10 +428,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) } result = v9fs_t_remove(v9ses, fid, &fcall); - if (result < 0) - dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n", - FCALL_ERROR(fcall), result); - else { + if (result < 0) { + PRINT_FCALL_ERROR("remove fails", fcall); + } else { v9fs_put_idpool(fid, &v9ses->fidpool); v9fs_fid_destroy(v9fid); } @@ -558,7 +485,6 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, struct v9fs_fid *fid; struct inode *inode; struct v9fs_fcall *fcall = NULL; - struct stat newstat; int dirfidnum = -1; int newfid = -1; int result = 0; @@ -611,8 +537,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, goto FreeFcall; } - v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); - inode = v9fs_get_inode(sb, newstat.st_mode); + inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, + fcall->params.rstat.stat.mode)); if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", @@ -622,7 +548,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, goto FreeFcall; } - inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); + inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); fid = v9fs_fid_create(dentry, v9ses, newfid, 0); if (fid == NULL) { @@ -631,10 +557,10 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, goto FreeFcall; } - fid->qid = fcall->params.rstat.stat->qid; + fid->qid = fcall->params.rstat.stat.qid; dentry->d_op = &v9fs_dentry_operations; - v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb); + v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); d_add(dentry, inode); kfree(fcall); @@ -690,7 +616,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, v9fs_fid_lookup(old_dentry->d_parent); struct v9fs_fid *newdirfid = v9fs_fid_lookup(new_dentry->d_parent); - struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + struct v9fs_wstat wstat; struct v9fs_fcall *fcall = NULL; int fid = -1; int olddirfidnum = -1; @@ -699,9 +625,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, dprintk(DEBUG_VFS, "\n"); - if (!mistat) - return -ENOMEM; - if ((!oldfid) || (!olddirfid) || (!newdirfid)) { dprintk(DEBUG_ERROR, "problem with arguments\n"); return -EBADF; @@ -725,26 +648,15 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto FreeFcallnBail; } - v9fs_blank_mistat(v9ses, mistat); - - strcpy(mistat->data + 1, v9ses->name); - mistat->name = mistat->data + 1 + strlen(v9ses->name); - - if (new_dentry->d_name.len > - (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) { - dprintk(DEBUG_ERROR, "new name too long\n"); - goto FreeFcallnBail; - } + v9fs_blank_wstat(&wstat); + wstat.muid = v9ses->name; + wstat.name = (char *) new_dentry->d_name.name; - strcpy(mistat->name, new_dentry->d_name.name); - retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall); + retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); FreeFcallnBail: - kfree(mistat); - if (retval < 0) - dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", - FCALL_ERROR(fcall)); + PRINT_FCALL_ERROR("wstat error", fcall); kfree(fcall); return retval; @@ -779,7 +691,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, if (err < 0) dprintk(DEBUG_ERROR, "stat error\n"); else { - v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode, + v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, dentry->d_inode->i_sb); generic_fillattr(dentry->d_inode, stat); } @@ -800,57 +712,44 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); struct v9fs_fid *fid = v9fs_fid_lookup(dentry); struct v9fs_fcall *fcall = NULL; - struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + struct v9fs_wstat wstat; int res = -EPERM; dprintk(DEBUG_VFS, "\n"); - if (!mistat) - return -ENOMEM; - if (!fid) { dprintk(DEBUG_ERROR, "Couldn't find fid associated with dentry\n"); return -EBADF; } - v9fs_blank_mistat(v9ses, mistat); + v9fs_blank_wstat(&wstat); if (iattr->ia_valid & ATTR_MODE) - mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode); + wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); if (iattr->ia_valid & ATTR_MTIME) - mistat->mtime = iattr->ia_mtime.tv_sec; + wstat.mtime = iattr->ia_mtime.tv_sec; if (iattr->ia_valid & ATTR_ATIME) - mistat->atime = iattr->ia_atime.tv_sec; + wstat.atime = iattr->ia_atime.tv_sec; if (iattr->ia_valid & ATTR_SIZE) - mistat->length = iattr->ia_size; + wstat.length = iattr->ia_size; if (v9ses->extended) { - char *ptr = mistat->data+1; + if (iattr->ia_valid & ATTR_UID) + wstat.n_uid = iattr->ia_uid; - if (iattr->ia_valid & ATTR_UID) { - mistat->uid = ptr; - ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid); - mistat->n_uid = iattr->ia_uid; - } - - if (iattr->ia_valid & ATTR_GID) { - mistat->gid = ptr; - ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid); - mistat->n_gid = iattr->ia_gid; - } + if (iattr->ia_valid & ATTR_GID) + wstat.n_gid = iattr->ia_gid; } - res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall); + res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); if (res < 0) - dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall)); + PRINT_FCALL_ERROR("wstat error", fcall); - kfree(mistat); kfree(fcall); - if (res >= 0) res = inode_setattr(dentry->d_inode, iattr); @@ -858,51 +757,42 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) } /** - * v9fs_mistat2inode - populate an inode structure with mistat info - * @mistat: Plan 9 metadata (mistat) structure + * v9fs_stat2inode - populate an inode structure with mistat info + * @stat: Plan 9 metadata (mistat) structure * @inode: inode to populate * @sb: superblock of filesystem * */ void -v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, - struct super_block *sb) +v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, + struct super_block *sb) { + char ext[32]; struct v9fs_session_info *v9ses = sb->s_fs_info; inode->i_nlink = 1; - inode->i_atime.tv_sec = mistat->atime; - inode->i_mtime.tv_sec = mistat->mtime; - inode->i_ctime.tv_sec = mistat->mtime; + inode->i_atime.tv_sec = stat->atime; + inode->i_mtime.tv_sec = stat->mtime; + inode->i_ctime.tv_sec = stat->mtime; - inode->i_uid = -1; - inode->i_gid = -1; + inode->i_uid = v9ses->uid; + inode->i_gid = v9ses->gid; if (v9ses->extended) { - /* TODO: string to uid mapping via user-space daemon */ - inode->i_uid = mistat->n_uid; - inode->i_gid = mistat->n_gid; - - if (mistat->n_uid == -1) - sscanf(mistat->uid, "%x", &inode->i_uid); - - if (mistat->n_gid == -1) - sscanf(mistat->gid, "%x", &inode->i_gid); + inode->i_uid = stat->n_uid; + inode->i_gid = stat->n_gid; } - if (inode->i_uid == -1) - inode->i_uid = v9ses->uid; - if (inode->i_gid == -1) - inode->i_gid = v9ses->gid; - - inode->i_mode = p9mode2unixmode(v9ses, mistat->mode); + inode->i_mode = p9mode2unixmode(v9ses, stat->mode); if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { char type = 0; int major = -1; int minor = -1; - sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); + + v9fs_str_copy(ext, sizeof(ext), &stat->extension); + sscanf(ext, "%c %u %u", &type, &major, &minor); switch (type) { case 'c': inode->i_mode &= ~S_IFBLK; @@ -911,14 +801,14 @@ v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, case 'b': break; default: - dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", - type, mistat->extension); + dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", + type, stat->extension.len, stat->extension.str); }; inode->i_rdev = MKDEV(major, minor); } else inode->i_rdev = 0; - inode->i_size = mistat->length; + inode->i_size = stat->length; inode->i_blksize = sb->s_blocksize; inode->i_blocks = @@ -945,72 +835,6 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid) return i; } -/** - * v9fs_vfs_symlink - helper function to create symlinks - * @dir: directory inode containing symlink - * @dentry: dentry for symlink - * @symname: symlink data - * - * See 9P2000.u RFC for more information - * - */ - -static int -v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) -{ - int retval = -EPERM; - struct v9fs_fid *newfid; - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); - struct v9fs_fcall *fcall = NULL; - struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); - int err; - - dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, - symname); - - if (!mistat) - return -ENOMEM; - - if (!v9ses->extended) { - dprintk(DEBUG_ERROR, "not extended\n"); - goto FreeFcall; - } - - /* issue a create */ - retval = v9fs_create(dir, dentry, S_IFLNK, 0); - if (retval != 0) - goto FreeFcall; - - newfid = v9fs_fid_lookup(dentry); - - /* issue a twstat */ - v9fs_blank_mistat(v9ses, mistat); - strcpy(mistat->data + 1, symname); - mistat->extension = mistat->data + 1; - retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); - if (retval < 0) { - dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", - FCALL_ERROR(fcall)); - goto FreeFcall; - } - - kfree(fcall); - - err = v9fs_t_clunk(v9ses, newfid->fid); - if (err < 0) { - dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); - goto FreeFcall; - } - - d_drop(dentry); /* FID - will this also clunk? */ - - FreeFcall: - kfree(mistat); - kfree(fcall); - - return retval; -} - /** * v9fs_readlink - read a symlink's location (internal version) * @dentry: dentry for symlink @@ -1050,16 +874,17 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) if (!fcall) return -EIO; - if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) { + if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { retval = -EINVAL; goto FreeFcall; } /* copy extension buffer into buffer */ - if (strlen(fcall->params.rstat.stat->extension) < buflen) - buflen = strlen(fcall->params.rstat.stat->extension); + if (fcall->params.rstat.stat.extension.len < buflen) + buflen = fcall->params.rstat.stat.extension.len; - memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1); + memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); + buffer[buflen-1] = 0; retval = buflen; @@ -1149,82 +974,111 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void __putname(s); } -/** - * v9fs_vfs_link - create a hardlink - * @old_dentry: dentry for file to link to - * @dir: inode destination for new link - * @dentry: dentry for link - * - */ - -/* XXX - lots of code dup'd from symlink and creates, - * figure out a better reuse strategy - */ - -static int -v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) +static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, + int mode, const char *extension) { - int retval = -EPERM; - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); - struct v9fs_fcall *fcall = NULL; - struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); - struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); - struct v9fs_fid *newfid = NULL; - char *symname = __getname(); - int err; + int err, retval; + struct v9fs_session_info *v9ses; + struct v9fs_fcall *fcall; + struct v9fs_fid *fid; + struct v9fs_wstat wstat; - dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, - old_dentry->d_name.name); + v9ses = v9fs_inode2v9ses(dir); + retval = -EPERM; + fcall = NULL; if (!v9ses->extended) { dprintk(DEBUG_ERROR, "not extended\n"); - goto FreeMem; + goto free_mem; } - /* get fid of old_dentry */ - sprintf(symname, "hardlink(%d)\n", oldfid->fid); - /* issue a create */ - retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0); + retval = v9fs_create(dir, dentry, mode, 0); if (retval != 0) - goto FreeMem; + goto free_mem; - newfid = v9fs_fid_lookup(dentry); - if (!newfid) { + fid = v9fs_fid_get_created(dentry); + if (!fid) { dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); - goto FreeMem; + goto free_mem; } - /* issue a twstat */ - v9fs_blank_mistat(v9ses, mistat); - strcpy(mistat->data + 1, symname); - mistat->extension = mistat->data + 1; - retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); + /* issue a Twstat */ + v9fs_blank_wstat(&wstat); + wstat.muid = v9ses->name; + wstat.extension = (char *) extension; + retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); if (retval < 0) { - dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", - FCALL_ERROR(fcall)); - goto FreeMem; + PRINT_FCALL_ERROR("wstat error", fcall); + goto free_mem; } - kfree(fcall); - - err = v9fs_t_clunk(v9ses, newfid->fid); - + err = v9fs_t_clunk(v9ses, fid->fid); if (err < 0) { - dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); - goto FreeMem; + dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); + goto free_mem; } d_drop(dentry); /* FID - will this also clunk? */ +free_mem: kfree(fcall); - fcall = NULL; + return retval; +} + +/** + * v9fs_vfs_symlink - helper function to create symlinks + * @dir: directory inode containing symlink + * @dentry: dentry for symlink + * @symname: symlink data + * + * See 9P2000.u RFC for more information + * + */ + +static int +v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, + symname); + + return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); +} + +/** + * v9fs_vfs_link - create a hardlink + * @old_dentry: dentry for file to link to + * @dir: inode destination for new link + * @dentry: dentry for link + * + */ + +/* XXX - lots of code dup'd from symlink and creates, + * figure out a better reuse strategy + */ + +static int +v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + int retval; + struct v9fs_fid *oldfid; + char *name; + + dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, + old_dentry->d_name.name); + + oldfid = v9fs_fid_lookup(old_dentry); + if (!oldfid) { + dprintk(DEBUG_ERROR, "can't find oldfid\n"); + return -EPERM; + } + + name = __getname(); + sprintf(name, "hardlink(%d)\n", oldfid->fid); + retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); + __putname(name); - FreeMem: - kfree(mistat); - kfree(fcall); - __putname(symname); return retval; } @@ -1240,83 +1094,30 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, static int v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) { - int retval = -EPERM; - struct v9fs_fid *newfid; - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); - struct v9fs_fcall *fcall = NULL; - struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); - char *symname = __getname(); - int err; + int retval; + char *name; dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); - if (!mistat) - return -ENOMEM; - - if (!new_valid_dev(rdev)) { - retval = -EINVAL; - goto FreeMem; - } - - if (!v9ses->extended) { - dprintk(DEBUG_ERROR, "not extended\n"); - goto FreeMem; - } - - /* issue a create */ - retval = v9fs_create(dir, dentry, mode, 0); - - if (retval != 0) - goto FreeMem; - - newfid = v9fs_fid_lookup(dentry); - if (!newfid) { - dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); - retval = -EINVAL; - goto FreeMem; - } + if (!new_valid_dev(rdev)) + return -EINVAL; + name = __getname(); /* build extension */ if (S_ISBLK(mode)) - sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev)); + sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); else if (S_ISCHR(mode)) - sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev)); + sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); else if (S_ISFIFO(mode)) - ; /* DO NOTHING */ + *name = 0; else { - retval = -EINVAL; - goto FreeMem; + __putname(name); + return -EINVAL; } - if (!S_ISFIFO(mode)) { - /* issue a twstat */ - v9fs_blank_mistat(v9ses, mistat); - strcpy(mistat->data + 1, symname); - mistat->extension = mistat->data + 1; - retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); - if (retval < 0) { - dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", - FCALL_ERROR(fcall)); - goto FreeMem; - } - } - - /* need to update dcache so we show up */ - kfree(fcall); - - err = v9fs_t_clunk(v9ses, newfid->fid); - if (err < 0) { - dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); - goto FreeMem; - } - - d_drop(dentry); /* FID - will this also clunk? */ - - FreeMem: - kfree(mistat); - kfree(fcall); - __putname(symname); + retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); + __putname(name); return retval; } diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 83b6edd0988a..d4d71a9ca573 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -44,7 +44,6 @@ #include "v9fs.h" #include "9p.h" #include "v9fs_vfs.h" -#include "conv.h" #include "fid.h" static void v9fs_clear_inode(struct inode *); @@ -123,10 +122,11 @@ static struct super_block *v9fs_get_sb(struct file_system_type dprintk(DEBUG_VFS, " \n"); - v9ses = kcalloc(1, sizeof(struct v9fs_session_info), GFP_KERNEL); + v9ses = kmalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); if (!v9ses) return ERR_PTR(-ENOMEM); + memset(v9ses, 0, sizeof(struct v9fs_session_info)); if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { dprintk(DEBUG_ERROR, "problem initiating session\n"); kfree(v9ses); @@ -168,10 +168,10 @@ static struct super_block *v9fs_get_sb(struct file_system_type goto put_back_sb; } - root_fid->qid = fcall->params.rstat.stat->qid; + root_fid->qid = fcall->params.rstat.stat.qid; root->d_inode->i_ino = - v9fs_qid2ino(&fcall->params.rstat.stat->qid); - v9fs_mistat2inode(fcall->params.rstat.stat, root->d_inode, sb); + v9fs_qid2ino(&fcall->params.rstat.stat.qid); + v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); } kfree(fcall); -- cgit v1.2.3 From 1dac06b20dcc8078dab037bd70652c69c67ba672 Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Sun, 8 Jan 2006 01:05:02 -0800 Subject: [PATCH] v9fs: handle kthread_create failure, minor bugfixes - remove unnecessary -ENOMEM assignments - return correct value when buf_check_size for second time in a buffer - handle failures when create_workqueue and kthread_create are called - use kzalloc instead of kmalloc/memset 0 - v9fs_str_copy and v9fs_str_compare were buggy, were used only in one place, correct the logic and move it to the place it is used. Signed-off-by: Latchesar Ionkov Cc: Eric Van Hensbergen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/9p/9p.c | 10 ---------- fs/9p/9p.h | 3 --- fs/9p/conv.c | 45 +++++++++------------------------------------ fs/9p/error.h | 1 - fs/9p/mux.c | 38 ++++++++++++++++++++++++++------------ fs/9p/mux.h | 3 ++- fs/9p/v9fs.c | 19 ++++++++++++++----- fs/9p/vfs_inode.c | 7 ++++++- fs/9p/vfs_super.c | 3 +-- 9 files changed, 58 insertions(+), 71 deletions(-) diff --git a/fs/9p/9p.c b/fs/9p/9p.c index dc3ce44ec836..1a6d08761f39 100644 --- a/fs/9p/9p.c +++ b/fs/9p/9p.c @@ -86,7 +86,6 @@ v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname, aname, fid, afid); - ret = -ENOMEM; tc = v9fs_create_tattach(fid, afid, uname, aname); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); @@ -136,7 +135,6 @@ v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid) dprintk(DEBUG_9P, "fid %d\n", fid); - ret = -ENOMEM; rc = NULL; tc = v9fs_create_tclunk(fid); if (!IS_ERR(tc)) @@ -165,7 +163,6 @@ int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag) dprintk(DEBUG_9P, "oldtag %d\n", oldtag); - ret = -ENOMEM; tc = v9fs_create_tflush(oldtag); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, NULL); @@ -221,7 +218,6 @@ v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, dprintk(DEBUG_9P, "fid %d\n", fid); - ret = -ENOMEM; tc = v9fs_create_twstat(fid, wstat, v9ses->extended); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); @@ -259,7 +255,6 @@ v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, else nwname = 0; - ret = -ENOMEM; tc = v9fs_create_twalk(fid, newfid, nwname, &name); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); @@ -289,7 +284,6 @@ v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode); - ret = -ENOMEM; tc = v9fs_create_topen(fid, mode); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); @@ -317,7 +311,6 @@ v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, dprintk(DEBUG_9P, "fid %d\n", fid); - ret = -ENOMEM; tc = v9fs_create_tremove(fid); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); @@ -349,7 +342,6 @@ v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n", fid, name, perm, mode); - ret = -ENOMEM; tc = v9fs_create_tcreate(fid, name, perm, mode); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, rcp); @@ -380,7 +372,6 @@ v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid, (long long unsigned) offset, count); - ret = -ENOMEM; tc = v9fs_create_tread(fid, offset, count); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); @@ -418,7 +409,6 @@ v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count, dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid, (long long unsigned) offset, count); - ret = -ENOMEM; tc = v9fs_create_twrite(fid, offset, count, data); if (!IS_ERR(tc)) { ret = v9fs_mux_rpc(v9ses->mux, tc, &rc); diff --git a/fs/9p/9p.h b/fs/9p/9p.h index 007ff639777d..0cd374d94717 100644 --- a/fs/9p/9p.h +++ b/fs/9p/9p.h @@ -340,9 +340,6 @@ struct v9fs_fcall { fcall?fcall->params.rerror.error.len:0, \ fcall?fcall->params.rerror.error.str:""); -char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str); -int v9fs_str_compare(char *buf, struct v9fs_str *str); - int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, char *version, struct v9fs_fcall **rcall); diff --git a/fs/9p/conv.c b/fs/9p/conv.c index f62434d435b3..55ccfa10ee9e 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -45,37 +45,6 @@ struct cbuf { unsigned char *ep; }; -char *v9fs_str_copy(char *buf, int buflen, struct v9fs_str *str) -{ - int n; - - if (buflen < str->len) - n = buflen; - else - n = str->len; - - memmove(buf, str->str, n - 1); - - return buf; -} - -int v9fs_str_compare(char *buf, struct v9fs_str *str) -{ - int n, ret; - - ret = strncmp(buf, str->str, str->len); - - if (!ret) { - n = strlen(buf); - if (n < str->len) - ret = -1; - else if (n > str->len) - ret = 1; - } - - return ret; -} - static inline void buf_init(struct cbuf *buf, void *data, int datalen) { buf->sp = buf->p = data; @@ -89,11 +58,14 @@ static inline int buf_check_overflow(struct cbuf *buf) static inline int buf_check_size(struct cbuf *buf, int len) { - if (buf->p + len > buf->ep && buf->p < buf->ep) { - eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", - len, (int)(buf->ep - buf->p)); - dump_stack(); - buf->p = buf->ep + 1; + if (buf->p + len > buf->ep) { + if (buf->p < buf->ep) { + eprintk(KERN_ERR, "buffer overflow: want %d has %d\n", + len, (int)(buf->ep - buf->p)); + dump_stack(); + buf->p = buf->ep + 1; + } + return 0; } @@ -527,6 +499,7 @@ v9fs_create_common(struct cbuf *bufp, u32 size, u8 id) void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag) { + fc->tag = tag; *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); } diff --git a/fs/9p/error.h b/fs/9p/error.h index 8b3176b3f658..a9794e85fe51 100644 --- a/fs/9p/error.h +++ b/fs/9p/error.h @@ -176,4 +176,3 @@ static struct errormap errmap[] = { }; extern int v9fs_error_init(void); -extern int v9fs_errstr2errno(char *errstr, int len); diff --git a/fs/9p/mux.c b/fs/9p/mux.c index f21cf5083973..945cb368d451 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -102,8 +102,6 @@ struct v9fs_mux_rpc { wait_queue_head_t wqueue; }; -extern int v9fs_errstr2errno(char *str, int len); - static int v9fs_poll_proc(void *); static void v9fs_read_work(void *); static void v9fs_write_work(void *); @@ -119,7 +117,7 @@ static int v9fs_mux_num; static int v9fs_mux_poll_task_num; static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100]; -void v9fs_mux_global_init(void) +int v9fs_mux_global_init(void) { int i; @@ -127,6 +125,10 @@ void v9fs_mux_global_init(void) v9fs_mux_poll_tasks[i].task = NULL; v9fs_mux_wq = create_workqueue("v9fs"); + if (!v9fs_mux_wq) + return -ENOMEM; + + return 0; } void v9fs_mux_global_exit(void) @@ -156,10 +158,11 @@ inline int v9fs_mux_calc_poll_procs(int muxnum) return n; } -static void v9fs_mux_poll_start(struct v9fs_mux_data *m) +static int v9fs_mux_poll_start(struct v9fs_mux_data *m) { int i, n; struct v9fs_mux_poll_task *vpt, *vptlast; + struct task_struct *pproc; dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num, v9fs_mux_poll_task_num); @@ -171,13 +174,16 @@ static void v9fs_mux_poll_start(struct v9fs_mux_data *m) if (v9fs_mux_poll_tasks[i].task == NULL) { vpt = &v9fs_mux_poll_tasks[i]; dprintk(DEBUG_MUX, "create proc %p\n", vpt); - vpt->task = - kthread_create(v9fs_poll_proc, vpt, + pproc = kthread_create(v9fs_poll_proc, vpt, "v9fs-poll"); - INIT_LIST_HEAD(&vpt->mux_list); - vpt->muxnum = 0; - v9fs_mux_poll_task_num++; - wake_up_process(vpt->task); + + if (!IS_ERR(pproc)) { + vpt->task = pproc; + INIT_LIST_HEAD(&vpt->mux_list); + vpt->muxnum = 0; + v9fs_mux_poll_task_num++; + wake_up_process(vpt->task); + } break; } } @@ -207,16 +213,21 @@ static void v9fs_mux_poll_start(struct v9fs_mux_data *m) } if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) { + if (vptlast == NULL) + return -ENOMEM; + dprintk(DEBUG_MUX, "put in proc %d\n", i); list_add(&m->mux_list, &vptlast->mux_list); vptlast->muxnum++; - m->poll_task = vpt; + m->poll_task = vptlast; memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); init_poll_funcptr(&m->pt, v9fs_pollwait); } v9fs_mux_num++; down(&v9fs_mux_task_lock); + + return 0; } static void v9fs_mux_poll_stop(struct v9fs_mux_data *m) @@ -283,7 +294,10 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, INIT_WORK(&m->wq, v9fs_write_work, m); m->wsched = 0; memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); - v9fs_mux_poll_start(m); + m->poll_task = NULL; + n = v9fs_mux_poll_start(m); + if (n) + return ERR_PTR(n); n = trans->poll(trans, &m->pt); if (n & POLLIN) { diff --git a/fs/9p/mux.h b/fs/9p/mux.h index 02b13b14b05b..9473b84f24b2 100644 --- a/fs/9p/mux.h +++ b/fs/9p/mux.h @@ -40,7 +40,7 @@ struct v9fs_mux_data; typedef void (*v9fs_mux_req_callback)(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err); -void v9fs_mux_global_init(void); +int v9fs_mux_global_init(void); void v9fs_mux_global_exit(void); struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, @@ -55,3 +55,4 @@ int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc, void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush); void v9fs_mux_cancel(struct v9fs_mux_data *m, int err); +int v9fs_errstr2errno(char *errstr, int len); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 519b21d8b15b..5250c428fc1f 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -269,6 +269,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses, int n = 0; int newfid = -1; int retval = -EINVAL; + struct v9fs_str *version; v9ses->name = __getname(); if (!v9ses->name) @@ -351,13 +352,16 @@ v9fs_session_init(struct v9fs_session_info *v9ses, goto FreeFcall; } - /* Really should check for 9P1 and report error */ - if (!v9fs_str_compare("9P2000.u", &fcall->params.rversion.version)) { + version = &fcall->params.rversion.version; + if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) { dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); v9ses->extended = 1; - } else { + } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) { dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n"); v9ses->extended = 0; + } else { + retval = -EREMOTEIO; + goto FreeFcall; } n = fcall->params.rversion.msize; @@ -449,12 +453,17 @@ extern int v9fs_error_init(void); static int __init init_v9fs(void) { + int ret; + v9fs_error_init(); printk(KERN_INFO "Installing v9fs 9P2000 file system support\n"); - v9fs_mux_global_init(); - return register_filesystem(&v9fs_fs_type); + ret = v9fs_mux_global_init(); + if (!ret) + ret = register_filesystem(&v9fs_fs_type); + + return ret; } /** diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 742bcd0dc4a7..d933ef1fbd8a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -768,6 +768,7 @@ void v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, struct super_block *sb) { + int n; char ext[32]; struct v9fs_session_info *v9ses = sb->s_fs_info; @@ -791,7 +792,11 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, int major = -1; int minor = -1; - v9fs_str_copy(ext, sizeof(ext), &stat->extension); + n = stat->extension.len; + if (n > sizeof(ext)-1) + n = sizeof(ext)-1; + memmove(ext, stat->extension.str, n); + ext[n] = 0; sscanf(ext, "%c %u %u", &type, &major, &minor); switch (type) { case 'c': diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index d4d71a9ca573..ae0f06b3c11a 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -122,11 +122,10 @@ static struct super_block *v9fs_get_sb(struct file_system_type dprintk(DEBUG_VFS, " \n"); - v9ses = kmalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); + v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); if (!v9ses) return ERR_PTR(-ENOMEM); - memset(v9ses, 0, sizeof(struct v9fs_session_info)); if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { dprintk(DEBUG_ERROR, "problem initiating session\n"); kfree(v9ses); -- cgit v1.2.3 From 19144d0beab077950f3e767385e3c1050061b475 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 8 Jan 2006 01:05:02 -0800 Subject: [PATCH] fix gcc4.1 build failure on xconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/kconfig/qconf.h:25: error: extra qualification ‘ConfigSettings::’ on member ‘readSizes’ scripts/kconfig/qconf.h:26: error: extra qualification ‘ConfigSettings::’ on member ‘writeSizes’ scripts/kconfig/qconf.h:127: error: extra qualification ‘ConfigList::’ on member ‘updateMenuList’ Signed-off-by: Dave Jones Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kconfig/qconf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index 7c03927d4c7c..e52f3e90bf0c 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -22,8 +22,8 @@ public: #if QT_VERSION >= 300 void readListSettings(); - QValueList ConfigSettings::readSizes(const QString& key, bool *ok); - bool ConfigSettings::writeSizes(const QString& key, const QValueList& value); + QValueList readSizes(const QString& key, bool *ok); + bool writeSizes(const QString& key, const QValueList& value); #endif bool showAll; @@ -124,7 +124,7 @@ public: void setParentMenu(void); template - void ConfigList::updateMenuList(P*, struct menu*); + void updateMenuList(P*, struct menu*); bool updateAll; -- cgit v1.2.3 From e0804b17984afa1504649e2535db489d2a3029b6 Mon Sep 17 00:00:00 2001 From: Eric Van Buggenhaut Date: Sun, 8 Jan 2006 01:05:03 -0800 Subject: [PATCH] hw_random: 82801AB PCI Bridge support pci.lst lists device 80862430 as another RNG # grep 80862430 /lib/discover/pci.lst 80862430 bridge i810_rng 82801AB PCI Bridge but it's not listed in rng_pci_tbl[] Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c index 49769f59ea1b..b3bc2e37e616 100644 --- a/drivers/char/hw_random.c +++ b/drivers/char/hw_random.c @@ -169,6 +169,7 @@ static struct pci_device_id rng_pci_tbl[] = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, -- cgit v1.2.3 From a771f2b82aa266fe578468deed82f797e26a3dc4 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 8 Jan 2006 01:05:04 -0800 Subject: [PATCH] Add a section about inlining to Documentation/CodingStyle Adds a bit of text to Documentation/Codingstyle to state that inlining everything "just because" is a bad idea Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/CodingStyle | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 187e12077e19..ce780ef648f1 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -344,7 +344,7 @@ Remember: if another thread can find your data structure, and you don't have a reference count on it, you almost certainly have a bug. - Chapter 11: Macros, Enums, Inline functions and RTL + Chapter 11: Macros, Enums and RTL Names of macros defining constants and labels in enums are capitalized. @@ -429,7 +429,35 @@ from void pointer to any other pointer type is guaranteed by the C programming language. - Chapter 14: References + Chapter 14: The inline disease + +There appears to be a common misperception that gcc has a magic "make me +faster" speedup option called "inline". While the use of inlines can be +appropriate (for example as a means of replacing macros, see Chapter 11), it +very often is not. Abundant use of the inline keyword leads to a much bigger +kernel, which in turn slows the system as a whole down, due to a bigger +icache footprint for the CPU and simply because there is less memory +available for the pagecache. Just think about it; a pagecache miss causes a +disk seek, which easily takes 5 miliseconds. There are a LOT of cpu cycles +that can go into these 5 miliseconds. + +A reasonable rule of thumb is to not put inline at functions that have more +than 3 lines of code in them. An exception to this rule are the cases where +a parameter is known to be a compiletime constant, and as a result of this +constantness you *know* the compiler will be able to optimize most of your +function away at compile time. For a good example of this later case, see +the kmalloc() inline function. + +Often people argue that adding inline to functions that are static and used +only once is always a win since there is no space tradeoff. While this is +technically correct, gcc is capable of inlining these automatically without +help, and the maintenance issue of removing the inline when a second user +appears outweighs the potential value of the hint that tells gcc to do +something it would have done anyway. + + + + Chapter 15: References The C Programming Language, Second Edition by Brian W. Kernighan and Dennis M. Ritchie. @@ -453,4 +481,4 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002: http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/ -- -Last updated on 16 February 2004 by a community effort on LKML. +Last updated on 30 December 2005 by a community effort on LKML. -- cgit v1.2.3 From d1c4ac408fbab78a5f89ff583b68d2d11b421bb3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:05:05 -0800 Subject: [PATCH] parport_pc: arm build fix free_dma() isn't implemented on ARM unless HAS_DMA is set. Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/parport/parport_pc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 18e85ccdae67..9302b8fd7461 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2371,8 +2371,10 @@ void parport_pc_unregister_port (struct parport *p) spin_lock(&ports_lock); list_del_init(&priv->list); spin_unlock(&ports_lock); +#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) if (p->dma != PARPORT_DMA_NONE) free_dma(p->dma); +#endif if (p->irq != PARPORT_IRQ_NONE) free_irq(p->irq, p); release_region(p->base, 3); @@ -2380,13 +2382,11 @@ void parport_pc_unregister_port (struct parport *p) release_region(p->base + 3, p->size - 3); if (p->modes & PARPORT_MODE_ECP) release_region(p->base_hi, 3); -#ifdef CONFIG_PARPORT_PC_FIFO -#ifdef HAS_DMA +#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) if (priv->dma_buf) pci_free_consistent(priv->dev, PAGE_SIZE, priv->dma_buf, priv->dma_handle); -#endif #endif kfree (p->private_data); parport_put_port(p); -- cgit v1.2.3 From d8a33496671e4533aed090793436d58debea6f3a Mon Sep 17 00:00:00 2001 From: Marko Kohtala Date: Sun, 8 Jan 2006 01:05:06 -0800 Subject: [PATCH] parport: bring back an unused phase for ppdev ioctl Earlier fix removed unused phase, but that changed the values for other phases. Since these are exposed to userspace through ppdev, it is safer not to change them. Restore the unused phase value. Signed-off-by: Marko Kohtala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/parport.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/parport.h b/include/linux/parport.h index f7ff0b0c4031..f67f838a3a1f 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -236,12 +236,14 @@ struct pardevice { /* IEEE1284 information */ -/* IEEE1284 phases */ +/* IEEE1284 phases. These are exposed to userland through ppdev IOCTL + * PP[GS]ETPHASE, so do not change existing values. */ enum ieee1284_phase { IEEE1284_PH_FWD_DATA, IEEE1284_PH_FWD_IDLE, IEEE1284_PH_TERMINATE, IEEE1284_PH_NEGOTIATION, + IEEE1284_PH_HBUSY_DNA, IEEE1284_PH_REV_IDLE, IEEE1284_PH_HBUSY_DAVAIL, IEEE1284_PH_REV_DATA, -- cgit v1.2.3 From 6a878184c202395ea17212f111ab9ec4b5f6d6ee Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Sun, 8 Jan 2006 01:05:07 -0800 Subject: [PATCH] Eliminate __attribute__ ((packed)) warnings for gcc-4.1 Since version 4.1 the gcc is warning about ignored attributes. This patch is using the equivalent attribute on the struct instead of on each of the structure or union members. GCC Manual: "Specifying Attributes of Types packed This attribute, attached to struct or union type definition, specifies that each member of the structure or union is placed to minimize the memory required. When attached to an enum definition, it indicates that the smallest integral type should be used. Specifying this attribute for struct and union types is equivalent to specifying the packed attribute on each of the structure or union members." Signed-off-by: Jan Blunck Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hisax/hisax.h | 18 +++--- drivers/isdn/hisax/hisax_fcpcipnp.h | 18 +++--- drivers/net/3c527.h | 50 +++++++------- drivers/net/irda/vlsi_ir.h | 4 +- drivers/net/wan/sdla.c | 6 +- include/linux/atalk.h | 18 +++--- include/linux/cycx_x25.h | 66 +++++++++---------- include/linux/if_frad.h | 12 ++-- include/linux/isdnif.h | 70 ++++++++++---------- include/linux/ncp.h | 126 ++++++++++++++++++------------------ include/linux/sdla.h | 64 +++++++++--------- include/linux/wavefront.h | 36 +++++------ include/net/dn_dev.h | 84 ++++++++++++------------ include/net/dn_nsp.h | 74 ++++++++++----------- include/sound/wavefront.h | 36 +++++------ 15 files changed, 341 insertions(+), 341 deletions(-) diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 26c545fa223b..1b85ce166af8 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -396,17 +396,17 @@ struct isar_hw { struct hdlc_stat_reg { #ifdef __BIG_ENDIAN - u_char fill __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char cmd __attribute__((packed)); + u_char fill; + u_char mode; + u_char xml; + u_char cmd; #else - u_char cmd __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char fill __attribute__((packed)); + u_char cmd; + u_char xml; + u_char mode; + u_char fill; #endif -}; +} __attribute__((packed)); struct hdlc_hw { union { diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h index bd8a22e4d6a2..21fbcedf3a94 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.h +++ b/drivers/isdn/hisax/hisax_fcpcipnp.h @@ -12,17 +12,17 @@ enum { struct hdlc_stat_reg { #ifdef __BIG_ENDIAN - u_char fill __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char cmd __attribute__((packed)); + u_char fill; + u_char mode; + u_char xml; + u_char cmd; #else - u_char cmd __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char fill __attribute__((packed)); + u_char cmd; + u_char xml; + u_char mode; + u_char fill; #endif -}; +} __attribute__((packed)); struct fritz_bcs { struct hisax_b_if b_if; diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h index c10f009ce9b6..53b5b071df08 100644 --- a/drivers/net/3c527.h +++ b/drivers/net/3c527.h @@ -32,43 +32,43 @@ struct mc32_mailbox { - u16 mbox __attribute((packed)); - u16 data[1] __attribute((packed)); -}; + u16 mbox; + u16 data[1]; +} __attribute((packed)); struct skb_header { - u8 status __attribute((packed)); - u8 control __attribute((packed)); - u16 next __attribute((packed)); /* Do not change! */ - u16 length __attribute((packed)); - u32 data __attribute((packed)); -}; + u8 status; + u8 control; + u16 next; /* Do not change! */ + u16 length; + u32 data; +} __attribute((packed)); struct mc32_stats { /* RX Errors */ - u32 rx_crc_errors __attribute((packed)); - u32 rx_alignment_errors __attribute((packed)); - u32 rx_overrun_errors __attribute((packed)); - u32 rx_tooshort_errors __attribute((packed)); - u32 rx_toolong_errors __attribute((packed)); - u32 rx_outofresource_errors __attribute((packed)); + u32 rx_crc_errors; + u32 rx_alignment_errors; + u32 rx_overrun_errors; + u32 rx_tooshort_errors; + u32 rx_toolong_errors; + u32 rx_outofresource_errors; - u32 rx_discarded __attribute((packed)); /* via card pattern match filter */ + u32 rx_discarded; /* via card pattern match filter */ /* TX Errors */ - u32 tx_max_collisions __attribute((packed)); - u32 tx_carrier_errors __attribute((packed)); - u32 tx_underrun_errors __attribute((packed)); - u32 tx_cts_errors __attribute((packed)); - u32 tx_timeout_errors __attribute((packed)) ; + u32 tx_max_collisions; + u32 tx_carrier_errors; + u32 tx_underrun_errors; + u32 tx_cts_errors; + u32 tx_timeout_errors; /* various cruft */ - u32 dataA[6] __attribute((packed)); - u16 dataB[5] __attribute((packed)); - u32 dataC[14] __attribute((packed)); -}; + u32 dataA[6]; + u16 dataB[5]; + u32 dataC[14]; +} __attribute((packed)); #define STATUS_MASK 0x0F #define COMPLETED (1<<7) diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index 741aecc655df..a82a4ba8de4f 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -577,8 +577,8 @@ struct ring_descr_hw { struct { u8 addr_res[3]; volatile u8 status; /* descriptor status */ - } rd_s __attribute__((packed)); - } rd_u __attribute((packed)); + } __attribute__((packed)) rd_s; + } __attribute((packed)) rd_u; } __attribute__ ((packed)); #define rd_addr rd_u.addr diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 036adc4f8ba7..22e794071cf4 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -329,9 +329,9 @@ static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr) struct _dlci_stat { - short dlci __attribute__((packed)); - char flags __attribute__((packed)); -}; + short dlci; + char flags; +} __attribute__((packed)); struct _frad_stat { diff --git a/include/linux/atalk.h b/include/linux/atalk.h index 911c09cb9bf9..6ba3aa8a81f4 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -155,15 +155,15 @@ struct elapaarp { #define AARP_REQUEST 1 #define AARP_REPLY 2 #define AARP_PROBE 3 - __u8 hw_src[ETH_ALEN] __attribute__ ((packed)); - __u8 pa_src_zero __attribute__ ((packed)); - __be16 pa_src_net __attribute__ ((packed)); - __u8 pa_src_node __attribute__ ((packed)); - __u8 hw_dst[ETH_ALEN] __attribute__ ((packed)); - __u8 pa_dst_zero __attribute__ ((packed)); - __be16 pa_dst_net __attribute__ ((packed)); - __u8 pa_dst_node __attribute__ ((packed)); -}; + __u8 hw_src[ETH_ALEN]; + __u8 pa_src_zero; + __be16 pa_src_net; + __u8 pa_src_node; + __u8 hw_dst[ETH_ALEN]; + __u8 pa_dst_zero; + __be16 pa_dst_net; + __u8 pa_dst_node; +} __attribute__ ((packed)); static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb) { diff --git a/include/linux/cycx_x25.h b/include/linux/cycx_x25.h index b10a7f3a8cac..f7a906583463 100644 --- a/include/linux/cycx_x25.h +++ b/include/linux/cycx_x25.h @@ -38,11 +38,11 @@ extern unsigned int cycx_debug; /* Data Structures */ /* X.25 Command Block. */ struct cycx_x25_cmd { - u16 command PACKED; - u16 link PACKED; /* values: 0 or 1 */ - u16 len PACKED; /* values: 0 thru 0x205 (517) */ - u32 buf PACKED; -}; + u16 command; + u16 link; /* values: 0 or 1 */ + u16 len; /* values: 0 thru 0x205 (517) */ + u32 buf; +} PACKED; /* Defines for the 'command' field. */ #define X25_CONNECT_REQUEST 0x4401 @@ -92,34 +92,34 @@ struct cycx_x25_cmd { * @flags - see dosx25.doc, in portuguese, for details */ struct cycx_x25_config { - u8 link PACKED; - u8 speed PACKED; - u8 clock PACKED; - u8 n2 PACKED; - u8 n2win PACKED; - u8 n3win PACKED; - u8 nvc PACKED; - u8 pktlen PACKED; - u8 locaddr PACKED; - u8 remaddr PACKED; - u16 t1 PACKED; - u16 t2 PACKED; - u8 t21 PACKED; - u8 npvc PACKED; - u8 t23 PACKED; - u8 flags PACKED; -}; + u8 link; + u8 speed; + u8 clock; + u8 n2; + u8 n2win; + u8 n3win; + u8 nvc; + u8 pktlen; + u8 locaddr; + u8 remaddr; + u16 t1; + u16 t2; + u8 t21; + u8 npvc; + u8 t23; + u8 flags; +} PACKED; struct cycx_x25_stats { - u16 rx_crc_errors PACKED; - u16 rx_over_errors PACKED; - u16 n2_tx_frames PACKED; - u16 n2_rx_frames PACKED; - u16 tx_timeouts PACKED; - u16 rx_timeouts PACKED; - u16 n3_tx_packets PACKED; - u16 n3_rx_packets PACKED; - u16 tx_aborts PACKED; - u16 rx_aborts PACKED; -}; + u16 rx_crc_errors; + u16 rx_over_errors; + u16 n2_tx_frames; + u16 n2_rx_frames; + u16 tx_timeouts; + u16 rx_timeouts; + u16 n3_tx_packets; + u16 n3_rx_packets; + u16 tx_aborts; + u16 rx_aborts; +} PACKED; #endif /* _CYCX_X25_H */ diff --git a/include/linux/if_frad.h b/include/linux/if_frad.h index 511999c7eeda..395f0aad9cbf 100644 --- a/include/linux/if_frad.h +++ b/include/linux/if_frad.h @@ -131,17 +131,17 @@ struct frad_conf /* these are the fields of an RFC 1490 header */ struct frhdr { - unsigned char control __attribute__((packed)); + unsigned char control; /* for IP packets, this can be the NLPID */ - unsigned char pad __attribute__((packed)); + unsigned char pad; - unsigned char NLPID __attribute__((packed)); - unsigned char OUI[3] __attribute__((packed)); - unsigned short PID __attribute__((packed)); + unsigned char NLPID; + unsigned char OUI[3]; + unsigned short PID; #define IP_NLPID pad -}; +} __attribute__((packed)); /* see RFC 1490 for the definition of the following */ #define FRAD_I_UI 0x03 diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index 7a4eacd77cb2..04e10f9f14f8 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -282,43 +282,43 @@ typedef struct setup_parm { typedef struct T30_s { /* session parameters */ - __u8 resolution __attribute__ ((packed)); - __u8 rate __attribute__ ((packed)); - __u8 width __attribute__ ((packed)); - __u8 length __attribute__ ((packed)); - __u8 compression __attribute__ ((packed)); - __u8 ecm __attribute__ ((packed)); - __u8 binary __attribute__ ((packed)); - __u8 scantime __attribute__ ((packed)); - __u8 id[FAXIDLEN] __attribute__ ((packed)); + __u8 resolution; + __u8 rate; + __u8 width; + __u8 length; + __u8 compression; + __u8 ecm; + __u8 binary; + __u8 scantime; + __u8 id[FAXIDLEN]; /* additional parameters */ - __u8 phase __attribute__ ((packed)); - __u8 direction __attribute__ ((packed)); - __u8 code __attribute__ ((packed)); - __u8 badlin __attribute__ ((packed)); - __u8 badmul __attribute__ ((packed)); - __u8 bor __attribute__ ((packed)); - __u8 fet __attribute__ ((packed)); - __u8 pollid[FAXIDLEN] __attribute__ ((packed)); - __u8 cq __attribute__ ((packed)); - __u8 cr __attribute__ ((packed)); - __u8 ctcrty __attribute__ ((packed)); - __u8 minsp __attribute__ ((packed)); - __u8 phcto __attribute__ ((packed)); - __u8 rel __attribute__ ((packed)); - __u8 nbc __attribute__ ((packed)); + __u8 phase; + __u8 direction; + __u8 code; + __u8 badlin; + __u8 badmul; + __u8 bor; + __u8 fet; + __u8 pollid[FAXIDLEN]; + __u8 cq; + __u8 cr; + __u8 ctcrty; + __u8 minsp; + __u8 phcto; + __u8 rel; + __u8 nbc; /* remote station parameters */ - __u8 r_resolution __attribute__ ((packed)); - __u8 r_rate __attribute__ ((packed)); - __u8 r_width __attribute__ ((packed)); - __u8 r_length __attribute__ ((packed)); - __u8 r_compression __attribute__ ((packed)); - __u8 r_ecm __attribute__ ((packed)); - __u8 r_binary __attribute__ ((packed)); - __u8 r_scantime __attribute__ ((packed)); - __u8 r_id[FAXIDLEN] __attribute__ ((packed)); - __u8 r_code __attribute__ ((packed)); -} T30_s; + __u8 r_resolution; + __u8 r_rate; + __u8 r_width; + __u8 r_length; + __u8 r_compression; + __u8 r_ecm; + __u8 r_binary; + __u8 r_scantime; + __u8 r_id[FAXIDLEN]; + __u8 r_code; +} __attribute__((packed)) T30_s; #define ISDN_TTY_FAX_CONN_IN 0 #define ISDN_TTY_FAX_CONN_OUT 1 diff --git a/include/linux/ncp.h b/include/linux/ncp.h index 99f77876b716..99f0adeeb3f3 100644 --- a/include/linux/ncp.h +++ b/include/linux/ncp.h @@ -20,29 +20,29 @@ #define NCP_DEALLOC_SLOT_REQUEST (0x5555) struct ncp_request_header { - __u16 type __attribute__((packed)); - __u8 sequence __attribute__((packed)); - __u8 conn_low __attribute__((packed)); - __u8 task __attribute__((packed)); - __u8 conn_high __attribute__((packed)); - __u8 function __attribute__((packed)); - __u8 data[0] __attribute__((packed)); -}; + __u16 type; + __u8 sequence; + __u8 conn_low; + __u8 task; + __u8 conn_high; + __u8 function; + __u8 data[0]; +} __attribute__((packed)); #define NCP_REPLY (0x3333) #define NCP_WATCHDOG (0x3E3E) #define NCP_POSITIVE_ACK (0x9999) struct ncp_reply_header { - __u16 type __attribute__((packed)); - __u8 sequence __attribute__((packed)); - __u8 conn_low __attribute__((packed)); - __u8 task __attribute__((packed)); - __u8 conn_high __attribute__((packed)); - __u8 completion_code __attribute__((packed)); - __u8 connection_state __attribute__((packed)); - __u8 data[0] __attribute__((packed)); -}; + __u16 type; + __u8 sequence; + __u8 conn_low; + __u8 task; + __u8 conn_high; + __u8 completion_code; + __u8 connection_state; + __u8 data[0]; +} __attribute__((packed)); #define NCP_VOLNAME_LEN (16) #define NCP_NUMBER_OF_VOLUMES (256) @@ -128,37 +128,37 @@ struct nw_nfs_info { }; struct nw_info_struct { - __u32 spaceAlloc __attribute__((packed)); - __le32 attributes __attribute__((packed)); - __u16 flags __attribute__((packed)); - __le32 dataStreamSize __attribute__((packed)); - __le32 totalStreamSize __attribute__((packed)); - __u16 numberOfStreams __attribute__((packed)); - __le16 creationTime __attribute__((packed)); - __le16 creationDate __attribute__((packed)); - __u32 creatorID __attribute__((packed)); - __le16 modifyTime __attribute__((packed)); - __le16 modifyDate __attribute__((packed)); - __u32 modifierID __attribute__((packed)); - __le16 lastAccessDate __attribute__((packed)); - __u16 archiveTime __attribute__((packed)); - __u16 archiveDate __attribute__((packed)); - __u32 archiverID __attribute__((packed)); - __u16 inheritedRightsMask __attribute__((packed)); - __le32 dirEntNum __attribute__((packed)); - __le32 DosDirNum __attribute__((packed)); - __u32 volNumber __attribute__((packed)); - __u32 EADataSize __attribute__((packed)); - __u32 EAKeyCount __attribute__((packed)); - __u32 EAKeySize __attribute__((packed)); - __u32 NSCreator __attribute__((packed)); - __u8 nameLen __attribute__((packed)); - __u8 entryName[256] __attribute__((packed)); + __u32 spaceAlloc; + __le32 attributes; + __u16 flags; + __le32 dataStreamSize; + __le32 totalStreamSize; + __u16 numberOfStreams; + __le16 creationTime; + __le16 creationDate; + __u32 creatorID; + __le16 modifyTime; + __le16 modifyDate; + __u32 modifierID; + __le16 lastAccessDate; + __u16 archiveTime; + __u16 archiveDate; + __u32 archiverID; + __u16 inheritedRightsMask; + __le32 dirEntNum; + __le32 DosDirNum; + __u32 volNumber; + __u32 EADataSize; + __u32 EAKeyCount; + __u32 EAKeySize; + __u32 NSCreator; + __u8 nameLen; + __u8 entryName[256]; /* libncp may depend on there being nothing after entryName */ #ifdef __KERNEL__ struct nw_nfs_info nfs; #endif -}; +} __attribute__((packed)); /* modify mask - use with MODIFY_DOS_INFO structure */ #define DM_ATTRIBUTES (cpu_to_le32(0x02)) @@ -176,26 +176,26 @@ struct nw_info_struct { #define DM_MAXIMUM_SPACE (cpu_to_le32(0x2000)) struct nw_modify_dos_info { - __le32 attributes __attribute__((packed)); - __le16 creationDate __attribute__((packed)); - __le16 creationTime __attribute__((packed)); - __u32 creatorID __attribute__((packed)); - __le16 modifyDate __attribute__((packed)); - __le16 modifyTime __attribute__((packed)); - __u32 modifierID __attribute__((packed)); - __u16 archiveDate __attribute__((packed)); - __u16 archiveTime __attribute__((packed)); - __u32 archiverID __attribute__((packed)); - __le16 lastAccessDate __attribute__((packed)); - __u16 inheritanceGrantMask __attribute__((packed)); - __u16 inheritanceRevokeMask __attribute__((packed)); - __u32 maximumSpace __attribute__((packed)); -}; + __le32 attributes; + __le16 creationDate; + __le16 creationTime; + __u32 creatorID; + __le16 modifyDate; + __le16 modifyTime; + __u32 modifierID; + __u16 archiveDate; + __u16 archiveTime; + __u32 archiverID; + __le16 lastAccessDate; + __u16 inheritanceGrantMask; + __u16 inheritanceRevokeMask; + __u32 maximumSpace; +} __attribute__((packed)); struct nw_search_sequence { - __u8 volNumber __attribute__((packed)); - __u32 dirBase __attribute__((packed)); - __u32 sequence __attribute__((packed)); -}; + __u8 volNumber; + __u32 dirBase; + __u32 sequence; +} __attribute__((packed)); #endif /* _LINUX_NCP_H */ diff --git a/include/linux/sdla.h b/include/linux/sdla.h index 3b6afb8caa42..564acd3a71c1 100644 --- a/include/linux/sdla.h +++ b/include/linux/sdla.h @@ -293,46 +293,46 @@ void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet); #define SDLA_S508_INTEN 0x10 struct sdla_cmd { - char opp_flag __attribute__((packed)); - char cmd __attribute__((packed)); - short length __attribute__((packed)); - char retval __attribute__((packed)); - short dlci __attribute__((packed)); - char flags __attribute__((packed)); - short rxlost_int __attribute__((packed)); - long rxlost_app __attribute__((packed)); - char reserve[2] __attribute__((packed)); - char data[SDLA_MAX_DATA] __attribute__((packed)); /* transfer data buffer */ -}; + char opp_flag; + char cmd; + short length; + char retval; + short dlci; + char flags; + short rxlost_int; + long rxlost_app; + char reserve[2]; + char data[SDLA_MAX_DATA]; /* transfer data buffer */ +} __attribute__((packed)); struct intr_info { - char flags __attribute__((packed)); - short txlen __attribute__((packed)); - char irq __attribute__((packed)); - char flags2 __attribute__((packed)); - short timeout __attribute__((packed)); -}; + char flags; + short txlen; + char irq; + char flags2; + short timeout; +} __attribute__((packed)); /* found in the 508's control window at RXBUF_INFO */ struct buf_info { - unsigned short rse_num __attribute__((packed)); - unsigned long rse_base __attribute__((packed)); - unsigned long rse_next __attribute__((packed)); - unsigned long buf_base __attribute__((packed)); - unsigned short reserved __attribute__((packed)); - unsigned long buf_top __attribute__((packed)); -}; + unsigned short rse_num; + unsigned long rse_base; + unsigned long rse_next; + unsigned long buf_base; + unsigned short reserved; + unsigned long buf_top; +} __attribute__((packed)); /* structure pointed to by rse_base in RXBUF_INFO struct */ struct buf_entry { - char opp_flag __attribute__((packed)); - short length __attribute__((packed)); - short dlci __attribute__((packed)); - char flags __attribute__((packed)); - short timestamp __attribute__((packed)); - short reserved[2] __attribute__((packed)); - long buf_addr __attribute__((packed)); -}; + char opp_flag; + short length; + short dlci; + char flags; + short timestamp; + short reserved[2]; + long buf_addr; +} __attribute__((packed)); #endif diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h index 61bd0fd35240..51ab3c933acd 100644 --- a/include/linux/wavefront.h +++ b/include/linux/wavefront.h @@ -434,22 +434,22 @@ typedef struct wf_multisample { } wavefront_multisample; typedef struct wf_alias { - INT16 OriginalSample __attribute__ ((packed)); - - struct wf_sample_offset sampleStartOffset __attribute__ ((packed)); - struct wf_sample_offset loopStartOffset __attribute__ ((packed)); - struct wf_sample_offset sampleEndOffset __attribute__ ((packed)); - struct wf_sample_offset loopEndOffset __attribute__ ((packed)); - - INT16 FrequencyBias __attribute__ ((packed)); - - UCHAR8 SampleResolution:2 __attribute__ ((packed)); - UCHAR8 Unused1:1 __attribute__ ((packed)); - UCHAR8 Loop:1 __attribute__ ((packed)); - UCHAR8 Bidirectional:1 __attribute__ ((packed)); - UCHAR8 Unused2:1 __attribute__ ((packed)); - UCHAR8 Reverse:1 __attribute__ ((packed)); - UCHAR8 Unused3:1 __attribute__ ((packed)); + INT16 OriginalSample; + + struct wf_sample_offset sampleStartOffset; + struct wf_sample_offset loopStartOffset; + struct wf_sample_offset sampleEndOffset; + struct wf_sample_offset loopEndOffset; + + INT16 FrequencyBias; + + UCHAR8 SampleResolution:2; + UCHAR8 Unused1:1; + UCHAR8 Loop:1; + UCHAR8 Bidirectional:1; + UCHAR8 Unused2:1; + UCHAR8 Reverse:1; + UCHAR8 Unused3:1; /* This structure is meant to be padded only to 16 bits on their original. Of course, whoever wrote their documentation didn't @@ -460,8 +460,8 @@ typedef struct wf_alias { standard 16->32 bit issues. */ - UCHAR8 sixteen_bit_padding __attribute__ ((packed)); -} wavefront_alias; + UCHAR8 sixteen_bit_padding; +} __attribute__((packed)) wavefront_alias; typedef struct wf_drum { UCHAR8 PatchNumber; diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h index 86e8e86e624a..5a86e78081bf 100644 --- a/include/net/dn_dev.h +++ b/include/net/dn_dev.h @@ -88,8 +88,8 @@ struct dn_dev { struct net_device *dev; struct dn_dev_parms parms; char use_long; - struct timer_list timer; - unsigned long t3; + struct timer_list timer; + unsigned long t3; struct neigh_parms *neigh_parms; unsigned char addr[ETH_ALEN]; struct neighbour *router; /* Default router on circuit */ @@ -99,57 +99,57 @@ struct dn_dev { struct dn_short_packet { - unsigned char msgflg __attribute__((packed)); - unsigned short dstnode __attribute__((packed)); - unsigned short srcnode __attribute__((packed)); - unsigned char forward __attribute__((packed)); -}; + unsigned char msgflg; + unsigned short dstnode; + unsigned short srcnode; + unsigned char forward; +} __attribute__((packed)); struct dn_long_packet { - unsigned char msgflg __attribute__((packed)); - unsigned char d_area __attribute__((packed)); - unsigned char d_subarea __attribute__((packed)); - unsigned char d_id[6] __attribute__((packed)); - unsigned char s_area __attribute__((packed)); - unsigned char s_subarea __attribute__((packed)); - unsigned char s_id[6] __attribute__((packed)); - unsigned char nl2 __attribute__((packed)); - unsigned char visit_ct __attribute__((packed)); - unsigned char s_class __attribute__((packed)); - unsigned char pt __attribute__((packed)); -}; + unsigned char msgflg; + unsigned char d_area; + unsigned char d_subarea; + unsigned char d_id[6]; + unsigned char s_area; + unsigned char s_subarea; + unsigned char s_id[6]; + unsigned char nl2; + unsigned char visit_ct; + unsigned char s_class; + unsigned char pt; +} __attribute__((packed)); /*------------------------- DRP - Routing messages ---------------------*/ struct endnode_hello_message { - unsigned char msgflg __attribute__((packed)); - unsigned char tiver[3] __attribute__((packed)); - unsigned char id[6] __attribute__((packed)); - unsigned char iinfo __attribute__((packed)); - unsigned short blksize __attribute__((packed)); - unsigned char area __attribute__((packed)); - unsigned char seed[8] __attribute__((packed)); - unsigned char neighbor[6] __attribute__((packed)); - unsigned short timer __attribute__((packed)); - unsigned char mpd __attribute__((packed)); - unsigned char datalen __attribute__((packed)); - unsigned char data[2] __attribute__((packed)); -}; + unsigned char msgflg; + unsigned char tiver[3]; + unsigned char id[6]; + unsigned char iinfo; + unsigned short blksize; + unsigned char area; + unsigned char seed[8]; + unsigned char neighbor[6]; + unsigned short timer; + unsigned char mpd; + unsigned char datalen; + unsigned char data[2]; +} __attribute__((packed)); struct rtnode_hello_message { - unsigned char msgflg __attribute__((packed)); - unsigned char tiver[3] __attribute__((packed)); - unsigned char id[6] __attribute__((packed)); - unsigned char iinfo __attribute__((packed)); - unsigned short blksize __attribute__((packed)); - unsigned char priority __attribute__((packed)); - unsigned char area __attribute__((packed)); - unsigned short timer __attribute__((packed)); - unsigned char mpd __attribute__((packed)); -}; + unsigned char msgflg; + unsigned char tiver[3]; + unsigned char id[6]; + unsigned char iinfo; + unsigned short blksize; + unsigned char priority; + unsigned char area; + unsigned short timer; + unsigned char mpd; +} __attribute__((packed)); extern void dn_dev_init(void); diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h index 1ba03be0af3a..e6182b86262b 100644 --- a/include/net/dn_nsp.h +++ b/include/net/dn_nsp.h @@ -72,78 +72,78 @@ extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int nobl struct nsp_data_seg_msg { - unsigned char msgflg __attribute__((packed)); - unsigned short dstaddr __attribute__((packed)); - unsigned short srcaddr __attribute__((packed)); -}; + unsigned char msgflg; + unsigned short dstaddr; + unsigned short srcaddr; +} __attribute__((packed)); struct nsp_data_opt_msg { - unsigned short acknum __attribute__((packed)); - unsigned short segnum __attribute__((packed)); - unsigned short lsflgs __attribute__((packed)); -}; + unsigned short acknum; + unsigned short segnum; + unsigned short lsflgs; +} __attribute__((packed)); struct nsp_data_opt_msg1 { - unsigned short acknum __attribute__((packed)); - unsigned short segnum __attribute__((packed)); -}; + unsigned short acknum; + unsigned short segnum; +} __attribute__((packed)); /* Acknowledgment Message (data/other data) */ struct nsp_data_ack_msg { - unsigned char msgflg __attribute__((packed)); - unsigned short dstaddr __attribute__((packed)); - unsigned short srcaddr __attribute__((packed)); - unsigned short acknum __attribute__((packed)); -}; + unsigned char msgflg; + unsigned short dstaddr; + unsigned short srcaddr; + unsigned short acknum; +} __attribute__((packed)); /* Connect Acknowledgment Message */ struct nsp_conn_ack_msg { - unsigned char msgflg __attribute__((packed)); - unsigned short dstaddr __attribute__((packed)); -}; + unsigned char msgflg; + unsigned short dstaddr; +} __attribute__((packed)); /* Connect Initiate/Retransmit Initiate/Connect Confirm */ struct nsp_conn_init_msg { - unsigned char msgflg __attribute__((packed)); + unsigned char msgflg; #define NSP_CI 0x18 /* Connect Initiate */ #define NSP_RCI 0x68 /* Retrans. Conn Init */ - unsigned short dstaddr __attribute__((packed)); - unsigned short srcaddr __attribute__((packed)); - unsigned char services __attribute__((packed)); + unsigned short dstaddr; + unsigned short srcaddr; + unsigned char services; #define NSP_FC_NONE 0x00 /* Flow Control None */ #define NSP_FC_SRC 0x04 /* Seg Req. Count */ #define NSP_FC_SCMC 0x08 /* Sess. Control Mess */ #define NSP_FC_MASK 0x0c /* FC type mask */ - unsigned char info __attribute__((packed)); - unsigned short segsize __attribute__((packed)); -}; + unsigned char info; + unsigned short segsize; +} __attribute__((packed)); /* Disconnect Initiate/Disconnect Confirm */ struct nsp_disconn_init_msg { - unsigned char msgflg __attribute__((packed)); - unsigned short dstaddr __attribute__((packed)); - unsigned short srcaddr __attribute__((packed)); - unsigned short reason __attribute__((packed)); -}; + unsigned char msgflg; + unsigned short dstaddr; + unsigned short srcaddr; + unsigned short reason; +} __attribute__((packed)); struct srcobj_fmt { - char format __attribute__((packed)); - unsigned char task __attribute__((packed)); - unsigned short grpcode __attribute__((packed)); - unsigned short usrcode __attribute__((packed)); - char dlen __attribute__((packed)); -}; + char format; + unsigned char task; + unsigned short grpcode; + unsigned short usrcode; + char dlen; +} __attribute__((packed)); /* * A collection of functions for manipulating the sequence diff --git a/include/sound/wavefront.h b/include/sound/wavefront.h index 9e572aed2435..15d82e594b56 100644 --- a/include/sound/wavefront.h +++ b/include/sound/wavefront.h @@ -454,22 +454,22 @@ typedef struct wf_multisample { } wavefront_multisample; typedef struct wf_alias { - s16 OriginalSample __attribute__ ((packed)); - - struct wf_sample_offset sampleStartOffset __attribute__ ((packed)); - struct wf_sample_offset loopStartOffset __attribute__ ((packed)); - struct wf_sample_offset sampleEndOffset __attribute__ ((packed)); - struct wf_sample_offset loopEndOffset __attribute__ ((packed)); - - s16 FrequencyBias __attribute__ ((packed)); - - u8 SampleResolution:2 __attribute__ ((packed)); - u8 Unused1:1 __attribute__ ((packed)); - u8 Loop:1 __attribute__ ((packed)); - u8 Bidirectional:1 __attribute__ ((packed)); - u8 Unused2:1 __attribute__ ((packed)); - u8 Reverse:1 __attribute__ ((packed)); - u8 Unused3:1 __attribute__ ((packed)); + s16 OriginalSample; + + struct wf_sample_offset sampleStartOffset; + struct wf_sample_offset loopStartOffset; + struct wf_sample_offset sampleEndOffset; + struct wf_sample_offset loopEndOffset; + + s16 FrequencyBias; + + u8 SampleResolution:2; + u8 Unused1:1; + u8 Loop:1; + u8 Bidirectional:1; + u8 Unused2:1; + u8 Reverse:1; + u8 Unused3:1; /* This structure is meant to be padded only to 16 bits on their original. Of course, whoever wrote their documentation didn't @@ -480,8 +480,8 @@ typedef struct wf_alias { standard 16->32 bit issues. */ - u8 sixteen_bit_padding __attribute__ ((packed)); -} wavefront_alias; + u8 sixteen_bit_padding; +} __attribute__((packed)) wavefront_alias; typedef struct wf_drum { u8 PatchNumber; -- cgit v1.2.3 From bfc090c468b33fb1f75c27a11efa7b7dc250556f Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Sun, 8 Jan 2006 01:05:08 -0800 Subject: [PATCH] afs: remove unnecessary __attribute__((packed)) Remove the unnecessary __attribute__((packed)) since the enum itself is packed and not the location of it in the structure. Signed-off-by: Jan Blunck Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/afs/volume.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/afs/volume.h b/fs/afs/volume.h index 1e691889c4c9..bfdcf19ba3f3 100644 --- a/fs/afs/volume.h +++ b/fs/afs/volume.h @@ -18,8 +18,6 @@ #include "kafsasyncd.h" #include "cache.h" -#define __packed __attribute__((packed)) - typedef enum { AFS_VLUPD_SLEEP, /* sleeping waiting for update timer to fire */ AFS_VLUPD_PENDING, /* on pending queue */ @@ -115,7 +113,7 @@ struct afs_volume struct cachefs_cookie *cache; /* caching cookie */ #endif afs_volid_t vid; /* volume ID */ - afs_voltype_t __packed type; /* type of volume */ + afs_voltype_t type; /* type of volume */ char type_force; /* force volume type (suppress R/O -> R/W) */ unsigned short nservers; /* number of server slots filled */ unsigned short rjservers; /* number of servers discarded due to -ENOMEDIUM */ -- cgit v1.2.3 From 9fe656e91fd95d0893cc4831b032e0be60791bd7 Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Sun, 8 Jan 2006 01:05:09 -0800 Subject: [PATCH] i4l: __attribute__((packed)) for the CAPI message structs The CAPI message structs itself should be packed and not the location of single fields in the structure. Signed-off-by: Jan Blunck Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/act2000/capi.h | 88 ++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index e82a9289ad96..49f453c53c64 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -78,29 +78,29 @@ typedef union actcapi_infoel { /* info element */ typedef struct actcapi_msn { __u8 eaz; __u8 len; /* Length of MSN */ - __u8 msn[15] __attribute__ ((packed)); -} actcapi_msn; + __u8 msn[15]; +} __attribute__((packed)) actcapi_msn; typedef struct actcapi_dlpd { __u8 len; /* Length of structure */ - __u16 dlen __attribute__ ((packed)); /* Data Length */ - __u8 laa __attribute__ ((packed)); /* Link Address A */ + __u16 dlen; /* Data Length */ + __u8 laa; /* Link Address A */ __u8 lab; /* Link Address B */ __u8 modulo; /* Modulo Mode */ __u8 win; /* Window size */ __u8 xid[100]; /* XID Information */ -} actcapi_dlpd; +} __attribute__((packed)) actcapi_dlpd; typedef struct actcapi_ncpd { __u8 len; /* Length of structure */ - __u16 lic __attribute__ ((packed)); - __u16 hic __attribute__ ((packed)); - __u16 ltc __attribute__ ((packed)); - __u16 htc __attribute__ ((packed)); - __u16 loc __attribute__ ((packed)); - __u16 hoc __attribute__ ((packed)); - __u8 modulo __attribute__ ((packed)); -} actcapi_ncpd; + __u16 lic; + __u16 hic; + __u16 ltc; + __u16 htc; + __u16 loc; + __u16 hoc; + __u8 modulo; +} __attribute__((packed)) actcapi_ncpd; #define actcapi_ncpi actcapi_ncpd /* @@ -168,19 +168,19 @@ typedef struct actcapi_msg { __u16 manuf_msg; __u16 controller; actcapi_msn msnmap; - } manufacturer_req_msn; + } __attribute ((packed)) manufacturer_req_msn; /* TODO: TraceInit-req/conf/ind/resp and * TraceDump-req/conf/ind/resp */ struct connect_req { __u8 controller; __u8 bchan; - __u32 infomask __attribute__ ((packed)); + __u32 infomask; __u8 si1; __u8 si2; __u8 eaz; actcapi_addr addr; - } connect_req; + } __attribute__ ((packed)) connect_req; struct connect_conf { __u16 plci; __u16 info; @@ -192,7 +192,7 @@ typedef struct actcapi_msg { __u8 si2; __u8 eaz; actcapi_addr addr; - } connect_ind; + } __attribute__ ((packed)) connect_ind; struct connect_resp { __u16 plci; __u8 rejectcause; @@ -200,14 +200,14 @@ typedef struct actcapi_msg { struct connect_active_ind { __u16 plci; actcapi_addr addr; - } connect_active_ind; + } __attribute__ ((packed)) connect_active_ind; struct connect_active_resp { __u16 plci; } connect_active_resp; struct connect_b3_req { __u16 plci; actcapi_ncpi ncpi; - } connect_b3_req; + } __attribute__ ((packed)) connect_b3_req; struct connect_b3_conf { __u16 plci; __u16 ncci; @@ -217,12 +217,12 @@ typedef struct actcapi_msg { __u16 ncci; __u16 plci; actcapi_ncpi ncpi; - } connect_b3_ind; + } __attribute__ ((packed)) connect_b3_ind; struct connect_b3_resp { __u16 ncci; __u8 rejectcause; - actcapi_ncpi ncpi __attribute__ ((packed)); - } connect_b3_resp; + actcapi_ncpi ncpi; + } __attribute__ ((packed)) connect_b3_resp; struct disconnect_req { __u16 plci; __u8 cause; @@ -241,14 +241,14 @@ typedef struct actcapi_msg { struct connect_b3_active_ind { __u16 ncci; actcapi_ncpi ncpi; - } connect_b3_active_ind; + } __attribute__ ((packed)) connect_b3_active_ind; struct connect_b3_active_resp { __u16 ncci; } connect_b3_active_resp; struct disconnect_b3_req { __u16 ncci; actcapi_ncpi ncpi; - } disconnect_b3_req; + } __attribute__ ((packed)) disconnect_b3_req; struct disconnect_b3_conf { __u16 ncci; __u16 info; @@ -257,7 +257,7 @@ typedef struct actcapi_msg { __u16 ncci; __u16 info; actcapi_ncpi ncpi; - } disconnect_b3_ind; + } __attribute__ ((packed)) disconnect_b3_ind; struct disconnect_b3_resp { __u16 ncci; } disconnect_b3_resp; @@ -265,7 +265,7 @@ typedef struct actcapi_msg { __u16 plci; actcapi_infonr nr; actcapi_infoel el; - } info_ind; + } __attribute__ ((packed)) info_ind; struct info_resp { __u16 plci; } info_resp; @@ -279,8 +279,8 @@ typedef struct actcapi_msg { struct select_b2_protocol_req { __u16 plci; __u8 protocol; - actcapi_dlpd dlpd __attribute__ ((packed)); - } select_b2_protocol_req; + actcapi_dlpd dlpd; + } __attribute__ ((packed)) select_b2_protocol_req; struct select_b2_protocol_conf { __u16 plci; __u16 info; @@ -288,47 +288,47 @@ typedef struct actcapi_msg { struct select_b3_protocol_req { __u16 plci; __u8 protocol; - actcapi_ncpd ncpd __attribute__ ((packed)); - } select_b3_protocol_req; + actcapi_ncpd ncpd; + } __attribute__ ((packed)) select_b3_protocol_req; struct select_b3_protocol_conf { __u16 plci; __u16 info; } select_b3_protocol_conf; struct listen_req { __u8 controller; - __u32 infomask __attribute__ ((packed)); - __u16 eazmask __attribute__ ((packed)); - __u16 simask __attribute__ ((packed)); - } listen_req; + __u32 infomask; + __u16 eazmask; + __u16 simask; + } __attribute__ ((packed)) listen_req; struct listen_conf { __u8 controller; - __u16 info __attribute__ ((packed)); - } listen_conf; + __u16 info; + } __attribute__ ((packed)) listen_conf; struct data_b3_req { __u16 fakencci; __u16 datalen; __u32 unused; __u8 blocknr; - __u16 flags __attribute__ ((packed)); - } data_b3_req; + __u16 flags; + } __attribute ((packed)) data_b3_req; struct data_b3_ind { __u16 fakencci; __u16 datalen; __u32 unused; __u8 blocknr; - __u16 flags __attribute__ ((packed)); - } data_b3_ind; + __u16 flags; + } __attribute__ ((packed)) data_b3_ind; struct data_b3_resp { __u16 ncci; __u8 blocknr; - } data_b3_resp; + } __attribute__ ((packed)) data_b3_resp; struct data_b3_conf { __u16 ncci; __u8 blocknr; - __u16 info __attribute__ ((packed)); - } data_b3_conf; + __u16 info; + } __attribute__ ((packed)) data_b3_conf; } msg; -} actcapi_msg; +} __attribute__ ((packed)) actcapi_msg; static inline unsigned short actcapi_nextsmsg(act2000_card *card) -- cgit v1.2.3 From 987d4613e52e4f655278265aabbcc69237018b1d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 8 Jan 2006 01:05:09 -0800 Subject: [PATCH] Make apm buildable without legacy pm APM doesn't _need_ the PM_LEGACY junk, so remove it's dependancy from Kconfig, and ifdef the junk in the code. Whilst the ifdefs are ugly, when the legacy stuff gets ripped out so will the ifdefs. Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/Kconfig | 2 +- arch/i386/kernel/apm.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 486449e9e710..810ba8c37a5f 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -699,7 +699,7 @@ depends on PM && !X86_VISWS config APM tristate "APM (Advanced Power Management) BIOS support" - depends on PM && PM_LEGACY + depends on PM ---help--- APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 2d793d4aef1a..9d8827156e54 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -2291,7 +2291,9 @@ static int __init apm_init(void) apm_info.disabled = 1; return -ENODEV; } +#ifdef CONFIG_PM_LEGACY pm_active = 1; +#endif /* * Set up a segment that references the real mode segment 0x40 @@ -2382,7 +2384,9 @@ static void __exit apm_exit(void) exit_kapmd = 1; while (kapmd_running) schedule(); +#ifdef CONFIG_PM_LEGACY pm_active = 0; +#endif } module_init(apm_init); -- cgit v1.2.3 From ef9ceab28203690a42d7d3915ccf6e208f0762bc Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:05:10 -0800 Subject: [PATCH] remove semicolons from save_flags() Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/interrupt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 41f150a3d2dd..e50a95fbeb11 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -79,7 +79,7 @@ static inline void __deprecated save_flags(unsigned long *x) { local_save_flags(*x); } -#define save_flags(x) save_flags(&x); +#define save_flags(x) save_flags(&x) static inline void __deprecated restore_flags(unsigned long x) { local_irq_restore(x); -- cgit v1.2.3 From 945f390f02ce44a13aefc6d9449c99f33c9286a5 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Sun, 8 Jan 2006 01:05:11 -0800 Subject: [PATCH] drivers/block: Use ARRAY_SIZE macro Use ARRAY_SIZE macro instead of sizeof(x)/sizeof(x[0]) and remove a duplicate of ARRAY_SIZE. Some trailing whitespaces are also removed. drivers/block/acsi* has been left out as it's marked BROKEN. Signed-off-by: Tobias Klauser Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/DAC960.c | 2 +- drivers/block/amiflop.c | 2 +- drivers/block/ataflop.c | 2 +- drivers/block/cciss.c | 4 ++-- drivers/block/cpqarray.c | 4 ++-- drivers/block/floppy.c | 9 ++++----- drivers/block/xd.c | 6 +++--- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 179c68a3cef3..4a7bb7dfce85 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3760,7 +3760,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) if (SenseKey == DAC960_SenseKey_VendorSpecific && AdditionalSenseCode == 0x80 && AdditionalSenseCodeQualifier < - sizeof(DAC960_EventMessages) / sizeof(char *)) + ARRAY_SIZE(DAC960_EventMessages)) DAC960_Critical("Physical Device %d:%d %s\n", Controller, EventLogEntry->Channel, EventLogEntry->TargetID, diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index cb2a545e57dc..3c679d30b698 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -131,7 +131,7 @@ static struct fd_drive_type drive_types[] = { { FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; -static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); +static int num_dr_types = ARRAY_SIZE(drive_types); static int amiga_read(int), dos_read(int); static void amiga_write(int), dos_write(int); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 22bda05fc693..3aa68a5447d6 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -181,7 +181,7 @@ static struct { { 6, TYPE_HD }, /* 31: H1640 <- was H1600 == h1600 for PC */ }; -#define NUM_DISK_MINORS (sizeof(minor2disktype)/sizeof(*minor2disktype)) +#define NUM_DISK_MINORS ARRAY_SIZE(minor2disktype) /* * Maximum disk size (in kilobytes). This default is used whenever the diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 46e8356a962a..74818cc6509b 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -103,7 +103,7 @@ static const struct pci_device_id cciss_pci_device_id[] = { }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); -#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) +#define NR_PRODUCTS ARRAY_SIZE(products) /* board_id = Subsystem Device ID & Vendor ID * product = Marketing Name for the board @@ -2833,7 +2833,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) c->board_id = board_id; #ifdef CCISS_DEBUG - print_cfg_table(c->cfgtable); + print_cfg_table(c->cfgtable); #endif /* CCISS_DEBUG */ for(i=0; icmos < NUMBER(default_drive_params)) { + if (UDP->cmos < ARRAY_SIZE(default_drive_params)) { int i = 0; do { int minor = base_minor + (table_sup[UDP->cmos][i] << 2); @@ -4219,7 +4218,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) !(allowed_drive_mask & (1 << drive)) || fdc_state[FDC(drive)].version == FDC_NONE) return NULL; - if (((*part >> 2) & 0x1f) >= NUMBER(floppy_type)) + if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type)) return NULL; *part = 0; return get_disk(disks[drive]); @@ -4571,7 +4570,7 @@ static void unregister_devfs_entries(int drive) { int i; - if (UDP->cmos < NUMBER(default_drive_params)) { + if (UDP->cmos < ARRAY_SIZE(default_drive_params)) { i = 0; do { devfs_remove("floppy/%d%s", drive, diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 97f5dab24b5a..cbce7c5e9445 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -279,11 +279,11 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address) return(1); } - for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])); i++) { + for (i = 0; i < ARRAY_SIZE(xd_bases); i++) { void __iomem *p = ioremap(xd_bases[i], 0x2000); if (!p) continue; - for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])); j++) { + for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) { const char *s = xd_sigs[j].string; if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) { *controller = j; @@ -1018,7 +1018,7 @@ static void __init do_xd_setup (int *integers) case 2: if ((integers[2] > 0) && (integers[2] < 16)) xd_irq = integers[2]; case 1: xd_override = 1; - if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0])))) + if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs))) xd_type = integers[1]; case 0: break; default:printk("xd: too many parameters for xd\n"); -- cgit v1.2.3 From f756d5e256059018d753f0ba79980ebeb87a1bc0 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Sun, 8 Jan 2006 01:05:12 -0800 Subject: [PATCH] fix workqueue oops during cpu offline Use first_cpu(cpu_possible_map) for the single-thread workqueue case. We used to hardcode 0, but that broke on systems where !cpu_possible(0) when workqueue_struct->cpu_workqueue_struct was changed from a static array to alloc_percpu. Commit id bce61dd49d6ba7799be2de17c772e4c701558f14 ("Fix hardcoded cpu=0 in workqueue for per_cpu_ptr() calls") fixed that for Ben's funky sparc64 system, but it regressed my Power5. Offlining cpu 0 oopses upon the next call to queue_work for a single-thread workqueue, because now we try to manipulate per_cpu_ptr(wq->cpu_wq, 1), which is uninitialized. So we need to establish an unchanging "slot" for single-thread workqueues which will have a valid percpu allocation. Since alloc_percpu keys off of cpu_possible_map, which must not change after initialization, make this slot == first_cpu(cpu_possible_map). Signed-off-by: Nathan Lynch Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/workqueue.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e72fb6478da6..82c4fa70595c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -29,7 +29,8 @@ #include /* - * The per-CPU workqueue (if single thread, we always use cpu 0's). + * The per-CPU workqueue (if single thread, we always use the first + * possible cpu). * * The sequence counters are for flush_scheduled_work(). It wants to wait * until until all currently-scheduled works are completed, but it doesn't @@ -69,6 +70,8 @@ struct workqueue_struct { static DEFINE_SPINLOCK(workqueue_lock); static LIST_HEAD(workqueues); +static int singlethread_cpu; + /* If it's single threaded, it isn't in the list of workqueues. */ static inline int is_single_threaded(struct workqueue_struct *wq) { @@ -102,7 +105,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work) if (!test_and_set_bit(0, &work->pending)) { if (unlikely(is_single_threaded(wq))) - cpu = any_online_cpu(cpu_online_map); + cpu = singlethread_cpu; BUG_ON(!list_empty(&work->entry)); __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); ret = 1; @@ -118,7 +121,7 @@ static void delayed_work_timer_fn(unsigned long __data) int cpu = smp_processor_id(); if (unlikely(is_single_threaded(wq))) - cpu = any_online_cpu(cpu_online_map); + cpu = singlethread_cpu; __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); } @@ -267,7 +270,7 @@ void fastcall flush_workqueue(struct workqueue_struct *wq) if (is_single_threaded(wq)) { /* Always use first cpu's area. */ - flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, any_online_cpu(cpu_online_map))); + flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu)); } else { int cpu; @@ -325,7 +328,7 @@ struct workqueue_struct *__create_workqueue(const char *name, lock_cpu_hotplug(); if (singlethread) { INIT_LIST_HEAD(&wq->list); - p = create_workqueue_thread(wq, any_online_cpu(cpu_online_map)); + p = create_workqueue_thread(wq, singlethread_cpu); if (!p) destroy = 1; else @@ -379,7 +382,7 @@ void destroy_workqueue(struct workqueue_struct *wq) /* We don't need the distraction of CPUs appearing and vanishing. */ lock_cpu_hotplug(); if (is_single_threaded(wq)) - cleanup_workqueue_thread(wq, any_online_cpu(cpu_online_map)); + cleanup_workqueue_thread(wq, singlethread_cpu); else { for_each_online_cpu(cpu) cleanup_workqueue_thread(wq, cpu); @@ -567,6 +570,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, void init_workqueues(void) { + singlethread_cpu = first_cpu(cpu_possible_map); hotcpu_notifier(workqueue_cpu_callback, 0); keventd_wq = create_workqueue("events"); BUG_ON(!keventd_wq); -- cgit v1.2.3 From 96e9dd14a3b2aab4098503a5999ee2ef42d82da1 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Sun, 8 Jan 2006 01:05:13 -0800 Subject: [PATCH] kconf: Check for eof from input stream. Signed-off-by: Ben Collins Cc: Sam Ravnborg Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kconfig/conf.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 8ba5d29d3d42..10eeae53d827 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -63,6 +63,20 @@ static void check_stdin(void) } } +static char *fgets_check_stream(char *s, int size, FILE *stream) +{ + char *ret = fgets(s, size, stream); + + if (ret == NULL && feof(stream)) { + printf(_("aborted!\n\n")); + printf(_("Console input is closed. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); + exit(1); + } + + return ret; +} + static void conf_askvalue(struct symbol *sym, const char *def) { enum symbol_type type = sym_get_type(sym); @@ -100,7 +114,7 @@ static void conf_askvalue(struct symbol *sym, const char *def) check_stdin(); case ask_all: fflush(stdout); - fgets(line, 128, stdin); + fgets_check_stream(line, 128, stdin); return; case set_default: printf("%s\n", def); @@ -356,7 +370,7 @@ static int conf_choice(struct menu *menu) check_stdin(); case ask_all: fflush(stdout); - fgets(line, 128, stdin); + fgets_check_stream(line, 128, stdin); strip(line); if (line[0] == '?') { printf("\n%s\n", menu->sym->help ? -- cgit v1.2.3 From 86f91d36c2aac910b7cf7e5d047019b10a9a627e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 8 Jan 2006 01:05:14 -0800 Subject: [PATCH] i810_audio: request_irq() fix Request the IRQ after having set everything up. Otherwise a shared interrupt at the right time can kill the machine. Found this with David Woodhouse 's debug-shared-irqs.patch. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/oss/i810_audio.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index b9a640fe48b1..4600cd6742ce 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -3359,12 +3359,6 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device goto out_region2; } - if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ, - card_names[pci_id->driver_data], card)) { - printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq); - goto out_pio; - } - if (card->use_mmio) { if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) { if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */ @@ -3395,10 +3389,8 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device } /* initialize AC97 codec and register /dev/mixer */ - if (i810_ac97_init(card) <= 0) { - free_irq(card->irq, card); + if (i810_ac97_init(card) <= 0) goto out_iospace; - } pci_set_drvdata(pci_dev, card); if(clocking == 0) { @@ -3410,7 +3402,6 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) { int i; printk(KERN_ERR "i810_audio: couldn't register DSP device!\n"); - free_irq(card->irq, card); for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL) { unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); @@ -3419,6 +3410,13 @@ static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device goto out_iospace; } + if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ, + card_names[pci_id->driver_data], card)) { + printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq); + goto out_iospace; + } + + card->initializing = 0; return 0; -- cgit v1.2.3 From 0f59cc4a35dbbc45c972daad0f1b063380cd9ea4 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 01:05:15 -0800 Subject: [PATCH] simplify k_getrusage() Factor out common code for different RUSAGE_xxx cases. Don't take ->sighand->siglock in RUSAGE_SELF case, suggested by Ravikiran G Thirumalai . Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sys.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/kernel/sys.c b/kernel/sys.c index 218937e837dc..b6941e06d5d5 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1692,7 +1692,10 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) if (unlikely(!p->signal)) return; + utime = stime = cputime_zero; + switch (who) { + case RUSAGE_BOTH: case RUSAGE_CHILDREN: spin_lock_irqsave(&p->sighand->siglock, flags); utime = p->signal->cutime; @@ -1702,22 +1705,11 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_minflt = p->signal->cmin_flt; r->ru_majflt = p->signal->cmaj_flt; spin_unlock_irqrestore(&p->sighand->siglock, flags); - cputime_to_timeval(utime, &r->ru_utime); - cputime_to_timeval(stime, &r->ru_stime); - break; + + if (who == RUSAGE_CHILDREN) + break; + case RUSAGE_SELF: - spin_lock_irqsave(&p->sighand->siglock, flags); - utime = stime = cputime_zero; - goto sum_group; - case RUSAGE_BOTH: - spin_lock_irqsave(&p->sighand->siglock, flags); - utime = p->signal->cutime; - stime = p->signal->cstime; - r->ru_nvcsw = p->signal->cnvcsw; - r->ru_nivcsw = p->signal->cnivcsw; - r->ru_minflt = p->signal->cmin_flt; - r->ru_majflt = p->signal->cmaj_flt; - sum_group: utime = cputime_add(utime, p->signal->utime); stime = cputime_add(stime, p->signal->stime); r->ru_nvcsw += p->signal->nvcsw; @@ -1734,13 +1726,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_majflt += t->maj_flt; t = next_thread(t); } while (t != p); - spin_unlock_irqrestore(&p->sighand->siglock, flags); - cputime_to_timeval(utime, &r->ru_utime); - cputime_to_timeval(stime, &r->ru_stime); break; + default: BUG(); } + + cputime_to_timeval(utime, &r->ru_utime); + cputime_to_timeval(stime, &r->ru_stime); } int getrusage(struct task_struct *p, int who, struct rusage __user *ru) -- cgit v1.2.3 From 6e21bd9a30f1d7eab26ef8b9259376e5322d89e5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:05:15 -0800 Subject: [PATCH] drivers/isdn/: add missing #includes Every file should #include the headers containing the prototypes for its global functions. Signed-off-by: Adrian Bunk Signed-off-by: Armin Schindler Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/capi/capifs.c | 2 ++ drivers/isdn/hardware/eicon/os_bri.c | 1 + drivers/isdn/hardware/eicon/os_pri.c | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 7b564c0dd996..207cae366256 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -17,6 +17,8 @@ #include #include /* current */ +#include "capifs.h" + MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); diff --git a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c index 4cc44a5dd1db..f31bba5b16ff 100644 --- a/drivers/isdn/hardware/eicon/os_bri.c +++ b/drivers/isdn/hardware/eicon/os_bri.c @@ -16,6 +16,7 @@ #include "diva_pci.h" #include "mi_pc.h" #include "pc_maint.h" +#include "dsrv_bri.h" /* ** IMPORTS diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c index 8ac207f75e54..a296a846f296 100644 --- a/drivers/isdn/hardware/eicon/os_pri.c +++ b/drivers/isdn/hardware/eicon/os_pri.c @@ -18,6 +18,7 @@ #include "pc_maint.h" #include "dsp_tst.h" #include "diva_dma.h" +#include "dsrv_pri.h" /* -------------------------------------------------------------------------- OS Dependent part of XDI driver for DIVA PRI Adapter -- cgit v1.2.3 From 7019e7e41e34388cb87a5f0e3d05e92992418f34 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 8 Jan 2006 01:05:16 -0800 Subject: [PATCH] drivers/isdn/hardware/eicon/os_4bri.c: correct the xdiLoadFile() signature It's not good if caller and callee disagree regarding the type of the arguments. In this case, this could cause problems on 64bit architectures. Signed-off-by: Adrian Bunk Signed-off-by: Armin Schindler Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hardware/eicon/os_4bri.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index cccfabc1117d..11e6f937c1e4 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -16,6 +16,7 @@ #include "diva_pci.h" #include "mi_pc.h" #include "dsrv4bri.h" +#include "helpers.h" static void *diva_xdiLoadFileFile = NULL; static dword diva_xdiLoadFileLength = 0; @@ -815,7 +816,7 @@ diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a, return (ret); } -void *xdiLoadFile(char *FileName, unsigned long *FileLength, +void *xdiLoadFile(char *FileName, dword *FileLength, unsigned long lim) { void *ret = diva_xdiLoadFileFile; -- cgit v1.2.3 From 564de74a7e2778e1d11b2d2e50ee8dab1cf1456a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 8 Jan 2006 01:05:17 -0800 Subject: [PATCH] cciss: avoid defining useless MAJOR_NR macro This sneaked in with one of the updates. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 2 +- drivers/block/cciss.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 74818cc6509b..88452c79fb64 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3118,7 +3118,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, * 8 controller support. */ if (i < MAX_CTLR_ORIG) - hba[i]->major = MAJOR_NR + i; + hba[i]->major = COMPAQ_CISS_MAJOR + i; rc = register_blkdev(hba[i]->major, hba[i]->devname); if(rc == -EBUSY || rc == -EINVAL) { printk(KERN_ERR diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index ad45e581a91d..b24fc0553ccf 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -13,8 +13,6 @@ #define IO_OK 0 #define IO_ERROR 1 -#define MAJOR_NR COMPAQ_CISS_MAJOR - struct ctlr_info; typedef struct ctlr_info ctlr_info_t; -- cgit v1.2.3 From e701e85b9f12af4dbe73b4299b541686ef6b1aa5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 8 Jan 2006 01:05:18 -0800 Subject: [PATCH] vr41xx: section tags fix module_init functions must be tagged __init rather than __devinit; likewise, module_exit functions must be tagged __exit rather than __devexit. Signed-off-by: Jean Delvare Cc: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/vr41xx_giu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 9ac6d43437b3..a5b18e086a94 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -718,7 +718,7 @@ static struct platform_driver giu_device_driver = { }, }; -static int __devinit vr41xx_giu_init(void) +static int __init vr41xx_giu_init(void) { int retval; @@ -733,7 +733,7 @@ static int __devinit vr41xx_giu_init(void) return retval; } -static void __devexit vr41xx_giu_exit(void) +static void __exit vr41xx_giu_exit(void) { platform_driver_unregister(&giu_device_driver); -- cgit v1.2.3 From d960600df3ce3588571e2c1adf1f5f6d8ca9eb5a Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:19 -0800 Subject: [PATCH] tiny: Add bloat-o-meter to scripts This is a rewrite of Andi Kleen's bloat-o-meter with sorting and reporting of gainers/decliners. Sample output: add/remove: 0/8 grow/shrink: 2/0 up/down: 88/-4424 (-4336) function old new delta __copy_to_user_ll 59 103 +44 __copy_from_user_ll 59 103 +44 fill_note 32 - -32 maydump 58 - -58 dump_seek 67 - -67 writenote 180 - -180 elf_dump_thread_status 274 - -274 fill_psinfo 308 - -308 fill_prstatus 466 - -466 elf_core_dump 3039 - -3039 The summary line says: no functions added, 8 removed two functions grew, none shrunk we gained 88 bytes and lost 4424 (or -4336 net) This work was sponsored in part by CE Linux Forum Signed-off-by: Matt Mackall Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/bloat-o-meter | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 scripts/bloat-o-meter diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter new file mode 100644 index 000000000000..75f21d843c1d --- /dev/null +++ b/scripts/bloat-o-meter @@ -0,0 +1,58 @@ +#!/usr/bin/python +# +# Copyright 2004 Matt Mackall +# +# inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +import sys, os, re + +if len(sys.argv) != 3: + sys.stderr.write("usage: %s file1 file2\n" % sys.argv[0]) + sys.exit(-1) + +def getsizes(file): + sym = {} + for l in os.popen("nm --size-sort " + file).readlines(): + size, type, name = l[:-1].split() + if type in "tTdDbB": + sym[name] = int(size, 16) + return sym + +old = getsizes(sys.argv[1]) +new = getsizes(sys.argv[2]) +grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 +delta, common = [], {} + +for a in old: + if a in new: + common[a] = 1 + +for name in old: + if name not in common: + remove += 1 + down += old[name] + delta.append((-old[name], name)) + +for name in new: + if name not in common: + add += 1 + up += new[name] + delta.append((new[name], name)) + +for name in common: + d = new.get(name, 0) - old.get(name, 0) + if d>0: grow, up = grow+1, up+d + if d<0: shrink, down = shrink+1, down-d + delta.append((d, name)) + +delta.sort() +delta.reverse() + +print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ + (add, remove, grow, shrink, up, -down, up-down) +print "%-40s %7s %7s %+7s" % ("function", "old", "new", "delta") +for d, n in delta: + if d: print "%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d) -- cgit v1.2.3 From b01ec0ef63e95570e2463b26333d9c9c854cb941 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:20 -0800 Subject: [PATCH] tiny: Uninline some open.c functions uninline some open.c functions add/remove: 3/0 grow/shrink: 0/6 up/down: 679/-1166 (-487) function old new delta do_sys_truncate - 336 +336 do_sys_ftruncate - 317 +317 __put_unused_fd - 26 +26 put_unused_fd 57 49 -8 sys_close 150 119 -31 sys_ftruncate64 260 26 -234 sys_ftruncate 272 24 -248 sys_truncate 339 25 -314 sys_truncate64 336 5 -331 Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/open.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/open.c b/fs/open.c index 94968cb3afca..75f3329e8a67 100644 --- a/fs/open.c +++ b/fs/open.c @@ -217,7 +217,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, return err; } -static inline long do_sys_truncate(const char __user * path, loff_t length) +static long do_sys_truncate(const char __user * path, loff_t length) { struct nameidata nd; struct inode * inode; @@ -283,7 +283,7 @@ asmlinkage long sys_truncate(const char __user * path, unsigned long length) return do_sys_truncate(path, (long)length); } -static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small) +static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode * inode; struct dentry *dentry; @@ -971,7 +971,7 @@ out: EXPORT_SYMBOL(get_unused_fd); -static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) +static void __put_unused_fd(struct files_struct *files, unsigned int fd) { struct fdtable *fdt = files_fdtable(files); __FD_CLR(fd, fdt->open_fds); -- cgit v1.2.3 From 5d2bea4582d20cb24085152acaa29b95c05cdcf8 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:21 -0800 Subject: [PATCH] tiny: Uninline some inode.c functions uninline a couple inode.c functions add/remove: 2/0 grow/shrink: 0/5 up/down: 256/-428 (-172) function old new delta ifind - 136 +136 ifind_fast - 120 +120 ilookup5_nowait 131 80 -51 ilookup 158 71 -87 ilookup5 171 80 -91 iget_locked 190 95 -95 iget5_locked 240 136 -104 Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index d8d04bd72b59..fd568caf7f74 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -770,7 +770,7 @@ EXPORT_SYMBOL(igrab); * * Note, @test is called with the inode_lock held, so can't sleep. */ -static inline struct inode *ifind(struct super_block *sb, +static struct inode *ifind(struct super_block *sb, struct hlist_head *head, int (*test)(struct inode *, void *), void *data, const int wait) { @@ -804,7 +804,7 @@ static inline struct inode *ifind(struct super_block *sb, * * Otherwise NULL is returned. */ -static inline struct inode *ifind_fast(struct super_block *sb, +static struct inode *ifind_fast(struct super_block *sb, struct hlist_head *head, unsigned long ino) { struct inode *inode; -- cgit v1.2.3 From 33443c42f4ffa5ca23b3323234bcb1a78e85d9db Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:22 -0800 Subject: [PATCH] tiny: Uninline some fslocks.c functions uninline some file locking functions add/remove: 3/0 grow/shrink: 0/15 up/down: 256/-1525 (-1269) function old new delta locks_free_lock - 134 +134 posix_same_owner - 69 +69 __locks_delete_block - 53 +53 posix_locks_conflict 126 108 -18 locks_remove_posix 266 237 -29 locks_wake_up_blocks 121 87 -34 locks_block_on_timeout 83 47 -36 locks_insert_block 157 120 -37 locks_delete_block 62 23 -39 posix_unblock_lock 104 59 -45 posix_locks_deadlock 162 100 -62 locks_delete_lock 228 119 -109 sys_flock 338 217 -121 __break_lease 600 474 -126 lease_init 252 122 -130 fcntl_setlk64 793 649 -144 fcntl_setlk 793 649 -144 __posix_lock_file 1477 1026 -451 Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/locks.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index fb32d6218e21..909eab8fb1d0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -154,7 +154,7 @@ static struct file_lock *locks_alloc_lock(void) } /* Free a lock which is not in use. */ -static inline void locks_free_lock(struct file_lock *fl) +static void locks_free_lock(struct file_lock *fl) { if (fl == NULL) { BUG(); @@ -475,8 +475,7 @@ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2) /* * Check whether two locks have the same owner. */ -static inline int -posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) +static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) { if (fl1->fl_lmops && fl1->fl_lmops->fl_compare_owner) return fl2->fl_lmops == fl1->fl_lmops && @@ -487,7 +486,7 @@ posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) /* Remove waiter from blocker's block list. * When blocker ends up pointing to itself then the list is empty. */ -static inline void __locks_delete_block(struct file_lock *waiter) +static void __locks_delete_block(struct file_lock *waiter) { list_del_init(&waiter->fl_block); list_del_init(&waiter->fl_link); -- cgit v1.2.3 From 18e92b12e83bef077a31ba6871f1aec3621b69e3 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:22 -0800 Subject: [PATCH] tiny: Trim non-IPX builds trivial: drop unused 802.3 code if we compile without IPX (originally from http://wohnheim.fh-wedel.de/~joern/software/kernel/je/25/) Signed-off-by: Matt Mackall Cc: "David S. Miller" Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- net/802/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/802/Makefile b/net/802/Makefile index 01861929591a..977704a54f68 100644 --- a/net/802/Makefile +++ b/net/802/Makefile @@ -2,8 +2,6 @@ # Makefile for the Linux 802.x protocol layers. # -obj-y := p8023.o - # Check the p8022 selections against net/core/Makefile. obj-$(CONFIG_SYSCTL) += sysctl_net_802.o obj-$(CONFIG_LLC) += p8022.o psnap.o @@ -11,5 +9,5 @@ obj-$(CONFIG_TR) += p8022.o psnap.o tr.o sysctl_net_802.o obj-$(CONFIG_NET_FC) += fc.o obj-$(CONFIG_FDDI) += fddi.o obj-$(CONFIG_HIPPI) += hippi.o -obj-$(CONFIG_IPX) += p8022.o psnap.o +obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o obj-$(CONFIG_ATALK) += p8022.o psnap.o -- cgit v1.2.3 From 22c4e3084eb8b88288a622a57d8b35c450a439f2 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:24 -0800 Subject: [PATCH] tiny: Make x86 doublefault handling optional This adds configurable support for doublefault reporting on x86 add/remove: 0/3 grow/shrink: 0/1 up/down: 0/-13048 (-13048) function old new delta cpu_init 846 786 -60 doublefault_fn 188 - -188 doublefault_stack 4096 - -4096 doublefault_tss 8704 - -8704 Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/Makefile | 3 ++- arch/i386/kernel/cpu/common.c | 2 ++ init/Kconfig | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index f10de0f2c5e6..4f40589e179c 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o quirks.o i8237.o + quirks.o i8237.o obj-y += cpu/ obj-y += timers/ @@ -33,6 +33,7 @@ obj-y += sysenter.o vsyscall.o obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o +obj-$(CONFIG_DOUBLEFAULT) += doublefault.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o EXTRA_AFLAGS := -traditional diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index cca655688ffc..170400879f44 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -609,8 +609,10 @@ void __devinit cpu_init(void) load_TR_desc(); load_LDT(&init_mm.context); +#ifdef CONFIG_DOUBLEFAULT /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); +#endif /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); diff --git a/init/Kconfig b/init/Kconfig index 0c9932f9f06b..0eb65f2ad8c9 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -309,6 +309,15 @@ config BUG option for embedded systems with no facilities for reporting errors. Just say Y. +config DOUBLEFAULT + depends X86 + default y if X86 + bool "Enable doublefault exception handler" if EMBEDDED + help + This option allows trapping of rare doublefault exceptions that + would otherwise cause a system to silently reboot. Disabling this + option saves about 4k. + config BASE_FULL default y bool "Enable full-sized data structures for core" if EMBEDDED -- cgit v1.2.3 From e585e47031751f4e393e10ffd922885508b958dd Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:24 -0800 Subject: [PATCH] tiny: Make *[ug]id16 support optional Configurable 16-bit UID and friends support This allows turning off the legacy 16 bit UID interfaces on embedded platforms. text data bss dec hex filename 3330172 529036 190556 4049764 3dcb64 vmlinux-baseline 3328268 529040 190556 4047864 3dc3f8 vmlinux From: Adrian Bunk UID16 was accidentially disabled for !EMBEDDED. Signed-off-by: Matt Mackall Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/Kconfig | 3 --- arch/arm/Kconfig | 4 ---- arch/arm26/Kconfig | 4 ---- arch/cris/Kconfig | 4 ---- arch/h8300/Kconfig | 4 ---- arch/i386/Kconfig | 4 ---- arch/m68k/Kconfig | 4 ---- arch/m68knommu/Kconfig | 4 ---- arch/parisc/Kconfig | 3 --- arch/powerpc/Kconfig | 3 --- arch/ppc/Kconfig | 3 --- arch/sh/Kconfig | 4 ---- arch/sparc/Kconfig | 4 ---- arch/sparc64/Kconfig | 5 ----- arch/um/Kconfig | 4 ---- arch/v850/Kconfig | 3 --- arch/x86_64/Kconfig | 5 ----- init/Kconfig | 9 +++++++++ kernel/sys_ni.c | 19 +++++++++++++++++++ 19 files changed, 28 insertions(+), 65 deletions(-) diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 153337ff1d7b..eedf41bf7057 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -18,9 +18,6 @@ config MMU bool default y -config UID16 - bool - config RWSEM_GENERIC_SPINLOCK bool diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 16a5d522b2f2..7a74e3e5f916 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -46,10 +46,6 @@ config MCA (and especially the web page given there) before attempting to build an MCA bus kernel. -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index 1f00b3d03a07..274e07019b46 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -34,10 +34,6 @@ config FORCE_MAX_ZONEORDER int default 9 -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index e5979d68e352..b83261949737 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -9,10 +9,6 @@ config MMU bool default y -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 26698a49f153..80940d712acf 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -21,10 +21,6 @@ config FPU bool default n -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 810ba8c37a5f..d849c6870e3a 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -29,10 +29,6 @@ config MMU config SBUS bool -config UID16 - bool - default y - config GENERIC_ISA_DMA bool default y diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 1dd5d18b2201..96b919828053 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -10,10 +10,6 @@ config MMU bool default y -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index b96498120fe9..e2a6e8648960 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -17,10 +17,6 @@ config FPU bool default n -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 874a283edb95..e77a06e9621e 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -19,9 +19,6 @@ config MMU config STACK_GROWSUP def_bool y -config UID16 - bool - config RWSEM_GENERIC_SPINLOCK def_bool y diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index db93dbc0e21a..331483ace0d9 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -26,9 +26,6 @@ config MMU bool default y -config UID16 - bool - config GENERIC_HARDIRQS bool default y diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index cc3f64c084c5..e396f4591d59 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -8,9 +8,6 @@ config MMU bool default y -config UID16 - bool - config GENERIC_HARDIRQS bool default y diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 64f5ae0ff96d..8cf6d437a630 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -14,10 +14,6 @@ config SUPERH gaming console. The SuperH port has a home page at . -config UID16 - bool - default y - config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 56c34e7fd4ee..f944b58cdfe7 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -9,10 +9,6 @@ config MMU bool default y -config UID16 - bool - default y - config HIGHMEM bool default y diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index c4b7ad70cd7c..b775ceb4cf98 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -309,11 +309,6 @@ config COMPAT depends on SPARC32_COMPAT default y -config UID16 - bool - depends on SPARC32_COMPAT - default y - config BINFMT_ELF32 tristate "Kernel support for 32-bit ELF binaries" depends on SPARC32_COMPAT diff --git a/arch/um/Kconfig b/arch/um/Kconfig index cdaa2ab19258..b4ff2e576021 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -22,10 +22,6 @@ config SBUS config PCI bool -config UID16 - bool - default y - config GENERIC_CALIBRATE_DELAY bool default y diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig index 310865903234..04494638b963 100644 --- a/arch/v850/Kconfig +++ b/arch/v850/Kconfig @@ -10,9 +10,6 @@ mainmenu "uClinux/v850 (w/o MMU) Kernel Configuration" config MMU bool default n -config UID16 - bool - default n config RWSEM_GENERIC_SPINLOCK bool default y diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 6ece645e4dbe..4f3e925962c3 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -542,11 +542,6 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y -config UID16 - bool - depends on IA32_EMULATION - default y - endmenu source "net/Kconfig" diff --git a/init/Kconfig b/init/Kconfig index 0eb65f2ad8c9..1a1f114a37e8 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -228,6 +228,15 @@ config CPUSETS source "usr/Kconfig" +config UID16 + bool "Enable 16-bit UID system calls" if EMBEDDED + depends !ALPHA && !PPC && !PPC64 && !PARISC && !V850 && !ARCH_S390X + depends !X86_64 || IA32_EMULATION + depends !SPARC64 || SPARC32_COMPAT + default y + help + This enables the legacy 16-bit UID syscall wrappers. + config CC_OPTIMIZE_FOR_SIZE bool "Optimize for size (Look out for broken compilers!)" default y diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 7a8bc7f60d91..72cafc922d39 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -83,6 +83,25 @@ cond_syscall(sys_inotify_init); cond_syscall(sys_inotify_add_watch); cond_syscall(sys_inotify_rm_watch); cond_syscall(sys_migrate_pages); +cond_syscall(sys_chown16); +cond_syscall(sys_fchown16); +cond_syscall(sys_getegid16); +cond_syscall(sys_geteuid16); +cond_syscall(sys_getgid16); +cond_syscall(sys_getgroups16); +cond_syscall(sys_getresgid16); +cond_syscall(sys_getresuid16); +cond_syscall(sys_getuid16); +cond_syscall(sys_lchown16); +cond_syscall(sys_setfsgid16); +cond_syscall(sys_setfsuid16); +cond_syscall(sys_setgid16); +cond_syscall(sys_setgroups16); +cond_syscall(sys_setregid16); +cond_syscall(sys_setresgid16); +cond_syscall(sys_setresuid16); +cond_syscall(sys_setreuid16); +cond_syscall(sys_setuid16); /* arch-specific weak syscall entries */ cond_syscall(sys_pciconfig_read); -- cgit v1.2.3 From 708e9a794cf8822b760edaccd9053edb07c34d19 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:25 -0800 Subject: [PATCH] tiny: Configure ELF core dump support configurable support for ELF core dumps text data bss dec hex filename 3330172 529036 190556 4049764 3dcb64 vmlinux-baseline 3325552 528912 190556 4045020 3db8dc vmlinux-no-elf add/remove: 0/8 grow/shrink: 0/0 up/down: 0/-4424 (-4424) function old new delta fill_note 32 - -32 maydump 58 - -58 dump_seek 67 - -67 writenote 180 - -180 elf_dump_thread_status 274 - -274 fill_psinfo 308 - -308 fill_prstatus 466 - -466 elf_core_dump 3039 - -3039 Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_elf.c | 4 ++-- init/Kconfig | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 288386b1deff..80ca932ba0bd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -58,7 +58,7 @@ extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); * If we don't support core dumping, then supply a NULL so we * don't even try. */ -#ifdef USE_ELF_CORE_DUMP +#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file); #else #define elf_core_dump NULL @@ -1113,7 +1113,7 @@ out: * Note that some platforms still use traditional core dumps and not * the ELF core dump. Each platform can select it as appropriate. */ -#ifdef USE_ELF_CORE_DUMP +#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) /* * ELF core dumper diff --git a/init/Kconfig b/init/Kconfig index 1a1f114a37e8..9ac522a40130 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -327,6 +327,12 @@ config DOUBLEFAULT would otherwise cause a system to silently reboot. Disabling this option saves about 4k. +config ELF_CORE + default y + bool "Enable ELF core dumps" if EMBEDDED + help + Enable support for generating core dumps. Disabling saves about 4k. + config BASE_FULL default y bool "Enable full-sized data structures for core" if EMBEDDED -- cgit v1.2.3 From 64ca9004b819ab87648dbfc78f3ef49ee491343e Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 8 Jan 2006 01:05:26 -0800 Subject: [PATCH] Make vm86 support optional This adds an option to remove vm86 support under CONFIG_EMBEDDED. Saves about 5k. This version eliminates most of the #ifdefs of the previous version and instead uses function stubs in vm86.h. Also, release_vm86_irqs is moved from asm-i386/irq.h to a more appropriate home in vm86.h so that the stubs can live together. $ size vmlinux-baseline vmlinux-novm86 text data bss dec hex filename 2920821 523232 190652 3634705 377611 vmlinux-baseline 2916268 523100 190492 3629860 376324 vmlinux-novm86 Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/Makefile | 3 ++- arch/i386/kernel/entry.S | 2 ++ arch/i386/kernel/process.c | 1 + include/asm-i386/irq.h | 2 -- include/asm-i386/vm86.h | 20 ++++++++++++++++++++ init/Kconfig | 10 ++++++++++ kernel/sys_ni.c | 2 ++ 7 files changed, 37 insertions(+), 3 deletions(-) diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 4f40589e179c..be1880bb75b4 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o init_task.o vmlinux.lds -obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ +obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ quirks.o i8237.o @@ -34,6 +34,7 @@ obj-$(CONFIG_ACPI_SRAT) += srat.o obj-$(CONFIG_HPET_TIMER) += time_hpet.o obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_DOUBLEFAULT) += doublefault.o +obj-$(CONFIG_VM86) += vm86.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o EXTRA_AFLAGS := -traditional diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 607c06007508..4d704724b2f5 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -323,6 +323,7 @@ work_notifysig: # deal with pending signals and ALIGN work_notifysig_v86: +#ifdef CONFIG_VM86 pushl %ecx # save ti_flags for do_notify_resume call save_v86_state # %eax contains pt_regs pointer popl %ecx @@ -330,6 +331,7 @@ work_notifysig_v86: xorl %edx, %edx call do_notify_resume jmp resume_userspace +#endif # perform syscall exit tracing ALIGN diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 45e7f0ac4b04..035928f3f6c1 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -48,6 +48,7 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h index 270f1986b19f..5169d7af456f 100644 --- a/include/asm-i386/irq.h +++ b/include/asm-i386/irq.h @@ -21,8 +21,6 @@ static __inline__ int irq_canonicalize(int irq) return ((irq == 2) ? 9 : irq); } -extern void release_vm86_irqs(struct task_struct *); - #ifdef CONFIG_X86_LOCAL_APIC # define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ #endif diff --git a/include/asm-i386/vm86.h b/include/asm-i386/vm86.h index 40ec82c6914d..952fd6957380 100644 --- a/include/asm-i386/vm86.h +++ b/include/asm-i386/vm86.h @@ -16,7 +16,11 @@ #define IF_MASK 0x00000200 #define IOPL_MASK 0x00003000 #define NT_MASK 0x00004000 +#ifdef CONFIG_VM86 #define VM_MASK 0x00020000 +#else +#define VM_MASK 0 /* ignored */ +#endif #define AC_MASK 0x00040000 #define VIF_MASK 0x00080000 /* virtual interrupt flag */ #define VIP_MASK 0x00100000 /* virtual interrupt pending */ @@ -200,9 +204,25 @@ struct kernel_vm86_struct { */ }; +#ifdef CONFIG_VM86 + void handle_vm86_fault(struct kernel_vm86_regs *, long); int handle_vm86_trap(struct kernel_vm86_regs *, long, int); +struct task_struct; +void release_vm86_irqs(struct task_struct *); + +#else + +#define handle_vm86_fault(a, b) +#define release_vm86_irqs(a) + +static inline int handle_vm86_trap(struct kernel_vm86_regs *a, long b, int c) { + return 0; +} + +#endif /* CONFIG_VM86 */ + #endif /* __KERNEL__ */ #endif diff --git a/init/Kconfig b/init/Kconfig index 9ac522a40130..f8f6929d8f25 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -237,6 +237,16 @@ config UID16 help This enables the legacy 16-bit UID syscall wrappers. +config VM86 + depends X86 + default y + bool "Enable VM86 support" if EMBEDDED + help + This option is required by programs like DOSEMU to run 16-bit legacy + code on X86 processors. It also may be needed by software like + XFree86 to initialize some video cards via BIOS. Disabling this + option saves about 6k. + config CC_OPTIMIZE_FOR_SIZE bool "Optimize for size (Look out for broken compilers!)" default y diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 72cafc922d39..bd3b9bfcfcec 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -102,6 +102,8 @@ cond_syscall(sys_setresgid16); cond_syscall(sys_setresuid16); cond_syscall(sys_setreuid16); cond_syscall(sys_setuid16); +cond_syscall(sys_vm86old); +cond_syscall(sys_vm86); /* arch-specific weak syscall entries */ cond_syscall(sys_pciconfig_read); -- cgit v1.2.3 From 021c73354921a315ae2fceb1ad7807d1569a5a74 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Dec 2005 22:45:27 +0100 Subject: [PATCH] powerpc: fix two build warnings Building the arch/powerpc tree currently gives me two warnings with gcc-4.0: arch/powerpc/mm/imalloc.c: In function '__im_get_area': arch/powerpc/mm/imalloc.c:225: warning: 'tmp' may be used uninitialized in this function arch/powerpc/mm/hugetlbpage.c: In function 'hugetlb_get_unmapped_area': arch/powerpc/mm/hugetlbpage.c:608: warning: unused variable 'vma' both fixes are trivial. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/mm/hugetlbpage.c | 1 - arch/powerpc/mm/imalloc.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index f6fe3eaf87a3..b51bb28c054b 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -620,7 +620,6 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, { int lastshift; u16 areamask, curareas; - struct vm_area_struct *vma; if (HPAGE_SHIFT == 0) return -EINVAL; diff --git a/arch/powerpc/mm/imalloc.c b/arch/powerpc/mm/imalloc.c index f9587bcc6a48..8b0c132bc163 100644 --- a/arch/powerpc/mm/imalloc.c +++ b/arch/powerpc/mm/imalloc.c @@ -107,6 +107,7 @@ static int im_region_status(unsigned long v_addr, unsigned long size, if (v_addr < (unsigned long) tmp->addr + tmp->size) break; + *vm = NULL; if (tmp) { if (im_region_overlaps(v_addr, size, tmp)) return IM_REGION_OVERLAP; @@ -127,7 +128,6 @@ static int im_region_status(unsigned long v_addr, unsigned long size, } } - *vm = NULL; return IM_REGION_UNUSED; } -- cgit v1.2.3 From b226e462124522f2f23153daff31c311729dfa2f Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Fri, 16 Dec 2005 14:30:35 -0800 Subject: [PATCH] powerpc: don't add memory to empty node/zone The system will oops if an attempt is made to add memory to an empty node/zone. This patch prevents adding memory to an empty node. The code to dynamically add a node/zone is non-trivial. This patch is temporary and will be removed when the ability to dynamically add a node/zone is complete. Signed-off-by: Mike Kravetz Signed-off-by: Paul Mackerras --- arch/powerpc/mm/numa.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index fc6f8ee9656f..2863a912bcd0 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -766,13 +766,15 @@ early_param("numa", early_numa); int hot_add_scn_to_nid(unsigned long scn_addr) { struct device_node *memory = NULL; + nodemask_t nodes; + int numa_domain = 0; if (!numa_enabled || (min_common_depth < 0)) - return 0; + return numa_domain; while ((memory = of_find_node_by_type(memory, "memory")) != NULL) { unsigned long start, size; - int numa_domain, ranges; + int ranges; unsigned int *memcell_buf; unsigned int len; @@ -793,14 +795,21 @@ ha_new_range: if ((scn_addr >= start) && (scn_addr < (start + size))) { of_node_put(memory); - return numa_domain; + goto got_numa_domain; } if (--ranges) /* process all ranges in cell */ goto ha_new_range; } - BUG(); /* section address should be found above */ - return 0; + + /* Temporary code to ensure that returned node is not empty */ +got_numa_domain: + nodes_setall(nodes); + while (NODE_DATA(numa_domain)->node_spanned_pages == 0) { + node_clear(numa_domain, nodes); + numa_domain = any_online_node(nodes); + } + return numa_domain; } #endif /* CONFIG_MEMORY_HOTPLUG */ -- cgit v1.2.3 From d0e132b536b6c8044991932d0c160676c46c98e5 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 20 Dec 2005 16:16:26 -0600 Subject: [PATCH] powerpc: Loosen udbg_probe_uart_speed sanity checking The checking of the baudrate in udbg_probe_uart_speed was too tight and would cause reporting back of the default baud rate in cases where the computed speed was valid. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/udbg_16550.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index e58c048a7b19..7541bf44d2da 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -137,7 +137,7 @@ unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock) speed = (clock / prescaler) / (divisor * 16); /* sanity check */ - if (speed < 9600 || speed > 115200) + if (speed < 0 || speed > (clock / 16)) speed = 9600; return speed; -- cgit v1.2.3 From b580d46ce833f6bdc6a5602f4f0efb1d9c488ed6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 20 Dec 2005 16:16:52 -0600 Subject: [PATCH] powerpc: Add the ability to handle SOC ports in legacy_serial Add the ability to configure and initialize legacy 8250 serials ports on an SOC bus. Also, fixed an issue that we would not configure any serial ports if "linux,stdout-path" was not found. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 62 +++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index d179ec502292..59164ba2eb1c 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -36,7 +36,8 @@ static int legacy_serial_console = -1; static int __init add_legacy_port(struct device_node *np, int want_index, int iotype, phys_addr_t base, - phys_addr_t taddr, unsigned long irq) + phys_addr_t taddr, unsigned long irq, + unsigned int flags) { u32 *clk, *spd, clock = BASE_BAUD * 16; int index; @@ -90,7 +91,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, legacy_serial_ports[index].iotype = iotype; legacy_serial_ports[index].uartclk = clock; legacy_serial_ports[index].irq = irq; - legacy_serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; + legacy_serial_ports[index].flags = flags; legacy_serial_infos[index].taddr = taddr; legacy_serial_infos[index].np = of_node_get(np); legacy_serial_infos[index].clock = clock; @@ -107,6 +108,32 @@ static int __init add_legacy_port(struct device_node *np, int want_index, return index; } +static int __init add_legacy_soc_port(struct device_node *np, + struct device_node *soc_dev) +{ + phys_addr_t addr; + u32 *addrp; + unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + + /* We only support ports that have a clock frequency properly + * encoded in the device-tree. + */ + if (get_property(np, "clock-frequency", NULL) == NULL) + return -1; + + /* Get the address */ + addrp = of_get_address(soc_dev, 0, NULL, NULL); + if (addrp == NULL) + return -1; + + addr = of_translate_address(soc_dev, addrp); + + /* Add port, irq will be dealt with later. We passed a translated + * IO port value. It will be fixed up later along with the irq + */ + return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags); +} + static int __init add_legacy_isa_port(struct device_node *np, struct device_node *isa_bridge) { @@ -137,7 +164,7 @@ static int __init add_legacy_isa_port(struct device_node *np, taddr = of_translate_address(np, reg); /* Add port, irq will be dealt with later */ - return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ); + return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF); } @@ -204,7 +231,7 @@ static int __init add_legacy_pci_port(struct device_node *np, /* Add port, irq will be dealt with later. We passed a translated * IO port value. It will be fixed up later along with the irq */ - return add_legacy_port(np, index, iotype, base, addr, NO_IRQ); + return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF); } /* @@ -218,7 +245,7 @@ static int __init add_legacy_pci_port(struct device_node *np, */ void __init find_legacy_serial_ports(void) { - struct device_node *np, *stdout; + struct device_node *np, *stdout = NULL; char *path; int index; @@ -226,13 +253,23 @@ void __init find_legacy_serial_ports(void) /* Now find out if one of these is out firmware console */ path = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (path == NULL) { + if (path != NULL) { + stdout = of_find_node_by_path(path); + if (stdout) + DBG("stdout is %s\n", stdout->full_name); + } else { DBG(" no linux,stdout-path !\n"); - return; } - stdout = of_find_node_by_path(path); - if (stdout) { - DBG("stdout is %s\n", stdout->full_name); + + /* First fill our array with SOC ports */ + for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) { + struct device_node *soc = of_get_parent(np); + if (soc && !strcmp(soc->type, "soc")) { + index = add_legacy_soc_port(np, np); + if (index >= 0 && np == stdout) + legacy_serial_console = index; + } + of_node_put(soc); } /* First fill our array with ISA ports */ @@ -437,6 +474,11 @@ static int __init check_legacy_serial_console(void) DBG(" of_chosen is NULL !\n"); return -ENODEV; } + + if (legacy_serial_console < 0) { + DBG(" legacy_serial_console not found !\n"); + return -ENODEV; + } /* We are getting a weird phandle from OF ... */ /* ... So use the full path instead */ name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); -- cgit v1.2.3 From be6b843918394067e93ebbacb834245251a6f18a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 20 Dec 2005 16:37:07 -0600 Subject: [PATCH] powerpc: added a udbg_progress Added a common udbg_progress for use by ppc_md.progress() Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/udbg.c | 6 ++++++ arch/powerpc/platforms/powermac/setup.c | 8 +------- include/asm-powerpc/udbg.h | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 9567d9474c80..558c1ceb2b93 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -90,6 +90,12 @@ void udbg_printf(const char *fmt, ...) va_end(args); } +void __init udbg_progress(char *s, unsigned short hex) +{ + udbg_puts(s); + udbg_puts("\n"); +} + /* * Early boot console based on udbg */ diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 1daa5a06e9ea..e5a5bdbdda7a 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -639,12 +639,6 @@ static void __init pmac_init_early(void) #endif } -static void __init pmac_progress(char *s, unsigned short hex) -{ - udbg_puts(s); - udbg_puts("\n"); -} - /* * pmac has no legacy IO, anything calling this function has to * fail or bad things will happen @@ -763,7 +757,7 @@ struct machdep_calls __initdata pmac_md = { .calibrate_decr = pmac_calibrate_decr, .feature_call = pmac_do_feature_call, .check_legacy_ioport = pmac_check_legacy_ioport, - .progress = pmac_progress, + .progress = udbg_progress, #ifdef CONFIG_PPC64 .pci_probe_mode = pmac_pci_probe_mode, .idle_loop = native_idle, diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h index 6c8abc924b28..479f2d8ff74a 100644 --- a/include/asm-powerpc/udbg.h +++ b/include/asm-powerpc/udbg.h @@ -24,6 +24,7 @@ extern int udbg_read(char *buf, int buflen); extern void register_early_udbg_console(void); extern void udbg_printf(const char *fmt, ...); +extern void udbg_progress(char *s, unsigned short hex); extern void udbg_init_uart(void __iomem *comport, unsigned int speed, unsigned int clock); -- cgit v1.2.3 From 79e7bac0d6ad56d62e2364313b5e5e5950c7385d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 21 Dec 2005 09:27:13 -0600 Subject: [PATCH] powerpc: Call find_legacy_serial_ports() if we enable CONFIG_SERIAL_8250 In setup_arch and setup_system call find_legacy_serial_ports() if we build in support for 8250 serial ports instead of basing it on PPC_MULTIPLATFORM. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 3 +-- arch/powerpc/kernel/setup_32.c | 2 +- arch/powerpc/kernel/setup_64.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 5bdc5faac713..a852b379d9eb 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -56,8 +56,7 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_6xx) += idle_6xx.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_PPC_MULTIPLATFORM) += legacy_serial.o -obj-$(CONFIG_PPC_MULTIPLATFORM) += udbg_16550.o +obj-$(CONFIG_SERIAL_8250) += legacy_serial.o udbg_16550.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 79d434fc14d2..e5d285adb496 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -299,7 +299,7 @@ void __init setup_arch(char **cmdline_p) if (ppc_md.init_early) ppc_md.init_early(); -#ifdef CONFIG_PPC_MULTIPLATFORM +#ifdef CONFIG_SERIAL_8250 find_legacy_serial_ports(); #endif finish_device_tree(); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 419e0b974b96..98e9f0595dd8 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -472,7 +472,7 @@ void __init setup_system(void) * hash table management for us, thus ioremap works. We do that early * so that further code can be debugged */ -#ifdef CONFIG_PPC_MULTIPLATFORM +#ifdef CONFIG_SERIAL_8250 find_legacy_serial_ports(); #endif -- cgit v1.2.3 From 9da5cad61c13fbdc7fc7aa425f03a15da9d0cb43 Mon Sep 17 00:00:00 2001 From: Haren Myneni Date: Tue, 27 Dec 2005 15:51:07 -0800 Subject: [PATCH] powerpc: Fix search for the main interrupt controller At present, we are not looking at all interrupt controller nodes in the device tree even though the proper node was not found. This is causing the system panic. The attached patch will scan all nodes until it finds the proper interrupt controller type. Signed-off-by: Haren Myneni Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/setup.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 2cb082871210..38b631ceaec9 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -324,15 +324,18 @@ static void __init pSeries_discover_pic(void) ppc64_interrupt_controller = IC_INVALID; for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { typep = (char *)get_property(np, "compatible", NULL); - if (strstr(typep, "open-pic")) + if (strstr(typep, "open-pic")) { ppc64_interrupt_controller = IC_OPEN_PIC; - else if (strstr(typep, "ppc-xicp")) + break; + } else if (strstr(typep, "ppc-xicp")) { ppc64_interrupt_controller = IC_PPC_XIC; - else - printk("pSeries_discover_pic: failed to recognize" - " interrupt-controller\n"); - break; + break; + } } + if (ppc64_interrupt_controller == IC_INVALID) + printk("pSeries_discover_pic: failed to recognize" + " interrupt-controller\n"); + } static void pSeries_mach_cpu_die(void) -- cgit v1.2.3 From 022930ebea0df878d449b7c74309c1d612441ac5 Mon Sep 17 00:00:00 2001 From: Haren Myneni Date: Tue, 27 Dec 2005 18:58:29 -0800 Subject: [PATCH] Small fix in eeh definitions when CONFIG_EEH not enabled Undefined symbols (eeh_add_device_tree_early and eeh_remove_bus_device) when EEH is not enabled. This small patch will fix this. Acked-by: Linas Vepstas Signed-off-by: Paul Mackerras --- include/asm-powerpc/eeh.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/asm-powerpc/eeh.h b/include/asm-powerpc/eeh.h index 14c9e8ab3e5f..4395b7bc1ed4 100644 --- a/include/asm-powerpc/eeh.h +++ b/include/asm-powerpc/eeh.h @@ -118,6 +118,9 @@ static inline void eeh_add_device_late(struct pci_dev *dev) { } static inline void eeh_remove_device(struct pci_dev *dev) { } +static inline void eeh_add_device_tree_early(struct device_node *dn) { } + +static inline void eeh_remove_bus_device(struct pci_dev *dev) { } #define EEH_POSSIBLE_ERROR(val, type) (0) #define EEH_IO_ERROR_VALUE(size) (-1UL) #endif /* CONFIG_EEH */ -- cgit v1.2.3 From 03929c76f3e5af919fb762e9882a9c286d361e7d Mon Sep 17 00:00:00 2001 From: Aristeu Sergio Rozanski Filho Date: Thu, 29 Dec 2005 19:18:49 -0200 Subject: [PATCH] ppc32: cpm_uart: fix xchar sending while using SCC as uart and as serial console at same time I got this: [ 138.214258] Oops: kernel access of bad area, sig: 11 [#1] [ 138.218832] PREEMPT [ 138.221021] NIP: C0105C48 LR: C0105E60 SP: C03D5D10 REGS: c03d5c60 TRAP: 0300 Not tainted [ 138.229280] MSR: 00009032 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11 [ 138.234713] DAR: 00000000, DSISR: C0000000 [ 138.238745] TASK = c0349420[693] 'sh' THREAD: c03d4000 [ 138.243754] Last syscall: 6 [ 138.246402] GPR00: FEFFFFFF C03D5D10 C0349420 C01FB094 00000011 00000000 C1ECFBBC C01F24B0 [ 138.254602] GPR08: FF002820 00000000 FF0028C0 00000000 19133615 A0CBCD5E 02000300 00000000 [ 138.262804] GPR16: 00000000 01FF9E4C 00000000 7FA9A770 00000000 00000000 1003E2A8 00000000 [ 138.271003] GPR24: 100562F4 7F9B6EF4 C0210000 C02A5338 C01FB094 00000000 C01FB094 C1F14574 [ 138.279376] NIP [c0105c48] cpm_uart_tx_pump+0x4c/0x22c [ 138.284419] LR [c0105e60] cpm_uart_start_tx+0x38/0xb0 [ 138.289361] Call trace: [ 138.291762] [c0105e60] cpm_uart_start_tx+0x38/0xb0 [ 138.296547] [c010277c] uart_send_xchar+0x88/0x118 [ 138.301244] [c01029a0] uart_unthrottle+0x6c/0x138 [ 138.305942] [c00ece10] check_unthrottle+0x60/0x64 [ 138.310641] [c00ecec4] reset_buffer_flags+0xb0/0x138 [ 138.315595] [c00ecf64] n_tty_flush_buffer+0x18/0x78 [ 138.320465] [c00e81b0] tty_ldisc_flush+0x64/0x7c [ 138.325078] [c010410c] uart_close+0xf0/0x2c8 [ 138.329348] [c00e9c48] release_dev+0x724/0x8d4 [ 138.333790] [c00e9e18] tty_release+0x20/0x3c [ 138.338061] [c006e544] __fput+0x178/0x1e0 [ 138.342076] [c006c43c] filp_close+0x54/0xac [ 138.346261] [c0002d90] ret_from_syscall+0x0/0x44 [ 138.352386] note: sh[693] exited with preempt_count 2 a easy way to reproduce it is log into the system using ssh and do: cat >/dev/ttyCPM0 then, switch to minicom and write some stuff on it back to ssh, a control C produce the oops this happens because uart_close calls uart_shutdown which frees xmit.buf, currently used by xchar sending in cpm_uart_tx_pump(), which seems wrong. the attached patch fixes the oops and also fixes xchar sending. Signed-off-by: Paul Mackerras --- drivers/serial/cpm_uart/cpm_uart_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 987d22b53c22..16af5626c243 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -608,7 +608,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) p = cpm2cpu_addr(bdp->cbd_bufaddr); - *p++ = xmit->buf[xmit->tail]; + *p++ = port->x_char; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; /* Get next BD. */ -- cgit v1.2.3 From 017e0fad3e40ece983527ec88a92b3da8fcdecea Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 3 Jan 2006 16:15:21 -0600 Subject: [PATCH] powerpc: fixing compile issue with !CONFIG_PCI in legacy_serial.c Only build in support for ISA and PCI cases if we have enabled CONFIG_ISA and CONFIG_PCI. Additionally, isa_bridge is a global so we shouldn't use it a parameter name since it gets redefined to NULL when !CONFIG_PCI. Signed-off-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 59164ba2eb1c..f970ace208d3 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -134,8 +134,9 @@ static int __init add_legacy_soc_port(struct device_node *np, return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags); } +#ifdef CONFIG_ISA static int __init add_legacy_isa_port(struct device_node *np, - struct device_node *isa_bridge) + struct device_node *isa_brg) { u32 *reg; char *typep; @@ -167,7 +168,9 @@ static int __init add_legacy_isa_port(struct device_node *np, return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF); } +#endif +#ifdef CONFIG_PCI static int __init add_legacy_pci_port(struct device_node *np, struct device_node *pci_dev) { @@ -233,6 +236,7 @@ static int __init add_legacy_pci_port(struct device_node *np, */ return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF); } +#endif /* * This is called very early, as part of setup_system() or eventually @@ -272,6 +276,7 @@ void __init find_legacy_serial_ports(void) of_node_put(soc); } +#ifdef CONFIG_ISA /* First fill our array with ISA ports */ for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { struct device_node *isa = of_get_parent(np); @@ -282,7 +287,9 @@ void __init find_legacy_serial_ports(void) } of_node_put(isa); } +#endif +#ifdef CONFIG_PCI /* Next, try to locate PCI ports */ for (np = NULL; (np = of_find_all_nodes(np));) { struct device_node *pci, *parent = of_get_parent(np); @@ -312,6 +319,7 @@ void __init find_legacy_serial_ports(void) legacy_serial_console = index; of_node_put(parent); } +#endif DBG("legacy_serial_console = %d\n", legacy_serial_console); @@ -375,6 +383,7 @@ static void __init fixup_port_pio(int index, struct device_node *np, struct plat_serial8250_port *port) { +#ifdef CONFIG_PCI struct pci_controller *hose; DBG("fixup_port_pio(%d)\n", index); @@ -391,6 +400,7 @@ static void __init fixup_port_pio(int index, index, port->iobase, port->iobase + offset); port->iobase += offset; } +#endif } static void __init fixup_port_mmio(int index, -- cgit v1.2.3 From c902be71dc6d5e8473bd021feafc8c3608e2b82a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 19:55:53 +0000 Subject: [PATCH] cell: enable pause(0) in cpu_idle This patch enables support for pause(0) power management state for the Cell Broadband Processor, which is import for power efficient operation. The pervasive infrastructure will in the future enable us to introduce more functionality specific to the Cell's pervasive unit. From: Maximino Aguilar Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 2 +- arch/powerpc/kernel/traps.c | 6 +- arch/powerpc/platforms/cell/Makefile | 2 + arch/powerpc/platforms/cell/pervasive.c | 229 ++++++++++++++++++++++++++++++++ arch/powerpc/platforms/cell/pervasive.h | 62 +++++++++ arch/powerpc/platforms/cell/setup.c | 2 + arch/powerpc/platforms/pseries/ras.c | 5 +- arch/powerpc/platforms/pseries/ras.h | 9 ++ arch/powerpc/platforms/pseries/setup.c | 4 +- include/asm-powerpc/cputable.h | 4 +- include/asm-powerpc/machdep.h | 2 +- include/asm-powerpc/reg.h | 22 ++- 12 files changed, 335 insertions(+), 14 deletions(-) create mode 100644 arch/powerpc/platforms/cell/pervasive.c create mode 100644 arch/powerpc/platforms/cell/pervasive.h create mode 100644 arch/powerpc/platforms/pseries/ras.h diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index f7f2a830fca1..2f82a2091440 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -273,7 +273,7 @@ struct cpu_spec cpu_specs[] = { .oprofile_model = &op_model_power4, #endif }, - { /* BE DD1.x */ + { /* Cell Broadband Engine */ .pvr_mask = 0xffff0000, .pvr_value = 0x00700000, .cpu_name = "Cell Broadband Engine", diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6c793463d511..7509aa6474f2 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -230,8 +230,10 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) void system_reset_exception(struct pt_regs *regs) { /* See if any machine dependent calls */ - if (ppc_md.system_reset_exception) - ppc_md.system_reset_exception(regs); + if (ppc_md.system_reset_exception) { + if (ppc_md.system_reset_exception(regs)) + return; + } die("System Reset", regs, SIGABRT); diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 74616cf13af9..ebbd1141498a 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,4 +1,6 @@ obj-y += interrupt.o iommu.o setup.o spider-pic.o +obj-y += pervasive.o + obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SPU_FS) += spufs/ spu_base.o builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c new file mode 100644 index 000000000000..85152544c153 --- /dev/null +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -0,0 +1,229 @@ +/* + * CBE Pervasive Monitor and Debug + * + * (C) Copyright IBM Corporation 2005 + * + * Authors: Maximino Aguilar (maguilar@us.ibm.com) + * Michael N. Day (mnday@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pervasive.h" + +static DEFINE_SPINLOCK(cbe_pervasive_lock); +struct cbe_pervasive { + struct pmd_regs __iomem *regs; + unsigned int thread; +}; + +/* can't use per_cpu from setup_arch */ +static struct cbe_pervasive cbe_pervasive[NR_CPUS]; + +static void __init cbe_enable_pause_zero(void) +{ + unsigned long thread_switch_control; + unsigned long temp_register; + struct cbe_pervasive *p; + int thread; + + spin_lock_irq(&cbe_pervasive_lock); + p = &cbe_pervasive[smp_processor_id()]; + + if (!cbe_pervasive->regs) + goto out; + + pr_debug("Power Management: CPU %d\n", smp_processor_id()); + + /* Enable Pause(0) control bit */ + temp_register = in_be64(&p->regs->pm_control); + + out_be64(&p->regs->pm_control, + temp_register|PMD_PAUSE_ZERO_CONTROL); + + /* Enable DEC and EE interrupt request */ + thread_switch_control = mfspr(SPRN_TSC_CELL); + thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; + + switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) { + case CTRL_CT0: + thread_switch_control |= TSC_CELL_DEC_ENABLE_0; + thread = 0; + break; + case CTRL_CT1: + thread_switch_control |= TSC_CELL_DEC_ENABLE_1; + thread = 1; + break; + default: + printk(KERN_WARNING "%s: unknown configuration\n", + __FUNCTION__); + thread = -1; + break; + } + + if (p->thread != thread) + printk(KERN_WARNING "%s: device tree inconsistant, " + "cpu %i: %d/%d\n", __FUNCTION__, + smp_processor_id(), + p->thread, thread); + + mtspr(SPRN_TSC_CELL, thread_switch_control); + +out: + spin_unlock_irq(&cbe_pervasive_lock); +} + +static void cbe_idle(void) +{ + unsigned long ctrl; + + cbe_enable_pause_zero(); + + while (1) { + if (!need_resched()) { + local_irq_disable(); + while (!need_resched()) { + /* go into low thread priority */ + HMT_low(); + + /* + * atomically disable thread execution + * and runlatch. + * External and Decrementer exceptions + * are still handled when the thread + * is disabled but now enter in + * cbe_system_reset_exception() + */ + ctrl = mfspr(SPRN_CTRLF); + ctrl &= ~(CTRL_RUNLATCH | CTRL_TE); + mtspr(SPRN_CTRLT, ctrl); + } + /* restore thread prio */ + HMT_medium(); + local_irq_enable(); + } + + /* + * turn runlatch on again before scheduling the + * process we just woke up + */ + ppc64_runlatch_on(); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +int cbe_system_reset_exception(struct pt_regs *regs) +{ + switch (regs->msr & SRR1_WAKEMASK) { + case SRR1_WAKEEE: + do_IRQ(regs); + break; + case SRR1_WAKEDEC: + timer_interrupt(regs); + break; + case SRR1_WAKEMT: + /* no action required */ + break; + default: + /* do system reset */ + return 0; + } + /* everything handled */ + return 1; +} + +static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p) +{ + struct device_node *node; + unsigned int *int_servers; + char *addr; + unsigned long real_address; + unsigned int size; + + struct pmd_regs __iomem *pmd_mmio_area; + int hardid, thread; + int proplen; + + pmd_mmio_area = NULL; + hardid = get_hard_smp_processor_id(cpu); + for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) { + int_servers = (void *) get_property(node, + "ibm,ppc-interrupt-server#s", &proplen); + if (!int_servers) { + printk(KERN_WARNING "%s misses " + "ibm,ppc-interrupt-server#s property", + node->full_name); + continue; + } + for (thread = 0; thread < proplen / sizeof (int); thread++) { + if (hardid == int_servers[thread]) { + addr = get_property(node, "pervasive", NULL); + goto found; + } + } + } + + printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu); + return -EINVAL; + +found: + real_address = *(unsigned long*) addr; + addr += sizeof (unsigned long); + size = *(unsigned int*) addr; + + pr_debug("pervasive area for CPU %d at %lx, size %x\n", + cpu, real_address, size); + p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE); + p->thread = thread; + return 0; +} + +void __init cell_pervasive_init(void) +{ + struct cbe_pervasive *p; + int cpu; + int ret; + + if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) + return; + + for_each_cpu(cpu) { + p = &cbe_pervasive[cpu]; + ret = cbe_find_pmd_mmio(cpu, p); + if (ret) + return; + } + + ppc_md.idle_loop = cbe_idle; + ppc_md.system_reset_exception = cbe_system_reset_exception; +} diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h new file mode 100644 index 000000000000..da1fb85ca3e8 --- /dev/null +++ b/arch/powerpc/platforms/cell/pervasive.h @@ -0,0 +1,62 @@ +/* + * Cell Pervasive Monitor and Debug interface and HW structures + * + * (C) Copyright IBM Corporation 2005 + * + * Authors: Maximino Aguilar (maguilar@us.ibm.com) + * David J. Erb (djerb@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef PERVASIVE_H +#define PERVASIVE_H + +struct pmd_regs { + u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */ + + /* Thermal Sensor Registers */ + u64 ts_ctsr1; /* 0x0800 */ + u64 ts_ctsr2; /* 0x0808 */ + u64 ts_mtsr1; /* 0x0810 */ + u64 ts_mtsr2; /* 0x0818 */ + u64 ts_itr1; /* 0x0820 */ + u64 ts_itr2; /* 0x0828 */ + u64 ts_gitr; /* 0x0830 */ + u64 ts_isr; /* 0x0838 */ + u64 ts_imr; /* 0x0840 */ + u64 tm_cr1; /* 0x0848 */ + u64 tm_cr2; /* 0x0850 */ + u64 tm_simr; /* 0x0858 */ + u64 tm_tpr; /* 0x0860 */ + u64 tm_str1; /* 0x0868 */ + u64 tm_str2; /* 0x0870 */ + u64 tm_tsr; /* 0x0878 */ + + /* Power Management */ + u64 pm_control; /* 0x0880 */ +#define PMD_PAUSE_ZERO_CONTROL 0x10000 + u64 pm_status; /* 0x0888 */ + + /* Time Base Register */ + u64 tbr; /* 0x0890 */ + + u8 pad_0x0898_0x1000 [0x1000 - 0x0898]; /* 0x0898 */ +}; + +void __init cell_pervasive_init(void); + +#endif diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index e5ee42b67509..18e25e65c04b 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -49,6 +49,7 @@ #include "interrupt.h" #include "iommu.h" +#include "pervasive.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -165,6 +166,7 @@ static void __init cell_setup_arch(void) init_pci_config_tokens(); find_and_init_phbs(); spider_init_IRQ(); + cell_pervasive_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 49b305f9c152..b046bcf7443d 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -51,6 +51,8 @@ #include #include +#include "ras.h" + static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); @@ -278,7 +280,7 @@ static void fwnmi_release_errinfo(void) printk("FWNMI: nmi-interlock failed: %d\n", ret); } -void pSeries_system_reset_exception(struct pt_regs *regs) +int pSeries_system_reset_exception(struct pt_regs *regs) { if (fwnmi_active) { struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs); @@ -287,6 +289,7 @@ void pSeries_system_reset_exception(struct pt_regs *regs) } fwnmi_release_errinfo(); } + return 0; /* need to perform reset */ } /* diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h new file mode 100644 index 000000000000..0e66b0da55e2 --- /dev/null +++ b/arch/powerpc/platforms/pseries/ras.h @@ -0,0 +1,9 @@ +#ifndef _PSERIES_RAS_H +#define _PSERIES_RAS_H + +struct pt_regs; + +extern int pSeries_system_reset_exception(struct pt_regs *regs); +extern int pSeries_machine_check_exception(struct pt_regs *regs); + +#endif /* _PSERIES_RAS_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 38b631ceaec9..8903cf63236a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -69,6 +69,7 @@ #include #include "plpar_wrappers.h" +#include "ras.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -80,9 +81,6 @@ extern void find_udbg_vterm(void); int fwnmi_active; /* TRUE if an FWNMI handler is present */ -extern void pSeries_system_reset_exception(struct pt_regs *regs); -extern int pSeries_machine_check_exception(struct pt_regs *regs); - static void pseries_shared_idle(void); static void pseries_dedicated_idle(void); diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index f4d508932467..d8798f31b360 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -105,6 +105,7 @@ extern void do_cpu_ftr_fixups(unsigned long offset); #define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000) #define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000) #define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000) +#define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000) #else /* ensure on 32b processors the flags are available for compiling but * don't do anything */ @@ -304,7 +305,8 @@ enum { CPU_FTR_MMCRA_SIHV, CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | - CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT, + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | + CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO, CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2, #endif diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 32539022f0a4..5348b820788c 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -134,7 +134,7 @@ struct machdep_calls { void (*nvram_sync)(void); /* Exception handlers */ - void (*system_reset_exception)(struct pt_regs *regs); + int (*system_reset_exception)(struct pt_regs *regs); int (*machine_check_exception)(struct pt_regs *regs); /* Motherboard/chipset features. This is a kind of general purpose diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index a9a76857f5aa..12ecc9b9f285 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -145,6 +145,10 @@ #define SPRN_CTR 0x009 /* Count Register */ #define SPRN_CTRLF 0x088 #define SPRN_CTRLT 0x098 +#define CTRL_CT 0xc0000000 /* current thread */ +#define CTRL_CT0 0x80000000 /* thread 0 */ +#define CTRL_CT1 0x40000000 /* thread 1 */ +#define CTRL_TE 0x00c00000 /* thread enable */ #define CTRL_RUNLATCH 0x1 #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ #define DABR_TRANSLATION (1UL << 2) @@ -257,11 +261,11 @@ #define SPRN_HID6 0x3F9 /* BE HID 6 */ #define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */ #define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */ -#define SPRN_TSCR 0x399 /* Thread switch control on BE */ -#define SPRN_TTR 0x39A /* Thread switch timeout on BE */ -#define TSCR_DEC_ENABLE 0x200000 /* Decrementer Interrupt */ -#define TSCR_EE_ENABLE 0x100000 /* External Interrupt */ -#define TSCR_EE_BOOST 0x080000 /* External Interrupt Boost */ +#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */ +#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */ +#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */ +#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */ +#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */ #define SPRN_TSC 0x3FD /* Thread switch control on others */ #define SPRN_TST 0x3FC /* Thread switch timeout on others */ #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2) @@ -375,6 +379,14 @@ #define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */ #define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ #define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ +#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ +#define SRR1_WAKERESET 0x00380000 /* System reset */ +#define SRR1_WAKESYSERR 0x00300000 /* System error */ +#define SRR1_WAKEEE 0x00200000 /* External interrupt */ +#define SRR1_WAKEMT 0x00280000 /* mtctrl */ +#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ +#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ + #ifndef SPRN_SVR #define SPRN_SVR 0x11E /* System Version Register */ #endif -- cgit v1.2.3 From 762cf6dac2623473e83bb271f2bbe97d2355c64d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:21 +0100 Subject: [PATCH] spufs: fix locking in spu_acquire_runnable We need to check for validity of owner under down_write, down_read is not enough. Noticed by Al Viro. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 1758cec58bc7..903c35d19577 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -120,27 +120,29 @@ int spu_acquire_runnable(struct spu_context *ctx) ctx->spu->prio = current->prio; return 0; } + up_read(&ctx->state_sema); + + down_write(&ctx->state_sema); /* ctx is about to be freed, can't acquire any more */ if (!ctx->owner) { ret = -EINVAL; goto out; } - up_read(&ctx->state_sema); - down_write(&ctx->state_sema); if (ctx->state == SPU_STATE_SAVED) { ret = spu_activate(ctx, 0); ctx->state = SPU_STATE_RUNNABLE; } - downgrade_write(&ctx->state_sema); if (ret) goto out; + downgrade_write(&ctx->state_sema); /* On success, we return holding the lock */ + return ret; out: /* Release here, to simplify calling code. */ - up_read(&ctx->state_sema); + up_write(&ctx->state_sema); return ret; } -- cgit v1.2.3 From c8ca0633e5f2bceab7b4eba4475820fd7674dece Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:22 +0100 Subject: [PATCH] spufs: dont hold root->isem in spu_forget spu_forget will do mmput on the DMA address space, which can lead to lots of other stuff getting triggered. We better not hold a semaphore here that we might need in the process. Noticed by Al Viro. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 2c3ba4eb41cb..45944012b06a 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -162,10 +162,10 @@ static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) { struct dentry *dentry, *tmp; struct spu_context *ctx; - int err; /* remove all entries */ - err = 0; + down(&root->i_sem); + down(&dir_dentry->d_inode->i_sem); list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) { spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); @@ -181,16 +181,16 @@ static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) spin_unlock(&dcache_lock); } } + shrink_dcache_parent(dir_dentry); + up(&dir_dentry->d_inode->i_sem); + up(&root->i_sem); /* We have to give up the mm_struct */ ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx; spu_forget(ctx); - if (!err) { - shrink_dcache_parent(dir_dentry); - err = simple_rmdir(root, dir_dentry); - } - return err; + /* XXX Do we need to hold i_sem here ? */ + return simple_rmdir(root, dir_dentry); } static int spufs_dir_close(struct inode *inode, struct file *file) @@ -201,10 +201,10 @@ static int spufs_dir_close(struct inode *inode, struct file *file) dentry = file->f_dentry; dir = dentry->d_parent->d_inode; - down(&dir->i_sem); - ret = spufs_rmdir(dir, file->f_dentry); + + ret = spufs_rmdir(dir, dentry); WARN_ON(ret); - up(&dir->i_sem); + return dcache_dir_close(inode, file); } -- cgit v1.2.3 From e80358ad8606382154d97165121602dfae213e4a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:23 +0100 Subject: [PATCH] spufs: check for proper file pointer in sys_spu_run Only checking for SPUFS_MAGIC is not reliable, because it might not be unique in theory. Worse than that, we accidentally allow spu_run to be performed on any file in spufs, not just those returned from spu_create as intended. Noticed by Al Viro. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 4 ++-- arch/powerpc/platforms/cell/spufs/spufs.h | 1 + arch/powerpc/platforms/cell/spufs/syscalls.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 45944012b06a..e314f18eccdd 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -212,7 +212,7 @@ struct inode_operations spufs_dir_inode_operations = { .lookup = simple_lookup, }; -struct file_operations spufs_autodelete_dir_operations = { +struct file_operations spufs_context_fops = { .open = dcache_dir_open, .release = spufs_dir_close, .llseek = dcache_dir_lseek, @@ -301,7 +301,7 @@ spufs_create_thread(struct nameidata *nd, const char *name, put_unused_fd(ret); ret = PTR_ERR(filp); } else { - filp->f_op = &spufs_autodelete_dir_operations; + filp->f_op = &spufs_context_fops; fd_install(ret, filp); } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 17cae5e5fdf5..420953b58881 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -103,6 +103,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, u32 *npc, u32 *status); long spufs_create_thread(struct nameidata *nd, const char *name, unsigned int flags, mode_t mode); +extern struct file_operations spufs_context_fops; /* context management */ struct spu_context * alloc_spu_context(struct address_space *local_store); diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 17a2b51c94bc..0c2896ac9518 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -39,8 +39,9 @@ long do_spu_run(struct file *filp, __u32 __user *unpc, __u32 __user *ustatus) if (get_user(npc, unpc) || get_user(status, ustatus)) goto out; + /* check if this file was created by spu_create */ ret = -EINVAL; - if (filp->f_vfsmnt->mnt_sb->s_magic != SPUFS_MAGIC) + if (filp->f_op != &spufs_context_fops) goto out; i = SPUFS_I(filp->f_dentry->d_inode); -- cgit v1.2.3 From 5ef8224aaa9220bfecb362f0802cf78aad47c02a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:24 +0100 Subject: [PATCH] spufs: serialize sys_spu_run per spu During an earlier cleanup, we lost the serialization of multiple spu_run calls performed on the same spu_context. In order to get this back, introduce a mutex in the spu_context that is held inside of spu_run. Noticed by Al Viro. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 1 + arch/powerpc/platforms/cell/spufs/file.c | 15 ++++++++++----- arch/powerpc/platforms/cell/spufs/spufs.h | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 903c35d19577..c5cd55ac848d 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -43,6 +43,7 @@ struct spu_context *alloc_spu_context(struct address_space *local_store) spin_lock_init(&ctx->mmio_lock); kref_init(&ctx->kref); init_rwsem(&ctx->state_sema); + init_MUTEX(&ctx->run_sema); init_waitqueue_head(&ctx->ibox_wq); init_waitqueue_head(&ctx->wbox_wq); init_waitqueue_head(&ctx->stop_wq); diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 9738de727f32..e63426822fd5 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -620,8 +620,12 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, { int ret; - if ((ret = spu_run_init(ctx, npc, status)) != 0) - return ret; + if (down_interruptible(&ctx->run_sema)) + return -ERESTARTSYS; + + ret = spu_run_init(ctx, npc, status); + if (ret) + goto out; do { ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); @@ -629,9 +633,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, break; if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, status); - if (ret) { - return ret; - } + if (ret) + goto out; continue; } ret = spu_process_events(ctx); @@ -645,6 +648,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, ret = *status; spu_yield(ctx); +out: + up(&ctx->run_sema); return ret; } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 420953b58881..b50474450819 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -48,6 +48,7 @@ struct spu_context { enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; struct rw_semaphore state_sema; + struct semaphore run_sema; struct mm_struct *owner; -- cgit v1.2.3 From 0106246594a05f02a6be6ee4695c7584c758fa7f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:25 +0100 Subject: [PATCH] spufs fix spu_acquire_runnable error path When spu_activate fails in spu_acquire_runnable, the state must still be SPU_STATE_SAVED, we were incorrectly setting it to SPU_STATE_RUNNABLE. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index c5cd55ac848d..336f238102fd 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -132,10 +132,10 @@ int spu_acquire_runnable(struct spu_context *ctx) if (ctx->state == SPU_STATE_SAVED) { ret = spu_activate(ctx, 0); + if (ret) + goto out; ctx->state = SPU_STATE_RUNNABLE; } - if (ret) - goto out; downgrade_write(&ctx->state_sema); /* On success, we return holding the lock */ -- cgit v1.2.3 From 346f4d3ce948a381a559dcaefb141d79f492335c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:26 +0100 Subject: [PATCH] spufs: dont leak directories in failed spu_create If get_unused_fd failed in sys_spu_create, we never cleaned up the created directory. Fix that by restructuring the error path. Noticed by Al Viro. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 54 +++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e314f18eccdd..d9a39fb63a8a 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) d_instantiate(dentry, inode); dget(dentry); dir->i_nlink++; + dentry->d_inode->i_nlink++; goto out; out_free_ctx: @@ -261,18 +263,44 @@ out: return ret; } +static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt) +{ + int ret; + struct file *filp; + + ret = get_unused_fd(); + if (ret < 0) { + dput(dentry); + mntput(mnt); + goto out; + } + + filp = dentry_open(dentry, mnt, O_RDONLY); + if (IS_ERR(filp)) { + put_unused_fd(ret); + ret = PTR_ERR(filp); + goto out; + } + + filp->f_op = &spufs_context_fops; + fd_install(ret, filp); +out: + return ret; +} + +static struct file_system_type spufs_type; + long spufs_create_thread(struct nameidata *nd, const char *name, unsigned int flags, mode_t mode) { struct dentry *dentry; - struct file *filp; int ret; /* need to be at the root of spufs */ ret = -EINVAL; - if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC || - nd->dentry != nd->dentry->d_sb->s_root) + if (nd->dentry->d_sb->s_type != &spufs_type || + nd->dentry != nd->dentry->d_sb->s_root) goto out; dentry = lookup_create(nd, 1); @@ -289,21 +317,13 @@ spufs_create_thread(struct nameidata *nd, const char *name, if (ret) goto out_dput; - ret = get_unused_fd(); + /* + * get references for dget and mntget, will be released + * in error path of *_open(). + */ + ret = spufs_context_open(dget(dentry), mntget(nd->mnt)); if (ret < 0) - goto out_dput; - - dentry->d_inode->i_nlink++; - - filp = filp_open(name, O_RDONLY, mode); - if (IS_ERR(filp)) { - // FIXME: remove directory again - put_unused_fd(ret); - ret = PTR_ERR(filp); - } else { - filp->f_op = &spufs_context_fops; - fd_install(ret, filp); - } + spufs_rmdir(nd->dentry->d_inode, dentry); out_dput: dput(dentry); -- cgit v1.2.3 From 3f51dd91c80746a5cf76f8c4a77bfc88aa82bb9e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:27 +0100 Subject: [PATCH] spufs: fix spufs_fill_dir error path If creating one entry failed in spufs_fill_dir, we never cleaned up the freshly created entries. Fix this by calling the cleanup function on error. Noticed by Al Viro. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 73 ++++++++++++++++--------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d9a39fb63a8a..687f80d09f41 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -134,47 +134,18 @@ spufs_delete_inode(struct inode *inode) clear_inode(inode); } -static int -spufs_fill_dir(struct dentry *dir, struct tree_descr *files, - int mode, struct spu_context *ctx) -{ - struct dentry *dentry; - int ret; - - while (files->name && files->name[0]) { - ret = -ENOMEM; - dentry = d_alloc_name(dir, files->name); - if (!dentry) - goto out; - ret = spufs_new_file(dir->d_sb, dentry, files->ops, - files->mode & mode, ctx); - if (ret) - goto out; - files++; - } - return 0; -out: - // FIXME: remove all files that are left - - return ret; -} - -static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) +static void spufs_prune_dir(struct dentry *dir) { struct dentry *dentry, *tmp; - struct spu_context *ctx; - - /* remove all entries */ - down(&root->i_sem); - down(&dir_dentry->d_inode->i_sem); - list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) { + down(&dir->d_inode->i_sem); + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (!(d_unhashed(dentry)) && dentry->d_inode) { dget_locked(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); - simple_unlink(dir_dentry->d_inode, dentry); + simple_unlink(dir->d_inode, dentry); spin_unlock(&dcache_lock); dput(dentry); } else { @@ -182,8 +153,17 @@ static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) spin_unlock(&dcache_lock); } } - shrink_dcache_parent(dir_dentry); - up(&dir_dentry->d_inode->i_sem); + shrink_dcache_parent(dir); + up(&dir->d_inode->i_sem); +} + +static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) +{ + struct spu_context *ctx; + + /* remove all entries */ + down(&root->i_sem); + spufs_prune_dir(dir_dentry); up(&root->i_sem); /* We have to give up the mm_struct */ @@ -194,6 +174,29 @@ static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) return simple_rmdir(root, dir_dentry); } +static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, + int mode, struct spu_context *ctx) +{ + struct dentry *dentry; + int ret; + + while (files->name && files->name[0]) { + ret = -ENOMEM; + dentry = d_alloc_name(dir, files->name); + if (!dentry) + goto out; + ret = spufs_new_file(dir->d_sb, dentry, files->ops, + files->mode & mode, ctx); + if (ret) + goto out; + files++; + } + return 0; +out: + spufs_prune_dir(dir); + return ret; +} + static int spufs_dir_close(struct inode *inode, struct file *file) { struct inode *dir; -- cgit v1.2.3 From 8837d9216f99048636fbb2c11347358e99e06181 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:28 +0100 Subject: [PATCH] spufs: clean up use of bitops checking bits manually might not be synchonized with the use of set_bit/clear_bit. Make sure we always use the correct bitops by removing the unnecessary identifiers. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 6 +++--- arch/powerpc/platforms/cell/spufs/sched.c | 8 ++++---- arch/powerpc/platforms/cell/spufs/spufs.h | 3 +-- arch/powerpc/platforms/cell/spufs/switch.c | 8 ++++---- include/asm-powerpc/spu.h | 6 ++---- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 3a5302151e09..ae8354740721 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -63,7 +63,7 @@ static void spu_restart_dma(struct spu *spu) { struct spu_priv2 __iomem *priv2 = spu->priv2; - if (!test_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags)) + if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags)) out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); } @@ -75,7 +75,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) pr_debug("%s\n", __FUNCTION__); - if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) { + if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) { /* SLBs are pre-loaded for context switch, so * we should never get here! */ @@ -122,7 +122,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) return 0; } - if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) { + if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) { printk("%s: invalid access during switch!\n", __func__); return 1; } diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 719ff27ce73e..c34198c29159 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -214,14 +214,14 @@ static void spu_reaper(void *data) down_write(&ctx->state_sema); spu = ctx->spu; - if (spu && (ctx->flags & SPU_CONTEXT_PREEMPT)) { + if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) { if (atomic_read(&spu->rq->prio.nr_blocked)) { pr_debug("%s: spu=%d\n", __func__, spu->number); ctx->ops->runcntl_stop(ctx); spu_deactivate(ctx); wake_up_all(&ctx->stop_wq); } else { - clear_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags); + clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags); } } up_write(&ctx->state_sema); @@ -234,7 +234,7 @@ static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu) unsigned long now = jiffies; unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE; - set_bit(SPU_CONTEXT_PREEMPT_nr, &ctx->flags); + set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags); INIT_WORK(&ctx->reap_work, spu_reaper, ctx); if (time_after(now, expire)) schedule_work(&ctx->reap_work); @@ -250,7 +250,7 @@ static void check_preempt_active(struct spu_runqueue *rq) list_for_each(p, &rq->active_list) { struct spu *spu = list_entry(p, struct spu, sched_list); struct spu_context *ctx = spu->ctx; - if (!(ctx->flags & SPU_CONTEXT_PREEMPT)) { + if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) { if (!worst || (spu->prio > worst->prio)) { worst = spu; } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index b50474450819..48961ac584a1 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -37,8 +37,7 @@ enum { struct spu_context_ops; -#define SPU_CONTEXT_PREEMPT_nr 0UL -#define SPU_CONTEXT_PREEMPT (1UL << SPU_CONTEXT_PREEMPT_nr) +#define SPU_CONTEXT_PREEMPT 0UL struct spu_context { struct spu *spu; /* pointer to a physical SPU */ diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 010a9fe55ef8..de1ad146fc63 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -165,7 +165,7 @@ static inline void set_switch_pending(struct spu_state *csa, struct spu *spu) * Restore, Step 5: * Set a software context switch pending flag. */ - set_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags); + set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags); mb(); } @@ -767,8 +767,8 @@ static inline void set_switch_active(struct spu_state *csa, struct spu *spu) * Change the software context switch pending flag * to context switch active. */ - set_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags); - clear_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags); + set_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags); + clear_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags); mb(); } @@ -1786,7 +1786,7 @@ static inline void reset_switch_active(struct spu_state *csa, struct spu *spu) /* Restore, Step 74: * Reset the "context switch active" flag. */ - clear_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags); + clear_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags); mb(); } diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index ee337e37195c..6b2aea0f6f20 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -102,10 +102,8 @@ #define MFC_MULTI_SRC_EVENT 0x00001000 /* Flags indicating progress during context switch. */ -#define SPU_CONTEXT_SWITCH_PENDING_nr 0UL -#define SPU_CONTEXT_SWITCH_ACTIVE_nr 1UL -#define SPU_CONTEXT_SWITCH_PENDING (1UL << SPU_CONTEXT_SWITCH_PENDING_nr) -#define SPU_CONTEXT_SWITCH_ACTIVE (1UL << SPU_CONTEXT_SWITCH_ACTIVE_nr) +#define SPU_CONTEXT_SWITCH_PENDING 0UL +#define SPU_CONTEXT_SWITCH_ACTIVE 1UL struct spu_context; struct spu_runqueue; -- cgit v1.2.3 From ce8ab8541203f6c7be5b2eeaa97f14f1d8d44e4f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:29 +0100 Subject: [PATCH] spufs: move spu_run call to its own file The logic for sys_spu_run keeps growing and it does not really belong into file.c any more since we moved away from using regular file operations to our own syscall. No functional change in here. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/Makefile | 2 +- arch/powerpc/platforms/cell/spufs/file.c | 152 ----------------------------- arch/powerpc/platforms/cell/spufs/run.c | 131 +++++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 28 ++++++ 4 files changed, 160 insertions(+), 153 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spufs/run.c diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index 9bfaba8791e3..a7cddf40e3d9 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_SPU_FS) += spufs.o spufs-y += inode.o file.o context.o switch.o syscalls.o -spufs-y += sched.o backing_ops.o hw_ops.o +spufs-y += sched.o backing_ops.o hw_ops.o run.o # Rules to build switch.o with the help of SPU tool chain SPU_CROSS := spu- diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index e63426822fd5..dfa649c9b956 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -304,34 +304,6 @@ static struct file_operations spufs_mbox_stat_fops = { .read = spufs_mbox_stat_read, }; -/* - * spufs_wait - * Same as wait_event_interruptible(), except that here - * we need to call spu_release(ctx) before sleeping, and - * then spu_acquire(ctx) when awoken. - */ - -#define spufs_wait(wq, condition) \ -({ \ - int __ret = 0; \ - DEFINE_WAIT(__wait); \ - for (;;) { \ - prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (!signal_pending(current)) { \ - spu_release(ctx); \ - schedule(); \ - spu_acquire(ctx); \ - continue; \ - } \ - __ret = -ERESTARTSYS; \ - break; \ - } \ - finish_wait(&(wq), &__wait); \ - __ret; \ -}) - /* low-level ibox access function */ size_t spu_ibox_read(struct spu_context *ctx, u32 *data) { @@ -529,130 +501,6 @@ static struct file_operations spufs_wbox_stat_fops = { .read = spufs_wbox_stat_read, }; -/* interrupt-level stop callback function. */ -void spufs_stop_callback(struct spu *spu) -{ - struct spu_context *ctx = spu->ctx; - - wake_up_all(&ctx->stop_wq); -} - -static inline int spu_stopped(struct spu_context *ctx, u32 * stat) -{ - struct spu *spu; - u64 pte_fault; - - *stat = ctx->ops->status_read(ctx); - if (ctx->state != SPU_STATE_RUNNABLE) - return 1; - spu = ctx->spu; - pte_fault = spu->dsisr & - (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); - return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; -} - -static inline int spu_run_init(struct spu_context *ctx, u32 * npc, - u32 * status) -{ - int ret; - - if ((ret = spu_acquire_runnable(ctx)) != 0) - return ret; - ctx->ops->npc_write(ctx, *npc); - ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); - return 0; -} - -static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, - u32 * status) -{ - int ret = 0; - - *status = ctx->ops->status_read(ctx); - *npc = ctx->ops->npc_read(ctx); - spu_release(ctx); - - if (signal_pending(current)) - ret = -ERESTARTSYS; - if (unlikely(current->ptrace & PT_PTRACED)) { - if ((*status & SPU_STATUS_STOPPED_BY_STOP) - && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { - force_sig(SIGTRAP, current); - ret = -ERESTARTSYS; - } - } - return ret; -} - -static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, - u32 *status) -{ - int ret; - - if ((ret = spu_run_fini(ctx, npc, status)) != 0) - return ret; - if (*status & (SPU_STATUS_STOPPED_BY_STOP | - SPU_STATUS_STOPPED_BY_HALT)) { - return *status; - } - if ((ret = spu_run_init(ctx, npc, status)) != 0) - return ret; - return 0; -} - -static inline int spu_process_events(struct spu_context *ctx) -{ - struct spu *spu = ctx->spu; - u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; - int ret = 0; - - if (spu->dsisr & pte_fault) - ret = spu_irq_class_1_bottom(spu); - if (spu->class_0_pending) - ret = spu_irq_class_0_bottom(spu); - if (!ret && signal_pending(current)) - ret = -ERESTARTSYS; - return ret; -} - -long spufs_run_spu(struct file *file, struct spu_context *ctx, - u32 * npc, u32 * status) -{ - int ret; - - if (down_interruptible(&ctx->run_sema)) - return -ERESTARTSYS; - - ret = spu_run_init(ctx, npc, status); - if (ret) - goto out; - - do { - ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); - if (unlikely(ret)) - break; - if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { - ret = spu_reacquire_runnable(ctx, npc, status); - if (ret) - goto out; - continue; - } - ret = spu_process_events(ctx); - - } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | - SPU_STATUS_STOPPED_BY_HALT))); - - ctx->ops->runcntl_stop(ctx); - ret = spu_run_fini(ctx, npc, status); - if (!ret) - ret = *status; - spu_yield(ctx); - -out: - up(&ctx->run_sema); - return ret; -} - static ssize_t spufs_signal1_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c new file mode 100644 index 000000000000..18ea8866c61a --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -0,0 +1,131 @@ +#include +#include + +#include + +#include "spufs.h" + +/* interrupt-level stop callback function. */ +void spufs_stop_callback(struct spu *spu) +{ + struct spu_context *ctx = spu->ctx; + + wake_up_all(&ctx->stop_wq); +} + +static inline int spu_stopped(struct spu_context *ctx, u32 * stat) +{ + struct spu *spu; + u64 pte_fault; + + *stat = ctx->ops->status_read(ctx); + if (ctx->state != SPU_STATE_RUNNABLE) + return 1; + spu = ctx->spu; + pte_fault = spu->dsisr & + (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); + return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; +} + +static inline int spu_run_init(struct spu_context *ctx, u32 * npc, + u32 * status) +{ + int ret; + + if ((ret = spu_acquire_runnable(ctx)) != 0) + return ret; + ctx->ops->npc_write(ctx, *npc); + ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); + return 0; +} + +static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, + u32 * status) +{ + int ret = 0; + + *status = ctx->ops->status_read(ctx); + *npc = ctx->ops->npc_read(ctx); + spu_release(ctx); + + if (signal_pending(current)) + ret = -ERESTARTSYS; + if (unlikely(current->ptrace & PT_PTRACED)) { + if ((*status & SPU_STATUS_STOPPED_BY_STOP) + && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { + force_sig(SIGTRAP, current); + ret = -ERESTARTSYS; + } + } + return ret; +} + +static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, + u32 *status) +{ + int ret; + + if ((ret = spu_run_fini(ctx, npc, status)) != 0) + return ret; + if (*status & (SPU_STATUS_STOPPED_BY_STOP | + SPU_STATUS_STOPPED_BY_HALT)) { + return *status; + } + if ((ret = spu_run_init(ctx, npc, status)) != 0) + return ret; + return 0; +} + +static inline int spu_process_events(struct spu_context *ctx) +{ + struct spu *spu = ctx->spu; + u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; + int ret = 0; + + if (spu->dsisr & pte_fault) + ret = spu_irq_class_1_bottom(spu); + if (spu->class_0_pending) + ret = spu_irq_class_0_bottom(spu); + if (!ret && signal_pending(current)) + ret = -ERESTARTSYS; + return ret; +} + +long spufs_run_spu(struct file *file, struct spu_context *ctx, + u32 * npc, u32 * status) +{ + int ret; + + if (down_interruptible(&ctx->run_sema)) + return -ERESTARTSYS; + + ret = spu_run_init(ctx, npc, status); + if (ret) + goto out; + + do { + ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); + if (unlikely(ret)) + break; + if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { + ret = spu_reacquire_runnable(ctx, npc, status); + if (ret) + goto out; + continue; + } + ret = spu_process_events(ctx); + + } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | + SPU_STATUS_STOPPED_BY_HALT))); + + ctx->ops->runcntl_stop(ctx); + ret = spu_run_fini(ctx, npc, status); + if (!ret) + ret = *status; + spu_yield(ctx); + +out: + up(&ctx->run_sema); + return ret; +} + diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 48961ac584a1..c715ed0c4014 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -124,6 +124,34 @@ void spu_yield(struct spu_context *ctx); int __init spu_sched_init(void); void __exit spu_sched_exit(void); +/* + * spufs_wait + * Same as wait_event_interruptible(), except that here + * we need to call spu_release(ctx) before sleeping, and + * then spu_acquire(ctx) when awoken. + */ + +#define spufs_wait(wq, condition) \ +({ \ + int __ret = 0; \ + DEFINE_WAIT(__wait); \ + for (;;) { \ + prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + spu_release(ctx); \ + schedule(); \ + spu_acquire(ctx); \ + continue; \ + } \ + __ret = -ERESTARTSYS; \ + break; \ + } \ + finish_wait(&(wq), &__wait); \ + __ret; \ +}) + size_t spu_wbox_write(struct spu_context *ctx, u32 data); size_t spu_ibox_read(struct spu_context *ctx, u32 *data); -- cgit v1.2.3 From f0831acc4b78e2d9737e8ed91b8b7505b21ddb83 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:30 +0100 Subject: [PATCH] spufs: abstract priv1 register access. In a hypervisor based setup, direct access to the first priviledged register space can typically not be allowed to the kernel and has to be implemented through hypervisor calls. As suggested by Masato Noguchi, let's abstract the register access trough a number of function calls. Since there is currently no public specification of actual hypervisor calls to implement this, I only provide a place that makes it easier to hook into. Cc: Masato Noguchi Cc: Geoff Levand Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/Makefile | 5 +- arch/powerpc/platforms/cell/spu_base.c | 51 ++++------- arch/powerpc/platforms/cell/spu_priv1.c | 133 +++++++++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/hw_ops.c | 19 ++--- arch/powerpc/platforms/cell/spufs/switch.c | 129 ++++++++++------------------ include/asm-powerpc/spu.h | 31 +++++-- 6 files changed, 233 insertions(+), 135 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spu_priv1.c diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index ebbd1141498a..16031b565be4 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -2,6 +2,9 @@ obj-y += interrupt.o iommu.o setup.o spider-pic.o obj-y += pervasive.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_SPU_FS) += spufs/ spu_base.o +obj-$(CONFIG_SPU_FS) += spufs/ spu-base.o + +spu-base-y += spu_base.o spu_priv1.o + builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o obj-y += $(builtin-spufs-m) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ae8354740721..081b3dcbaf14 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -142,8 +142,7 @@ static int __spu_trap_mailbox(struct spu *spu) /* atomically disable SPU mailbox interrupts */ spin_lock(&spu->register_lock); - out_be64(&spu->priv1->int_mask_class2_RW, - in_be64(&spu->priv1->int_mask_class2_RW) & ~0x1); + spu_int_mask_and(spu, 2, ~0x1); spin_unlock(&spu->register_lock); return 0; } @@ -180,8 +179,7 @@ static int __spu_trap_spubox(struct spu *spu) /* atomically disable SPU mailbox interrupts */ spin_lock(&spu->register_lock); - out_be64(&spu->priv1->int_mask_class2_RW, - in_be64(&spu->priv1->int_mask_class2_RW) & ~0x10); + spu_int_mask_and(spu, 2, ~0x10); spin_unlock(&spu->register_lock); return 0; } @@ -206,8 +204,8 @@ spu_irq_class_0_bottom(struct spu *spu) spu->class_0_pending = 0; - mask = in_be64(&spu->priv1->int_mask_class0_RW); - stat = in_be64(&spu->priv1->int_stat_class0_RW); + mask = spu_int_mask_get(spu, 0); + stat = spu_int_stat_get(spu, 0); stat &= mask; @@ -220,7 +218,7 @@ spu_irq_class_0_bottom(struct spu *spu) if (stat & 4) /* error on SPU */ __spu_trap_error(spu); - out_be64(&spu->priv1->int_stat_class0_RW, stat); + spu_int_stat_clear(spu, 0, stat); return (stat & 0x7) ? -EIO : 0; } @@ -236,13 +234,13 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) /* atomically read & clear class1 status. */ spin_lock(&spu->register_lock); - mask = in_be64(&spu->priv1->int_mask_class1_RW); - stat = in_be64(&spu->priv1->int_stat_class1_RW) & mask; - dar = in_be64(&spu->priv1->mfc_dar_RW); - dsisr = in_be64(&spu->priv1->mfc_dsisr_RW); + mask = spu_int_mask_get(spu, 1); + stat = spu_int_stat_get(spu, 1) & mask; + dar = spu_mfc_dar_get(spu); + dsisr = spu_mfc_dsisr_get(spu); if (stat & 2) /* mapping fault */ - out_be64(&spu->priv1->mfc_dsisr_RW, 0UL); - out_be64(&spu->priv1->int_stat_class1_RW, stat); + spu_mfc_dsisr_set(spu, 0ul); + spu_int_stat_clear(spu, 1, stat); spin_unlock(&spu->register_lock); if (stat & 1) /* segment fault */ @@ -270,8 +268,8 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs) unsigned long mask; spu = data; - stat = in_be64(&spu->priv1->int_stat_class2_RW); - mask = in_be64(&spu->priv1->int_mask_class2_RW); + stat = spu_int_stat_get(spu, 2); + mask = spu_int_mask_get(spu, 2); pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); @@ -292,7 +290,7 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs) if (stat & 0x10) /* SPU mailbox threshold */ __spu_trap_spubox(spu); - out_be64(&spu->priv1->int_stat_class2_RW, stat); + spu_int_stat_clear(spu, 2, stat); return stat ? IRQ_HANDLED : IRQ_NONE; } @@ -309,21 +307,18 @@ spu_request_irqs(struct spu *spu) spu_irq_class_0, 0, spu->irq_c0, spu); if (ret) goto out; - out_be64(&spu->priv1->int_mask_class0_RW, 0x7); snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number); ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu_irq_class_1, 0, spu->irq_c1, spu); if (ret) goto out1; - out_be64(&spu->priv1->int_mask_class1_RW, 0x3); snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu_irq_class_2, 0, spu->irq_c2, spu); if (ret) goto out2; - out_be64(&spu->priv1->int_mask_class2_RW, 0xe); goto out; out2: @@ -383,13 +378,6 @@ static void spu_init_channels(struct spu *spu) } } -static void spu_init_regs(struct spu *spu) -{ - out_be64(&spu->priv1->int_mask_class0_RW, 0x7); - out_be64(&spu->priv1->int_mask_class1_RW, 0x3); - out_be64(&spu->priv1->int_mask_class2_RW, 0xe); -} - struct spu *spu_alloc(void) { struct spu *spu; @@ -405,10 +393,8 @@ struct spu *spu_alloc(void) } up(&spu_mutex); - if (spu) { + if (spu) spu_init_channels(spu); - spu_init_regs(spu); - } return spu; } @@ -579,8 +565,7 @@ static int __init spu_map_device(struct spu *spu, struct device_node *spe) goto out_unmap; spu->priv1= map_spe_prop(spe, "priv1"); - if (!spu->priv1) - goto out_unmap; + /* priv1 is not available on a hypervisor */ spu->priv2= map_spe_prop(spe, "priv2"); if (!spu->priv2) @@ -633,8 +618,8 @@ static int __init create_spu(struct device_node *spe) spu->dsisr = 0UL; spin_lock_init(&spu->register_lock); - out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); - out_be64(&spu->priv1->mfc_sr1_RW, 0x33); + spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); + spu_mfc_sr1_set(spu, 0x33); spu->ibox_callback = NULL; spu->wbox_callback = NULL; diff --git a/arch/powerpc/platforms/cell/spu_priv1.c b/arch/powerpc/platforms/cell/spu_priv1.c new file mode 100644 index 000000000000..b2656421c7b5 --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_priv1.c @@ -0,0 +1,133 @@ +/* + * access to SPU privileged registers + */ +#include + +#include +#include + +void spu_int_mask_and(struct spu *spu, int class, u64 mask) +{ + u64 old_mask; + + old_mask = in_be64(&spu->priv1->int_mask_RW[class]); + out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask); +} +EXPORT_SYMBOL_GPL(spu_int_mask_and); + +void spu_int_mask_or(struct spu *spu, int class, u64 mask) +{ + u64 old_mask; + + old_mask = in_be64(&spu->priv1->int_mask_RW[class]); + out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask); +} +EXPORT_SYMBOL_GPL(spu_int_mask_or); + +void spu_int_mask_set(struct spu *spu, int class, u64 mask) +{ + out_be64(&spu->priv1->int_mask_RW[class], mask); +} +EXPORT_SYMBOL_GPL(spu_int_mask_set); + +u64 spu_int_mask_get(struct spu *spu, int class) +{ + return in_be64(&spu->priv1->int_mask_RW[class]); +} +EXPORT_SYMBOL_GPL(spu_int_mask_get); + +void spu_int_stat_clear(struct spu *spu, int class, u64 stat) +{ + out_be64(&spu->priv1->int_stat_RW[class], stat); +} +EXPORT_SYMBOL_GPL(spu_int_stat_clear); + +u64 spu_int_stat_get(struct spu *spu, int class) +{ + return in_be64(&spu->priv1->int_stat_RW[class]); +} +EXPORT_SYMBOL_GPL(spu_int_stat_get); + +void spu_int_route_set(struct spu *spu, u64 route) +{ + out_be64(&spu->priv1->int_route_RW, route); +} +EXPORT_SYMBOL_GPL(spu_int_route_set); + +u64 spu_mfc_dar_get(struct spu *spu) +{ + return in_be64(&spu->priv1->mfc_dar_RW); +} +EXPORT_SYMBOL_GPL(spu_mfc_dar_get); + +u64 spu_mfc_dsisr_get(struct spu *spu) +{ + return in_be64(&spu->priv1->mfc_dsisr_RW); +} +EXPORT_SYMBOL_GPL(spu_mfc_dsisr_get); + +void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr) +{ + out_be64(&spu->priv1->mfc_dsisr_RW, dsisr); +} +EXPORT_SYMBOL_GPL(spu_mfc_dsisr_set); + +void spu_mfc_sdr_set(struct spu *spu, u64 sdr) +{ + out_be64(&spu->priv1->mfc_sdr_RW, sdr); +} +EXPORT_SYMBOL_GPL(spu_mfc_sdr_set); + +void spu_mfc_sr1_set(struct spu *spu, u64 sr1) +{ + out_be64(&spu->priv1->mfc_sr1_RW, sr1); +} +EXPORT_SYMBOL_GPL(spu_mfc_sr1_set); + +u64 spu_mfc_sr1_get(struct spu *spu) +{ + return in_be64(&spu->priv1->mfc_sr1_RW); +} +EXPORT_SYMBOL_GPL(spu_mfc_sr1_get); + +void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id) +{ + out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id); +} +EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_set); + +u64 spu_mfc_tclass_id_get(struct spu *spu) +{ + return in_be64(&spu->priv1->mfc_tclass_id_RW); +} +EXPORT_SYMBOL_GPL(spu_mfc_tclass_id_get); + +void spu_tlb_invalidate(struct spu *spu) +{ + out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul); +} +EXPORT_SYMBOL_GPL(spu_tlb_invalidate); + +void spu_resource_allocation_groupID_set(struct spu *spu, u64 id) +{ + out_be64(&spu->priv1->resource_allocation_groupID_RW, id); +} +EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_set); + +u64 spu_resource_allocation_groupID_get(struct spu *spu) +{ + return in_be64(&spu->priv1->resource_allocation_groupID_RW); +} +EXPORT_SYMBOL_GPL(spu_resource_allocation_groupID_get); + +void spu_resource_allocation_enable_set(struct spu *spu, u64 enable) +{ + out_be64(&spu->priv1->resource_allocation_enable_RW, enable); +} +EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_set); + +u64 spu_resource_allocation_enable_get(struct spu *spu) +{ + return in_be64(&spu->priv1->resource_allocation_enable_RW); +} +EXPORT_SYMBOL_GPL(spu_resource_allocation_enable_get); diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index 9a53e29f9d7e..5445719bff79 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -62,7 +62,6 @@ static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx, unsigned int events) { struct spu *spu = ctx->spu; - struct spu_priv1 __iomem *priv1 = spu->priv1; int ret = 0; u32 stat; @@ -78,18 +77,16 @@ static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx, if (stat & 0xff0000) ret |= POLLIN | POLLRDNORM; else { - out_be64(&priv1->int_stat_class2_RW, 0x1); - out_be64(&priv1->int_mask_class2_RW, - in_be64(&priv1->int_mask_class2_RW) | 0x1); + spu_int_stat_clear(spu, 2, 0x1); + spu_int_mask_or(spu, 2, 0x1); } } if (events & (POLLOUT | POLLWRNORM)) { if (stat & 0x00ff00) ret = POLLOUT | POLLWRNORM; else { - out_be64(&priv1->int_stat_class2_RW, 0x10); - out_be64(&priv1->int_mask_class2_RW, - in_be64(&priv1->int_mask_class2_RW) | 0x10); + spu_int_stat_clear(spu, 2, 0x10); + spu_int_mask_or(spu, 2, 0x10); } } spin_unlock_irq(&spu->register_lock); @@ -100,7 +97,6 @@ static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data) { struct spu *spu = ctx->spu; struct spu_problem __iomem *prob = spu->problem; - struct spu_priv1 __iomem *priv1 = spu->priv1; struct spu_priv2 __iomem *priv2 = spu->priv2; int ret; @@ -111,8 +107,7 @@ static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data) ret = 4; } else { /* make sure we get woken up by the interrupt */ - out_be64(&priv1->int_mask_class2_RW, - in_be64(&priv1->int_mask_class2_RW) | 0x1); + spu_int_mask_or(spu, 2, 0x1); ret = 0; } spin_unlock_irq(&spu->register_lock); @@ -123,7 +118,6 @@ static int spu_hw_wbox_write(struct spu_context *ctx, u32 data) { struct spu *spu = ctx->spu; struct spu_problem __iomem *prob = spu->problem; - struct spu_priv1 __iomem *priv1 = spu->priv1; int ret; spin_lock_irq(&spu->register_lock); @@ -134,8 +128,7 @@ static int spu_hw_wbox_write(struct spu_context *ctx, u32 data) } else { /* make sure we get woken up by the interrupt when space becomes available */ - out_be64(&priv1->int_mask_class2_RW, - in_be64(&priv1->int_mask_class2_RW) | 0x10); + spu_int_mask_or(spu, 2, 0x10); ret = 0; } spin_unlock_irq(&spu->register_lock); diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index de1ad146fc63..1061c12b2edb 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -108,8 +108,6 @@ static inline int check_spu_isolate(struct spu_state *csa, struct spu *spu) static inline void disable_interrupts(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 3: * Restore, Step 2: * Save INT_Mask_class0 in CSA. @@ -121,16 +119,13 @@ static inline void disable_interrupts(struct spu_state *csa, struct spu *spu) */ spin_lock_irq(&spu->register_lock); if (csa) { - csa->priv1.int_mask_class0_RW = - in_be64(&priv1->int_mask_class0_RW); - csa->priv1.int_mask_class1_RW = - in_be64(&priv1->int_mask_class1_RW); - csa->priv1.int_mask_class2_RW = - in_be64(&priv1->int_mask_class2_RW); + csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0); + csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1); + csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2); } - out_be64(&priv1->int_mask_class0_RW, 0UL); - out_be64(&priv1->int_mask_class1_RW, 0UL); - out_be64(&priv1->int_mask_class2_RW, 0UL); + spu_int_mask_set(spu, 0, 0ul); + spu_int_mask_set(spu, 1, 0ul); + spu_int_mask_set(spu, 2, 0ul); eieio(); spin_unlock_irq(&spu->register_lock); } @@ -195,12 +190,10 @@ static inline void save_spu_runcntl(struct spu_state *csa, struct spu *spu) static inline void save_mfc_sr1(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 10: * Save MFC_SR1 in the CSA. */ - csa->priv1.mfc_sr1_RW = in_be64(&priv1->mfc_sr1_RW); + csa->priv1.mfc_sr1_RW = spu_mfc_sr1_get(spu); } static inline void save_spu_status(struct spu_state *csa, struct spu *spu) @@ -292,15 +285,13 @@ static inline void do_mfc_mssync(struct spu_state *csa, struct spu *spu) static inline void issue_mfc_tlbie(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 17: * Restore, Step 12. * Restore, Step 48. * Write TLB_Invalidate_Entry[IS,VPN,L,Lp]=0 register. * Then issue a PPE sync instruction. */ - out_be64(&priv1->tlb_invalidate_entry_W, 0UL); + spu_tlb_invalidate(spu); mb(); } @@ -410,25 +401,21 @@ static inline void save_mfc_csr_ato(struct spu_state *csa, struct spu *spu) static inline void save_mfc_tclass_id(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 25: * Save the MFC_TCLASS_ID register in * the CSA. */ - csa->priv1.mfc_tclass_id_RW = in_be64(&priv1->mfc_tclass_id_RW); + csa->priv1.mfc_tclass_id_RW = spu_mfc_tclass_id_get(spu); } static inline void set_mfc_tclass_id(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 26: * Restore, Step 23. * Write the MFC_TCLASS_ID register with * the value 0x10000000. */ - out_be64(&priv1->mfc_tclass_id_RW, 0x10000000); + spu_mfc_tclass_id_set(spu, 0x10000000); eieio(); } @@ -458,14 +445,13 @@ static inline void wait_purge_complete(struct spu_state *csa, struct spu *spu) static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; struct spu_priv2 __iomem *priv2 = spu->priv2; int i; /* Save, Step 29: * If MFC_SR1[R]='1', save SLBs in CSA. */ - if (in_be64(&priv1->mfc_sr1_RW) & MFC_STATE1_RELOCATE_MASK) { + if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) { csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W); for (i = 0; i < 8; i++) { out_be64(&priv2->slb_index_W, i); @@ -479,8 +465,6 @@ static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu) static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 30: * Restore, Step 18: * Write MFC_SR1 with MFC_SR1[D=0,S=1] and @@ -492,9 +476,9 @@ static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu) * MFC_SR1[Pr] bit is not set. * */ - out_be64(&priv1->mfc_sr1_RW, (MFC_STATE1_MASTER_RUN_CONTROL_MASK | - MFC_STATE1_RELOCATE_MASK | - MFC_STATE1_BUS_TLBIE_MASK)); + spu_mfc_sr1_set(spu, (MFC_STATE1_MASTER_RUN_CONTROL_MASK | + MFC_STATE1_RELOCATE_MASK | + MFC_STATE1_BUS_TLBIE_MASK)); } static inline void save_spu_npc(struct spu_state *csa, struct spu *spu) @@ -571,16 +555,14 @@ static inline void save_pm_trace(struct spu_state *csa, struct spu *spu) static inline void save_mfc_rag(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Save, Step 38: * Save RA_GROUP_ID register and the * RA_ENABLE reigster in the CSA. */ csa->priv1.resource_allocation_groupID_RW = - in_be64(&priv1->resource_allocation_groupID_RW); + spu_resource_allocation_groupID_get(spu); csa->priv1.resource_allocation_enable_RW = - in_be64(&priv1->resource_allocation_enable_RW); + spu_resource_allocation_enable_get(spu); } static inline void save_ppu_mb_stat(struct spu_state *csa, struct spu *spu) @@ -698,14 +680,13 @@ static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu) static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; struct spu_priv2 __iomem *priv2 = spu->priv2; /* Save, Step 45: * Restore, Step 19: * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All. */ - if (in_be64(&priv1->mfc_sr1_RW) & MFC_STATE1_RELOCATE_MASK) { + if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) { out_be64(&priv2->slb_invalidate_all_W, 0UL); eieio(); } @@ -774,7 +755,6 @@ static inline void set_switch_active(struct spu_state *csa, struct spu *spu) static inline void enable_interrupts(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; unsigned long class1_mask = CLASS1_ENABLE_SEGMENT_FAULT_INTR | CLASS1_ENABLE_STORAGE_FAULT_INTR; @@ -787,12 +767,12 @@ static inline void enable_interrupts(struct spu_state *csa, struct spu *spu) * (translation) interrupts. */ spin_lock_irq(&spu->register_lock); - out_be64(&priv1->int_stat_class0_RW, ~(0UL)); - out_be64(&priv1->int_stat_class1_RW, ~(0UL)); - out_be64(&priv1->int_stat_class2_RW, ~(0UL)); - out_be64(&priv1->int_mask_class0_RW, 0UL); - out_be64(&priv1->int_mask_class1_RW, class1_mask); - out_be64(&priv1->int_mask_class2_RW, 0UL); + spu_int_stat_clear(spu, 0, ~0ul); + spu_int_stat_clear(spu, 1, ~0ul); + spu_int_stat_clear(spu, 2, ~0ul); + spu_int_mask_set(spu, 0, 0ul); + spu_int_mask_set(spu, 1, class1_mask); + spu_int_mask_set(spu, 2, 0ul); spin_unlock_irq(&spu->register_lock); } @@ -930,7 +910,6 @@ static inline void set_ppu_querymask(struct spu_state *csa, struct spu *spu) static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; struct spu_problem __iomem *prob = spu->problem; u32 mask = MFC_TAGID_TO_TAGMASK(0); unsigned long flags; @@ -947,14 +926,13 @@ static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu) POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask); local_irq_save(flags); - out_be64(&priv1->int_stat_class0_RW, ~(0UL)); - out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + spu_int_stat_clear(spu, 0, ~(0ul)); + spu_int_stat_clear(spu, 2, ~(0ul)); local_irq_restore(flags); } static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; struct spu_problem __iomem *prob = spu->problem; unsigned long flags; @@ -967,8 +945,8 @@ static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu) POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); local_irq_save(flags); - out_be64(&priv1->int_stat_class0_RW, ~(0UL)); - out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + spu_int_stat_clear(spu, 0, ~(0ul)); + spu_int_stat_clear(spu, 2, ~(0ul)); local_irq_restore(flags); } @@ -1067,7 +1045,6 @@ static inline int suspend_spe(struct spu_state *csa, struct spu *spu) static inline void clear_spu_status(struct spu_state *csa, struct spu *spu) { struct spu_problem __iomem *prob = spu->problem; - struct spu_priv1 __iomem *priv1 = spu->priv1; /* Restore, Step 10: * If SPU_Status[R]=0 and SPU_Status[E,L,IS]=1, @@ -1076,8 +1053,8 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu) if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) { if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_EXIT_STAUTUS) { - out_be64(&priv1->mfc_sr1_RW, - MFC_STATE1_MASTER_RUN_CONTROL_MASK); + spu_mfc_sr1_set(spu, + MFC_STATE1_MASTER_RUN_CONTROL_MASK); eieio(); out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE); eieio(); @@ -1088,8 +1065,8 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu) SPU_STATUS_ISOLATED_LOAD_STAUTUS) || (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE)) { - out_be64(&priv1->mfc_sr1_RW, - MFC_STATE1_MASTER_RUN_CONTROL_MASK); + spu_mfc_sr1_set(spu, + MFC_STATE1_MASTER_RUN_CONTROL_MASK); eieio(); out_be32(&prob->spu_runcntl_RW, 0x2); eieio(); @@ -1257,16 +1234,14 @@ static inline void setup_spu_status_part2(struct spu_state *csa, static inline void restore_mfc_rag(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Restore, Step 29: * Restore RA_GROUP_ID register and the * RA_ENABLE reigster from the CSA. */ - out_be64(&priv1->resource_allocation_groupID_RW, - csa->priv1.resource_allocation_groupID_RW); - out_be64(&priv1->resource_allocation_enable_RW, - csa->priv1.resource_allocation_enable_RW); + spu_resource_allocation_groupID_set(spu, + csa->priv1.resource_allocation_groupID_RW); + spu_resource_allocation_enable_set(spu, + csa->priv1.resource_allocation_enable_RW); } static inline void send_restore_code(struct spu_state *csa, struct spu *spu) @@ -1409,8 +1384,6 @@ static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu) static inline void clear_interrupts(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Restore, Step 49: * Write INT_MASK_class0 with value of 0. * Write INT_MASK_class1 with value of 0. @@ -1420,12 +1393,12 @@ static inline void clear_interrupts(struct spu_state *csa, struct spu *spu) * Write INT_STAT_class2 with value of -1. */ spin_lock_irq(&spu->register_lock); - out_be64(&priv1->int_mask_class0_RW, 0UL); - out_be64(&priv1->int_mask_class1_RW, 0UL); - out_be64(&priv1->int_mask_class2_RW, 0UL); - out_be64(&priv1->int_stat_class0_RW, ~(0UL)); - out_be64(&priv1->int_stat_class1_RW, ~(0UL)); - out_be64(&priv1->int_stat_class2_RW, ~(0UL)); + spu_int_mask_set(spu, 0, 0ul); + spu_int_mask_set(spu, 1, 0ul); + spu_int_mask_set(spu, 2, 0ul); + spu_int_stat_clear(spu, 0, ~0ul); + spu_int_stat_clear(spu, 1, ~0ul); + spu_int_stat_clear(spu, 2, ~0ul); spin_unlock_irq(&spu->register_lock); } @@ -1522,12 +1495,10 @@ static inline void restore_mfc_csr_ato(struct spu_state *csa, struct spu *spu) static inline void restore_mfc_tclass_id(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Restore, Step 56: * Restore the MFC_TCLASS_ID register from CSA. */ - out_be64(&priv1->mfc_tclass_id_RW, csa->priv1.mfc_tclass_id_RW); + spu_mfc_tclass_id_set(spu, csa->priv1.mfc_tclass_id_RW); eieio(); } @@ -1689,7 +1660,6 @@ static inline void check_ppu_mb_stat(struct spu_state *csa, struct spu *spu) static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; struct spu_priv2 __iomem *priv2 = spu->priv2; u64 dummy = 0UL; @@ -1700,8 +1670,7 @@ static inline void check_ppuint_mb_stat(struct spu_state *csa, struct spu *spu) if ((csa->prob.mb_stat_R & 0xFF0000) == 0) { dummy = in_be64(&priv2->puint_mb_R); eieio(); - out_be64(&priv1->int_stat_class2_RW, - CLASS2_ENABLE_MAILBOX_INTR); + spu_int_stat_clear(spu, 2, CLASS2_ENABLE_MAILBOX_INTR); eieio(); } } @@ -1729,12 +1698,10 @@ static inline void restore_mfc_slbs(struct spu_state *csa, struct spu *spu) static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Restore, Step 69: * Restore the MFC_SR1 register from CSA. */ - out_be64(&priv1->mfc_sr1_RW, csa->priv1.mfc_sr1_RW); + spu_mfc_sr1_set(spu, csa->priv1.mfc_sr1_RW); eieio(); } @@ -1792,15 +1759,13 @@ static inline void reset_switch_active(struct spu_state *csa, struct spu *spu) static inline void reenable_interrupts(struct spu_state *csa, struct spu *spu) { - struct spu_priv1 __iomem *priv1 = spu->priv1; - /* Restore, Step 75: * Re-enable SPU interrupts. */ spin_lock_irq(&spu->register_lock); - out_be64(&priv1->int_mask_class0_RW, csa->priv1.int_mask_class0_RW); - out_be64(&priv1->int_mask_class1_RW, csa->priv1.int_mask_class1_RW); - out_be64(&priv1->int_mask_class2_RW, csa->priv1.int_mask_class2_RW); + spu_int_mask_set(spu, 0, csa->priv1.int_mask_class0_RW); + spu_int_mask_set(spu, 1, csa->priv1.int_mask_class1_RW); + spu_int_mask_set(spu, 2, csa->priv1.int_mask_class2_RW); spin_unlock_irq(&spu->register_lock); } diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 6b2aea0f6f20..3bf6a502aeaf 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -172,6 +172,29 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls) #endif /* MODULE */ +/* access to priv1 registers */ +void spu_int_mask_and(struct spu *spu, int class, u64 mask); +void spu_int_mask_or(struct spu *spu, int class, u64 mask); +void spu_int_mask_set(struct spu *spu, int class, u64 mask); +u64 spu_int_mask_get(struct spu *spu, int class); +void spu_int_stat_clear(struct spu *spu, int class, u64 stat); +u64 spu_int_stat_get(struct spu *spu, int class); +void spu_int_route_set(struct spu *spu, u64 route); +u64 spu_mfc_dar_get(struct spu *spu); +u64 spu_mfc_dsisr_get(struct spu *spu); +void spu_mfc_dsisr_set(struct spu *spu, u64 dsisr); +void spu_mfc_sdr_set(struct spu *spu, u64 sdr); +void spu_mfc_sr1_set(struct spu *spu, u64 sr1); +u64 spu_mfc_sr1_get(struct spu *spu); +void spu_mfc_tclass_id_set(struct spu *spu, u64 tclass_id); +u64 spu_mfc_tclass_id_get(struct spu *spu); +void spu_tlb_invalidate(struct spu *spu); +void spu_resource_allocation_groupID_set(struct spu *spu, u64 id); +u64 spu_resource_allocation_groupID_get(struct spu *spu); +void spu_resource_allocation_enable_set(struct spu *spu, u64 enable); +u64 spu_resource_allocation_enable_get(struct spu *spu); + + /* * This defines the Local Store, Problem Area and Privlege Area of an SPU. */ @@ -379,25 +402,21 @@ struct spu_priv1 { /* Interrupt Area */ - u64 int_mask_class0_RW; /* 0x100 */ + u64 int_mask_RW[3]; /* 0x100 */ #define CLASS0_ENABLE_DMA_ALIGNMENT_INTR 0x1L #define CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR 0x2L #define CLASS0_ENABLE_SPU_ERROR_INTR 0x4L #define CLASS0_ENABLE_MFC_FIR_INTR 0x8L - u64 int_mask_class1_RW; /* 0x108 */ #define CLASS1_ENABLE_SEGMENT_FAULT_INTR 0x1L #define CLASS1_ENABLE_STORAGE_FAULT_INTR 0x2L #define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_GET_INTR 0x4L #define CLASS1_ENABLE_LS_COMPARE_SUSPEND_ON_PUT_INTR 0x8L - u64 int_mask_class2_RW; /* 0x110 */ #define CLASS2_ENABLE_MAILBOX_INTR 0x1L #define CLASS2_ENABLE_SPU_STOP_INTR 0x2L #define CLASS2_ENABLE_SPU_HALT_INTR 0x4L #define CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR 0x8L u8 pad_0x118_0x140[0x28]; /* 0x118 */ - u64 int_stat_class0_RW; /* 0x140 */ - u64 int_stat_class1_RW; /* 0x148 */ - u64 int_stat_class2_RW; /* 0x150 */ + u64 int_stat_RW[3]; /* 0x140 */ u8 pad_0x158_0x180[0x28]; /* 0x158 */ u64 int_route_RW; /* 0x180 */ -- cgit v1.2.3 From 6ff730c33b42a6c68217fc6660728676aa8eeb9c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:31 +0100 Subject: [PATCH] spufs: fix sparse warnings One local variable is missing an __iomem modifier, in another place, we pass a completely unused argument with a missing __user modifier. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 2 +- arch/powerpc/platforms/cell/spufs/inode.c | 5 ++--- arch/powerpc/platforms/cell/spufs/spufs.h | 2 +- arch/powerpc/platforms/cell/spufs/syscalls.c | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 081b3dcbaf14..7fe3fa3da0e9 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -357,7 +357,7 @@ static void spu_init_channels(struct spu *spu) { 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, }, { 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, }, }; - struct spu_priv2 *priv2; + struct spu_priv2 __iomem *priv2; int i; priv2 = spu->priv2; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 687f80d09f41..1f3507c75e90 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -293,9 +293,8 @@ out: static struct file_system_type spufs_type; -long -spufs_create_thread(struct nameidata *nd, const char *name, - unsigned int flags, mode_t mode) +long spufs_create_thread(struct nameidata *nd, + unsigned int flags, mode_t mode) { struct dentry *dentry; int ret; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index c715ed0c4014..db2601f0abd5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -101,7 +101,7 @@ extern struct tree_descr spufs_dir_contents[]; /* system call implementation */ long spufs_run_spu(struct file *file, struct spu_context *ctx, u32 *npc, u32 *status); -long spufs_create_thread(struct nameidata *nd, const char *name, +long spufs_create_thread(struct nameidata *nd, unsigned int flags, mode_t mode); extern struct file_operations spufs_context_fops; diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 0c2896ac9518..d549aa7ebea6 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -85,7 +85,7 @@ asmlinkage long sys_spu_create(const char __user *pathname, ret = path_lookup(tmp, LOOKUP_PARENT| LOOKUP_OPEN|LOOKUP_CREATE, &nd); if (!ret) { - ret = spufs_create_thread(&nd, pathname, flags, mode); + ret = spufs_create_thread(&nd, flags, mode); path_release(&nd); } putname(tmp); -- cgit v1.2.3 From aeb013772a2cc85a8d0baffd64977d2888bc781d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 4 Jan 2006 20:31:32 +0100 Subject: [PATCH] spufs: fix allocation on 64k pages The size of the local store is architecture defined and independent from the page size, so it should not be defined in terms of pages in the first place. This mistake broke a few places when building for 64kb pages. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- include/asm-powerpc/spu.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 3bf6a502aeaf..692aa60e9903 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -28,9 +28,7 @@ #include #include -#define LS_ORDER (6) /* 256 kb */ - -#define LS_SIZE (PAGE_SIZE << LS_ORDER) +#define LS_SIZE (256 * 1024) #define LS_ADDR_MASK (LS_SIZE - 1) #define MFC_PUT_CMD 0x20 -- cgit v1.2.3 From 2fb9d2063626374dd8a2514b3a730facac8235d8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Jan 2006 14:05:29 +0000 Subject: [PATCH] spufs: set irq affinity for running threads For far, all SPU triggered interrupts always end up on the first SMT thread, which is a bad solution. This patch implements setting the affinity to the CPU that was running last when entering execution on an SPU. This should result in a significant reduction in IPI calls and better cache locality for SPE thread specific data. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/interrupt.c | 42 +++++++++++++++++++------------ arch/powerpc/platforms/cell/interrupt.h | 1 + arch/powerpc/platforms/cell/spu_base.c | 8 ++++++ arch/powerpc/platforms/cell/spufs/sched.c | 5 ++++ include/asm-powerpc/spu.h | 1 + 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 7fbe78a9327d..63aa52acf441 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ struct iic_regs { struct iic { struct iic_regs __iomem *regs; + u8 target_id; }; static DEFINE_PER_CPU(struct iic, iic); @@ -172,12 +174,11 @@ int iic_get_irq(struct pt_regs *regs) return irq; } -static struct iic_regs __iomem *find_iic(int cpu) +static int setup_iic(int cpu, struct iic *iic) { struct device_node *np; int nodeid = cpu / 2; unsigned long regs; - struct iic_regs __iomem *iic_regs; for (np = of_find_node_by_type(NULL, "cpu"); np; @@ -188,20 +189,23 @@ static struct iic_regs __iomem *find_iic(int cpu) if (!np) { printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); - iic_regs = NULL; - } else { - regs = *(long *)get_property(np, "iic", NULL); - - /* hack until we have decided on the devtree info */ - regs += 0x400; - if (cpu & 1) - regs += 0x20; - - printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); - iic_regs = __ioremap(regs, sizeof(struct iic_regs), - _PAGE_NO_CACHE); + iic->regs = NULL; + iic->target_id = 0xff; + return -ENODEV; } - return iic_regs; + + regs = *(long *)get_property(np, "iic", NULL); + + /* hack until we have decided on the devtree info */ + regs += 0x400; + if (cpu & 1) + regs += 0x20; + + printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); + iic->regs = __ioremap(regs, sizeof(struct iic_regs), + _PAGE_NO_CACHE); + iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); + return 0; } #ifdef CONFIG_SMP @@ -227,6 +231,12 @@ void iic_cause_IPI(int cpu, int mesg) out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4); } +u8 iic_get_target_id(int cpu) +{ + return per_cpu(iic, cpu).target_id; +} +EXPORT_SYMBOL_GPL(iic_get_target_id); + static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) { smp_message_recv(iic_irq_to_ipi(irq), regs); @@ -276,7 +286,7 @@ void iic_init_IRQ(void) irq_offset = 0; for_each_cpu(cpu) { iic = &per_cpu(iic, cpu); - iic->regs = find_iic(cpu); + setup_iic(cpu, iic); if (iic->regs) out_be64(&iic->regs->prio, 0xff); } diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index 37d58e6fd0c6..a14bd38791c0 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h @@ -54,6 +54,7 @@ extern void iic_setup_cpu(void); extern void iic_local_enable(void); extern void iic_local_disable(void); +extern u8 iic_get_target_id(int cpu); extern void spider_init_IRQ(void); extern int spider_get_irq(unsigned long int_pending); diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 7fe3fa3da0e9..d75ae03df686 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -507,6 +507,14 @@ int spu_irq_class_1_bottom(struct spu *spu) return ret; } +void spu_irq_setaffinity(struct spu *spu, int cpu) +{ + u64 target = iic_get_target_id(cpu); + u64 route = target << 48 | target << 32 | target << 16; + spu_int_route_set(spu, route); +} +EXPORT_SYMBOL_GPL(spu_irq_setaffinity); + static void __iomem * __init map_spe_prop(struct device_node *n, const char *name) { diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index c34198c29159..963182fbd1aa 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -357,6 +357,11 @@ int spu_activate(struct spu_context *ctx, u64 flags) if (!spu) return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN; bind_context(spu, ctx); + /* + * We're likely to wait for interrupts on the same + * CPU that we are now on, so send them here. + */ + spu_irq_setaffinity(spu, raw_smp_processor_id()); put_active_spu(spu); return 0; } diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index 692aa60e9903..38bacf2f6e0c 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h @@ -147,6 +147,7 @@ struct spu *spu_alloc(void); void spu_free(struct spu *spu); int spu_irq_class_0_bottom(struct spu *spu); int spu_irq_class_1_bottom(struct spu *spu); +void spu_irq_setaffinity(struct spu *spu, int cpu); extern struct spufs_calls { asmlinkage long (*create_thread)(const char __user *name, -- cgit v1.2.3 From aed9c6ccb87d96c333bd6ae631d9e90f3b6d7271 Mon Sep 17 00:00:00 2001 From: Paul Janzen Date: Wed, 4 Jan 2006 21:40:48 -0800 Subject: [PATCH] ppc32: Put cache flush routines back into .relocate_code section In 2.6.14, we had the following definition of _GLOBAL() in include/asm-ppc/processor.h: #define _GLOBAL(n)\ .stabs __stringify(n:F-1),N_FUN,0,0,n;\ .globl n;\ n: In 2.6.15, as part of the great powerpc merge, we moved this definition to include/asm-powerpc/ppc_asm.h, where it appears (to 32-bit code) as: #define _GLOBAL(n) \ .text; \ .stabs __stringify(n:F-1),N_FUN,0,0,n;\ .globl n; \ n: Mostly, this is fine. However, we also have the following, in arch/ppc/boot/common/util.S: .section ".relocate_code","xa" [...] _GLOBAL(flush_instruction_cache) [...] _GLOBAL(flush_data_cache) [...] The addition of the .text section definition in the definition of _GLOBAL overrides the .relocate_code section definition. As a result, these two functions don't end up in .relocate_code, so they don't get relocated correctly, and the boot fails. There's another suspicious-looking usage at kernel/swsusp.S:37 that someone should look into. I did not exhaustively search the source tree, though. The following is the minimal patch that fixes the immediate problem. I could easily be convinced that the _GLOBAL definition should be modified to remove the ".text;" line either instead of, or in addition to, this fix. Signed-off-by: Paul Janzen Signed-off-by: Paul Mackerras --- arch/ppc/boot/common/util.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S index c96c9f80521e..368ec035e6cd 100644 --- a/arch/ppc/boot/common/util.S +++ b/arch/ppc/boot/common/util.S @@ -234,7 +234,8 @@ udelay: * First, flush the data cache in case it was enabled and may be * holding instructions for copy back. */ -_GLOBAL(flush_instruction_cache) + .globl flush_instruction_cache +flush_instruction_cache: mflr r6 bl flush_data_cache @@ -279,7 +280,8 @@ _GLOBAL(flush_instruction_cache) * Flush data cache * Do this by just reading lots of stuff into the cache. */ -_GLOBAL(flush_data_cache) + .globl flush_data_cache +flush_data_cache: lis r3,cache_flush_buffer@h ori r3,r3,cache_flush_buffer@l li r4,NUM_CACHE_LINES -- cgit v1.2.3 From 002ec58eb57bac2380f0ed5a4e88121b4bdb32ec Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 7 Jan 2006 00:49:49 +1100 Subject: [PATCH] ppc64: fix time syscall ppc64 has its own version of sys_time. It looks pretty scary, touching a whole bunch of variables without any locking or memory ordering. In fact, a recent bugreport has shown it can actually go backwards. Time to remove it and just use the generic sys_time, which is implemented on top of do_gettimeofday. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/syscalls.c | 28 ---------------------------- arch/powerpc/kernel/systbl.S | 2 +- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 91b93d917b64..ad895c99813b 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -43,9 +43,6 @@ #include #include -extern unsigned long wall_jiffies; - - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * @@ -311,31 +308,6 @@ int sys_olduname(struct oldold_utsname __user *name) return error? -EFAULT: 0; } -#ifdef CONFIG_PPC64 -time_t sys64_time(time_t __user * tloc) -{ - time_t secs; - time_t usecs; - - long tb_delta = tb_ticks_since(tb_last_stamp); - tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; - - secs = xtime.tv_sec; - usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec; - while (usecs >= USEC_PER_SEC) { - ++secs; - usecs -= USEC_PER_SEC; - } - - if (tloc) { - if (put_user(secs,tloc)) - secs = -EFAULT; - } - - return secs; -} -#endif - long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, u32 len_high, u32 len_low) { diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 989f6286991a..65463a1076e8 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -54,7 +54,7 @@ SYSCALL(link) SYSCALL(unlink) COMPAT_SYS(execve) SYSCALL(chdir) -SYSX(sys64_time,compat_sys_time,sys_time) +COMPAT_SYS(time) SYSCALL(mknod) SYSCALL(chmod) SYSCALL(lchown) -- cgit v1.2.3 From 730745a5c45093982112ddc94cee6a9973455641 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 7 Jan 2006 11:30:44 +1100 Subject: [PATCH] 1/5 powerpc: Rework PowerMac i2c part 1 This is the first part of a rework of the PowerMac i2c code. It completely reworks the "low_i2c" layer. It is now more flexible, supports KeyWest, SMU and PMU i2c busses, and provides functions to match device nodes to i2c busses and adapters. This patch also extends & fix some bugs in the SMU driver related to i2c support and removes the clock spreading hacks from the pmac feature code rather than adapting them to the new API since they'll be replaced by the platform function code completely in patch 3/5 Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/feature.c | 127 ----- arch/powerpc/platforms/powermac/low_i2c.c | 853 ++++++++++++++++++++++++------ arch/powerpc/platforms/powermac/setup.c | 23 +- arch/powerpc/platforms/powermac/smp.c | 75 +-- drivers/i2c/busses/i2c-pmac-smu.c | 17 +- drivers/macintosh/smu.c | 58 +- drivers/macintosh/via-pmu.c | 264 +-------- include/asm-powerpc/pmac_feature.h | 4 - include/asm-powerpc/pmac_low_i2c.h | 85 ++- include/asm-powerpc/smu.h | 12 +- include/linux/pmu.h | 8 +- 11 files changed, 859 insertions(+), 667 deletions(-) diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index d2915d64d45e..b271b11583ac 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -1677,124 +1677,6 @@ intrepid_shutdown(struct macio_chip *macio, int sleep_mode) } -void pmac_tweak_clock_spreading(int enable) -{ - struct macio_chip *macio = &macio_chips[0]; - - /* Hack for doing clock spreading on some machines PowerBooks and - * iBooks. This implements the "platform-do-clockspreading" OF - * property as decoded manually on various models. For safety, we also - * check the product ID in the device-tree in cases we'll whack the i2c - * chip to make reasonably sure we won't set wrong values in there - * - * Of course, ultimately, we have to implement a real parser for - * the platform-do-* stuff... - */ - - if (macio->type == macio_intrepid) { - struct device_node *clock = - of_find_node_by_path("/uni-n@f8000000/hw-clock"); - if (clock && get_property(clock, "platform-do-clockspreading", - NULL)) { - printk(KERN_INFO "%sabling clock spreading on Intrepid" - " ASIC\n", enable ? "En" : "Dis"); - if (enable) - UN_OUT(UNI_N_CLOCK_SPREADING, 2); - else - UN_OUT(UNI_N_CLOCK_SPREADING, 0); - mdelay(40); - } - of_node_put(clock); - } - - while (machine_is_compatible("PowerBook5,2") || - machine_is_compatible("PowerBook5,3") || - machine_is_compatible("PowerBook6,2") || - machine_is_compatible("PowerBook6,3")) { - struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); - struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); - u8 buffer[9]; - u32 *productID; - int i, rc, changed = 0; - - if (dt == NULL) - break; - productID = (u32 *)get_property(dt, "pid#", NULL); - if (productID == NULL) - break; - while(ui2c) { - struct device_node *p = of_get_parent(ui2c); - if (p && !strcmp(p->name, "uni-n")) - break; - ui2c = of_find_node_by_type(ui2c, "i2c"); - } - if (ui2c == NULL) - break; - DBG("Trying to bump clock speed for PID: %08x...\n", *productID); - rc = pmac_low_i2c_open(ui2c, 1); - if (rc != 0) - break; - pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); - DBG("read result: %d,", rc); - if (rc != 0) { - pmac_low_i2c_close(ui2c); - break; - } - for (i=0; i<9; i++) - DBG(" %02x", buffer[i]); - DBG("\n"); - - switch(*productID) { - case 0x1182: /* AlBook 12" rev 2 */ - case 0x1183: /* iBook G4 12" */ - buffer[0] = (buffer[0] & 0x8f) | 0x70; - buffer[2] = (buffer[2] & 0x7f) | 0x00; - buffer[5] = (buffer[5] & 0x80) | 0x31; - buffer[6] = (buffer[6] & 0x40) | 0xb0; - buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba); - buffer[8] = (buffer[8] & 0x00) | 0x30; - changed = 1; - break; - case 0x3142: /* AlBook 15" (ATI M10) */ - case 0x3143: /* AlBook 17" (ATI M10) */ - buffer[0] = (buffer[0] & 0xaf) | 0x50; - buffer[2] = (buffer[2] & 0x7f) | 0x00; - buffer[5] = (buffer[5] & 0x80) | 0x31; - buffer[6] = (buffer[6] & 0x40) | 0xb0; - buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0); - buffer[8] = (buffer[8] & 0x00) | 0x30; - changed = 1; - break; - default: - DBG("i2c-hwclock: Machine model not handled\n"); - break; - } - if (!changed) { - pmac_low_i2c_close(ui2c); - break; - } - printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n", - enable ? "En" : "Dis"); - - pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); - DBG("write result: %d,", rc); - pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); - DBG("read result: %d,", rc); - if (rc != 0) { - pmac_low_i2c_close(ui2c); - break; - } - for (i=0; i<9; i++) - DBG(" %02x", buffer[i]); - pmac_low_i2c_close(ui2c); - break; - } -} - - static int core99_sleep(void) { @@ -2980,12 +2862,6 @@ set_initial_features(void) MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); } - /* Some machine models need the clock chip to be properly setup for - * clock spreading now. This should be a platform function but we - * don't do these at the moment - */ - pmac_tweak_clock_spreading(1); - #endif /* CONFIG_POWER4 */ /* On all machines, switch modem & serial ports off */ @@ -3013,9 +2889,6 @@ pmac_feature_init(void) return; } - /* Setup low-level i2c stuffs */ - pmac_init_low_i2c(); - /* Probe machine type */ if (probe_motherboard()) printk(KERN_WARNING "Unknown PowerMac !\n"); diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index 606e0ed13731..f31d6a678b9e 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -1,22 +1,34 @@ /* - * arch/ppc/platforms/pmac_low_i2c.c + * arch/powerpc/platforms/powermac/low_i2c.c * - * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org) + * Copyright (C) 2003-2005 Ben. Herrenschmidt (benh@kernel.crashing.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * This file contains some low-level i2c access routines that - * need to be used by various bits of the PowerMac platform code - * at times where the real asynchronous & interrupt driven driver - * cannot be used. The API borrows some semantics from the darwin - * driver in order to ease the implementation of the platform - * properties parser + * The linux i2c layer isn't completely suitable for our needs for various + * reasons ranging from too late initialisation to semantics not perfectly + * matching some requirements of the apple platform functions etc... + * + * This file thus provides a simple low level unified i2c interface for + * powermac that covers the various types of i2c busses used in Apple machines. + * For now, keywest, PMU and SMU, though we could add Cuda, or other bit + * banging busses found on older chipstes in earlier machines if we ever need + * one of them. + * + * The drivers in this file are synchronous/blocking. In addition, the + * keywest one is fairly slow due to the use of msleep instead of interrupts + * as the interrupt is currently used by i2c-keywest. In the long run, we + * might want to get rid of those high-level interfaces to linux i2c layer + * either completely (converting all drivers) or replacing them all with a + * single stub driver on top of this one. Once done, the interrupt will be + * available for our use. */ #undef DEBUG +#undef DEBUG_LOW #include #include @@ -25,15 +37,16 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include -#define MAX_LOW_I2C_HOST 4 - #ifdef DEBUG #define DBG(x...) do {\ printk(KERN_DEBUG "low_i2c:" x); \ @@ -42,49 +55,54 @@ #define DBG(x...) #endif -struct low_i2c_host; - -typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len); - -struct low_i2c_host -{ - struct device_node *np; /* OF device node */ - struct semaphore mutex; /* Access mutex for use by i2c-keywest */ - low_i2c_func_t func; /* Access function */ - unsigned int is_open : 1; /* Poor man's access control */ - int mode; /* Current mode */ - int channel; /* Current channel */ - int num_channels; /* Number of channels */ - void __iomem *base; /* For keywest-i2c, base address */ - int bsteps; /* And register stepping */ - int speed; /* And speed */ -}; - -static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST]; +#ifdef DEBUG_LOW +#define DBG_LOW(x...) do {\ + printk(KERN_DEBUG "low_i2c:" x); \ + } while(0) +#else +#define DBG_LOW(x...) +#endif -/* No locking is necessary on allocation, we are running way before - * anything can race with us +/* + * A bus structure. Each bus in the system has such a structure associated. */ -static struct low_i2c_host *find_low_i2c_host(struct device_node *np) +struct pmac_i2c_bus { - int i; + struct list_head link; + struct device_node *controller; + struct device_node *busnode; + int type; + int flags; + struct i2c_adapter *adapter; + void *hostdata; + int channel; /* some hosts have multiple */ + int mode; /* current mode */ + struct semaphore sem; + int opened; + int polled; /* open mode */ + + /* ops */ + int (*open)(struct pmac_i2c_bus *bus); + void (*close)(struct pmac_i2c_bus *bus); + int (*xfer)(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, + u32 subaddr, u8 *data, int len); +}; - for (i = 0; i < MAX_LOW_I2C_HOST; i++) - if (low_i2c_hosts[i].np == np) - return &low_i2c_hosts[i]; - return NULL; -} +static LIST_HEAD(pmac_i2c_busses); /* - * - * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's) - * + * Keywest implementation */ -/* - * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h, - * should be moved somewhere in include/asm-ppc/ - */ +struct pmac_i2c_host_kw +{ + struct semaphore mutex; /* Access mutex for use by + * i2c-keywest */ + void __iomem *base; /* register base address */ + int bsteps; /* register stepping */ + int speed; /* speed */ +}; + /* Register indices */ typedef enum { reg_mode = 0, @@ -153,52 +171,56 @@ static const char *__kw_state_names[] = { "state_dead" }; -static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) +static inline u8 __kw_read_reg(struct pmac_i2c_bus *bus, reg_t reg) { + struct pmac_i2c_host_kw *host = bus->hostdata; return readb(host->base + (((unsigned int)reg) << host->bsteps)); } -static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) +static inline void __kw_write_reg(struct pmac_i2c_bus *bus, reg_t reg, u8 val) { + struct pmac_i2c_host_kw *host = bus->hostdata; writeb(val, host->base + (((unsigned)reg) << host->bsteps)); - (void)__kw_read_reg(host, reg_subaddr); + (void)__kw_read_reg(bus, reg_subaddr); } -#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) -#define kw_read_reg(reg) __kw_read_reg(host, reg) +#define kw_write_reg(reg, val) __kw_write_reg(bus, reg, val) +#define kw_read_reg(reg) __kw_read_reg(bus, reg) - -/* Don't schedule, the g5 fan controller is too - * timing sensitive - */ -static u8 kw_wait_interrupt(struct low_i2c_host* host) +static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) { int i, j; u8 isr; - for (i = 0; i < 100000; i++) { + for (i = 0; i < 1000; i++) { isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; if (isr != 0) return isr; /* This code is used with the timebase frozen, we cannot rely - * on udelay ! For now, just use a bogus loop + * on udelay nor schedule when in polled mode ! + * For now, just use a bogus loop.... */ - for (j = 1; j < 10000; j++) - mb(); + if (bus->polled) { + for (j = 1; j < 1000000; j++) + mb(); + } else + msleep(1); } return isr; } -static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) +static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw, + int *rc, u8 **data, int *len, u8 isr) { u8 ack; - DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr); + DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n", + __kw_state_names[state], isr); if (isr == 0) { if (state != state_stop) { - DBG("KW: Timeout !\n"); + DBG_LOW("KW: Timeout !\n"); *rc = -EIO; goto stop; } @@ -220,15 +242,16 @@ static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc = -EIO; goto stop; } - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { + if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { *rc = -ENODEV; - DBG("KW: NAK on address\n"); + DBG_LOW("KW: NAK on address\n"); return state_stop; } else { if (rw) { state = state_read; if (*len > 1) - kw_write_reg(reg_control, KW_I2C_CTL_AAK); + kw_write_reg(reg_control, + KW_I2C_CTL_AAK); } else { state = state_write; kw_write_reg(reg_data, **data); @@ -250,7 +273,7 @@ static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int } else if (state == state_write) { ack = kw_read_reg(reg_status); if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - DBG("KW: nack on data write\n"); + DBG_LOW("KW: nack on data write\n"); *rc = -EIO; goto stop; } else if (*len) { @@ -291,35 +314,57 @@ static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int return state_stop; } -static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len) +static int kw_i2c_open(struct pmac_i2c_bus *bus) { + struct pmac_i2c_host_kw *host = bus->hostdata; + down(&host->mutex); + return 0; +} + +static void kw_i2c_close(struct pmac_i2c_bus *bus) +{ + struct pmac_i2c_host_kw *host = bus->hostdata; + up(&host->mutex); +} + +static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, + u32 subaddr, u8 *data, int len) +{ + struct pmac_i2c_host_kw *host = bus->hostdata; u8 mode_reg = host->speed; int state = state_addr; int rc = 0; /* Setup mode & subaddress if any */ - switch(host->mode) { - case pmac_low_i2c_mode_dumb: - printk(KERN_ERR "low_i2c: Dumb mode not supported !\n"); + switch(bus->mode) { + case pmac_i2c_mode_dumb: return -EINVAL; - case pmac_low_i2c_mode_std: + case pmac_i2c_mode_std: mode_reg |= KW_I2C_MODE_STANDARD; + if (subsize != 0) + return -EINVAL; break; - case pmac_low_i2c_mode_stdsub: + case pmac_i2c_mode_stdsub: mode_reg |= KW_I2C_MODE_STANDARDSUB; + if (subsize != 1) + return -EINVAL; break; - case pmac_low_i2c_mode_combined: + case pmac_i2c_mode_combined: mode_reg |= KW_I2C_MODE_COMBINED; + if (subsize != 1) + return -EINVAL; break; } /* Setup channel & clear pending irqs */ kw_write_reg(reg_isr, kw_read_reg(reg_isr)); - kw_write_reg(reg_mode, mode_reg | (host->channel << 4)); + kw_write_reg(reg_mode, mode_reg | (bus->channel << 4)); kw_write_reg(reg_status, 0); - /* Set up address and r/w bit */ - kw_write_reg(reg_addr, addr); + /* Set up address and r/w bit, strip possible stale bus number from + * address top bits + */ + kw_write_reg(reg_addr, addrdir & 0xff); /* Set up the sub address */ if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB @@ -330,27 +375,27 @@ static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); kw_write_reg(reg_control, KW_I2C_CTL_XADDR); - /* State machine, to turn into an interrupt handler */ + /* State machine, to turn into an interrupt handler in the future */ while(state != state_idle) { - u8 isr = kw_wait_interrupt(host); - state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr); + u8 isr = kw_i2c_wait_interrupt(bus); + state = kw_i2c_handle_interrupt(bus, state, addrdir & 1, &rc, + &data, &len, isr); } return rc; } -static void keywest_low_i2c_add(struct device_node *np) +static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) { - struct low_i2c_host *host = find_low_i2c_host(NULL); + struct pmac_i2c_host_kw *host; u32 *psteps, *prate, *addrp, steps; - struct device_node *parent; + host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL); if (host == NULL) { printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", np->full_name); - return; + return NULL; } - memset(host, 0, sizeof(*host)); /* Apple is kind enough to provide a valid AAPL,address property * on all i2c keywest nodes so far ... we would have to fallback @@ -360,18 +405,14 @@ static void keywest_low_i2c_add(struct device_node *np) if (addrp == NULL) { printk(KERN_ERR "low_i2c: Can't find address for %s\n", np->full_name); - return; + kfree(host); + return NULL; } init_MUTEX(&host->mutex); - host->np = of_node_get(np); psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); steps = psteps ? (*psteps) : 0x10; for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) steps >>= 1; - parent = of_get_parent(np); - host->num_channels = 1; - if (parent && parent->name[0] == 'u') - host->num_channels = 2; /* Select interface rate */ host->speed = KW_I2C_MODE_25KHZ; prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); @@ -387,148 +428,620 @@ static void keywest_low_i2c_add(struct device_node *np) break; } - printk(KERN_INFO "low_i2c: Bus %s found at 0x%08x, %d channels," - " speed = %d KHz\n", - np->full_name, *addrp, host->num_channels, prate ? *prate : 25); - - host->mode = pmac_low_i2c_mode_std; + printk(KERN_INFO "KeyWest i2c @0x%08x %s\n", *addrp, np->full_name); host->base = ioremap((*addrp), 0x1000); - host->func = keywest_low_i2c_func; + + return host; } + +static void __init kw_i2c_add(struct pmac_i2c_host_kw *host, + struct device_node *controller, + struct device_node *busnode, + int channel) +{ + struct pmac_i2c_bus *bus; + + bus = kzalloc(sizeof(struct pmac_i2c_bus), GFP_KERNEL); + if (bus == NULL) + return; + + bus->controller = of_node_get(controller); + bus->busnode = of_node_get(busnode); + bus->type = pmac_i2c_bus_keywest; + bus->hostdata = host; + bus->channel = channel; + bus->mode = pmac_i2c_mode_std; + bus->open = kw_i2c_open; + bus->close = kw_i2c_close; + bus->xfer = kw_i2c_xfer; + init_MUTEX(&bus->sem); + if (controller == busnode) + bus->flags = pmac_i2c_multibus; + list_add(&bus->link, &pmac_i2c_busses); + + printk(KERN_INFO " channel %d bus %s\n", channel, + (controller == busnode) ? "" : busnode->full_name); +} + +static void __init kw_i2c_probe(void) +{ + struct device_node *np, *child, *parent; + + /* Probe keywest-i2c busses */ + for (np = NULL; + (np = of_find_compatible_node(np, "i2c","keywest-i2c")) != NULL;){ + struct pmac_i2c_host_kw *host; + int multibus, chans, i; + + /* Found one, init a host structure */ + host = kw_i2c_host_init(np); + if (host == NULL) + continue; + + /* Now check if we have a multibus setup (old style) or if we + * have proper bus nodes. Note that the "new" way (proper bus + * nodes) might cause us to not create some busses that are + * kept hidden in the device-tree. In the future, we might + * want to work around that by creating busses without a node + * but not for now + */ + child = of_get_next_child(np, NULL); + multibus = !child || strcmp(child->name, "i2c-bus"); + of_node_put(child); + + /* For a multibus setup, we get the bus count based on the + * parent type + */ + if (multibus) { + parent = of_get_parent(np); + if (parent == NULL) + continue; + chans = parent->name[0] == 'u' ? 2 : 1; + for (i = 0; i < chans; i++) + kw_i2c_add(host, np, np, i); + } else { + for (child = NULL; + (child = of_get_next_child(np, child)) != NULL;) { + u32 *reg = + (u32 *)get_property(child, "reg", NULL); + if (reg == NULL) + continue; + kw_i2c_add(host, np, child, *reg); + } + } + } +} + + /* * * PMU implementation * */ - #ifdef CONFIG_ADB_PMU -static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len) +/* + * i2c command block to the PMU + */ +struct pmu_i2c_hdr { + u8 bus; + u8 mode; + u8 bus2; + u8 address; + u8 sub_addr; + u8 comb_addr; + u8 count; + u8 data[]; +}; + +static void pmu_i2c_complete(struct adb_request *req) { - // TODO - return -ENODEV; + complete(req->arg); } -static void pmu_low_i2c_add(struct device_node *np) +static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, + u32 subaddr, u8 *data, int len) { - struct low_i2c_host *host = find_low_i2c_host(NULL); + struct adb_request *req = bus->hostdata; + struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req->data[1]; + struct completion comp; + int read = addrdir & 1; + int retry; + int rc = 0; - if (host == NULL) { - printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", - np->full_name); - return; + /* For now, limit ourselves to 16 bytes transfers */ + if (len > 16) + return -EINVAL; + + init_completion(&comp); + + for (retry = 0; retry < 16; retry++) { + memset(req, 0, sizeof(struct adb_request)); + hdr->bus = bus->channel; + hdr->count = len; + + switch(bus->mode) { + case pmac_i2c_mode_std: + if (subsize != 0) + return -EINVAL; + hdr->address = addrdir; + hdr->mode = PMU_I2C_MODE_SIMPLE; + break; + case pmac_i2c_mode_stdsub: + case pmac_i2c_mode_combined: + if (subsize != 1) + return -EINVAL; + hdr->address = addrdir & 0xfe; + hdr->comb_addr = addrdir; + hdr->sub_addr = subaddr; + if (bus->mode == pmac_i2c_mode_stdsub) + hdr->mode = PMU_I2C_MODE_STDSUB; + else + hdr->mode = PMU_I2C_MODE_COMBINED; + break; + default: + return -EINVAL; + } + + INIT_COMPLETION(comp); + req->data[0] = PMU_I2C_CMD; + req->reply[0] = 0xff; + req->nbytes = sizeof(struct pmu_i2c_hdr) + 1; + req->done = pmu_i2c_complete; + req->arg = ∁ + if (!read) { + memcpy(hdr->data, data, len); + req->nbytes += len; + } + rc = pmu_queue_request(req); + if (rc) + return rc; + wait_for_completion(&comp); + if (req->reply[0] == PMU_I2C_STATUS_OK) + break; + msleep(15); } - memset(host, 0, sizeof(*host)); + if (req->reply[0] != PMU_I2C_STATUS_OK) + return -EIO; - init_MUTEX(&host->mutex); - host->np = of_node_get(np); - host->num_channels = 3; - host->mode = pmac_low_i2c_mode_std; - host->func = pmu_low_i2c_func; + for (retry = 0; retry < 16; retry++) { + memset(req, 0, sizeof(struct adb_request)); + + /* I know that looks like a lot, slow as hell, but darwin + * does it so let's be on the safe side for now + */ + msleep(15); + + hdr->bus = PMU_I2C_BUS_STATUS; + + INIT_COMPLETION(comp); + req->data[0] = PMU_I2C_CMD; + req->reply[0] = 0xff; + req->nbytes = 2; + req->done = pmu_i2c_complete; + req->arg = ∁ + rc = pmu_queue_request(req); + if (rc) + return rc; + wait_for_completion(&comp); + + if (req->reply[0] == PMU_I2C_STATUS_OK && !read) + return 0; + if (req->reply[0] == PMU_I2C_STATUS_DATAREAD && read) { + int rlen = req->reply_len - 1; + + if (rlen != len) { + printk(KERN_WARNING "low_i2c: PMU returned %d" + " bytes, expected %d !\n", rlen, len); + return -EIO; + } + memcpy(data, &req->reply[1], len); + return 0; + } + } + return -EIO; +} + +static void __init pmu_i2c_probe(void) +{ + struct pmac_i2c_bus *bus; + struct device_node *busnode; + int channel, sz; + + if (!pmu_present()) + return; + + /* There might or might not be a "pmu-i2c" node, we use that + * or via-pmu itself, whatever we find. I haven't seen a machine + * with separate bus nodes, so we assume a multibus setup + */ + busnode = of_find_node_by_name(NULL, "pmu-i2c"); + if (busnode == NULL) + busnode = of_find_node_by_name(NULL, "via-pmu"); + if (busnode == NULL) + return; + + printk(KERN_INFO "PMU i2c %s\n", busnode->full_name); + + /* + * We add bus 1 and 2 only for now, bus 0 is "special" + */ + for (channel = 1; channel <= 2; channel++) { + sz = sizeof(struct pmac_i2c_bus) + sizeof(struct adb_request); + bus = kzalloc(sz, GFP_KERNEL); + if (bus == NULL) + return; + + bus->controller = busnode; + bus->busnode = busnode; + bus->type = pmac_i2c_bus_pmu; + bus->channel = channel; + bus->mode = pmac_i2c_mode_std; + bus->hostdata = bus + 1; + bus->xfer = pmu_i2c_xfer; + init_MUTEX(&bus->sem); + bus->flags = pmac_i2c_multibus; + list_add(&bus->link, &pmac_i2c_busses); + + printk(KERN_INFO " channel %d bus \n", channel); + } } #endif /* CONFIG_ADB_PMU */ -void __init pmac_init_low_i2c(void) + +/* + * + * SMU implementation + * + */ + +#ifdef CONFIG_PMAC_SMU + +static void smu_i2c_complete(struct smu_i2c_cmd *cmd, void *misc) { - struct device_node *np; + complete(misc); +} - /* Probe keywest-i2c busses */ - np = of_find_compatible_node(NULL, "i2c", "keywest-i2c"); - while(np) { - keywest_low_i2c_add(np); - np = of_find_compatible_node(np, "i2c", "keywest-i2c"); +static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, + u32 subaddr, u8 *data, int len) +{ + struct smu_i2c_cmd *cmd = bus->hostdata; + struct completion comp; + int read = addrdir & 1; + int rc = 0; + + memset(cmd, 0, sizeof(struct smu_i2c_cmd)); + cmd->info.bus = bus->channel; + cmd->info.devaddr = addrdir; + cmd->info.datalen = len; + + switch(bus->mode) { + case pmac_i2c_mode_std: + if (subsize != 0) + return -EINVAL; + cmd->info.type = SMU_I2C_TRANSFER_SIMPLE; + break; + case pmac_i2c_mode_stdsub: + case pmac_i2c_mode_combined: + if (subsize > 3 || subsize < 1) + return -EINVAL; + cmd->info.sublen = subsize; + /* that's big-endian only but heh ! */ + memcpy(&cmd->info.subaddr, ((char *)&subaddr) + (4 - subsize), + subsize); + if (bus->mode == pmac_i2c_mode_stdsub) + cmd->info.type = SMU_I2C_TRANSFER_STDSUB; + else + cmd->info.type = SMU_I2C_TRANSFER_COMBINED; + break; + default: + return -EINVAL; } + if (!read) + memcpy(cmd->info.data, data, len); + + init_completion(&comp); + cmd->done = smu_i2c_complete; + cmd->misc = ∁ + rc = smu_queue_i2c(cmd); + if (rc < 0) + return rc; + wait_for_completion(&comp); + rc = cmd->status; + + if (read) + memcpy(data, cmd->info.data, len); + return rc < 0 ? rc : 0; +} -#ifdef CONFIG_ADB_PMU - /* Probe PMU busses */ - np = of_find_node_by_name(NULL, "via-pmu"); - if (np) - pmu_low_i2c_add(np); -#endif /* CONFIG_ADB_PMU */ +static void __init smu_i2c_probe(void) +{ + struct device_node *controller, *busnode; + struct pmac_i2c_bus *bus; + u32 *reg; + int sz; + + if (!smu_present()) + return; + + controller = of_find_node_by_name(NULL, "smu_i2c_control"); + if (controller == NULL) + controller = of_find_node_by_name(NULL, "smu"); + if (controller == NULL) + return; + + printk(KERN_INFO "SMU i2c %s\n", controller->full_name); + + /* Look for childs, note that they might not be of the right + * type as older device trees mix i2c busses and other thigns + * at the same level + */ + for (busnode = NULL; + (busnode = of_get_next_child(controller, busnode)) != NULL;) { + if (strcmp(busnode->type, "i2c") && + strcmp(busnode->type, "i2c-bus")) + continue; + reg = (u32 *)get_property(busnode, "reg", NULL); + if (reg == NULL) + continue; + + sz = sizeof(struct pmac_i2c_bus) + sizeof(struct smu_i2c_cmd); + bus = kzalloc(sz, GFP_KERNEL); + if (bus == NULL) + return; + + bus->controller = controller; + bus->busnode = of_node_get(busnode); + bus->type = pmac_i2c_bus_smu; + bus->channel = *reg; + bus->mode = pmac_i2c_mode_std; + bus->hostdata = bus + 1; + bus->xfer = smu_i2c_xfer; + init_MUTEX(&bus->sem); + bus->flags = 0; + list_add(&bus->link, &pmac_i2c_busses); + + printk(KERN_INFO " channel %x bus %s\n", + bus->channel, busnode->full_name); + } +} + +#endif /* CONFIG_PMAC_SMU */ + +/* + * + * Core code + * + */ + + +struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node) +{ + struct device_node *p = of_node_get(node); + struct device_node *prev = NULL; + struct pmac_i2c_bus *bus; + + while(p) { + list_for_each_entry(bus, &pmac_i2c_busses, link) { + if (p == bus->busnode) { + if (prev && bus->flags & pmac_i2c_multibus) { + u32 *reg; + reg = (u32 *)get_property(prev, "reg", + NULL); + if (!reg) + continue; + if (((*reg) >> 8) != bus->channel) + continue; + } + of_node_put(p); + of_node_put(prev); + return bus; + } + } + of_node_put(prev); + prev = p; + p = of_get_parent(p); + } + return NULL; +} +EXPORT_SYMBOL_GPL(pmac_i2c_find_bus); + +u8 pmac_i2c_get_dev_addr(struct device_node *device) +{ + u32 *reg = (u32 *)get_property(device, "reg", NULL); + + if (reg == NULL) + return 0; + + return (*reg) & 0xff; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_dev_addr); + +struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus) +{ + return bus->controller; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_controller); + +struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus) +{ + return bus->busnode; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_bus_node); + +int pmac_i2c_get_type(struct pmac_i2c_bus *bus) +{ + return bus->type; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_type); + +int pmac_i2c_get_flags(struct pmac_i2c_bus *bus) +{ + return bus->flags; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_flags); - /* TODO: Add CUDA support as well */ +void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, + struct i2c_adapter *adapter) +{ + WARN_ON(bus->adapter != NULL); + bus->adapter = adapter; } +EXPORT_SYMBOL_GPL(pmac_i2c_attach_adapter); + +void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus, + struct i2c_adapter *adapter) +{ + WARN_ON(bus->adapter != adapter); + bus->adapter = NULL; +} +EXPORT_SYMBOL_GPL(pmac_i2c_detach_adapter); + +struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus) +{ + return bus->adapter; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter); + +extern int pmac_i2c_match_adapter(struct device_node *dev, + struct i2c_adapter *adapter) +{ + struct pmac_i2c_bus *bus = pmac_i2c_find_bus(dev); + + if (bus == NULL) + return 0; + return (bus->adapter == adapter); +} +EXPORT_SYMBOL_GPL(pmac_i2c_match_adapter); int pmac_low_i2c_lock(struct device_node *np) { - struct low_i2c_host *host = find_low_i2c_host(np); + struct pmac_i2c_bus *bus, *found = NULL; - if (!host) + list_for_each_entry(bus, &pmac_i2c_busses, link) { + if (np == bus->controller) { + found = bus; + break; + } + } + if (!found) return -ENODEV; - down(&host->mutex); - return 0; + return pmac_i2c_open(bus, 0); } -EXPORT_SYMBOL(pmac_low_i2c_lock); +EXPORT_SYMBOL_GPL(pmac_low_i2c_lock); int pmac_low_i2c_unlock(struct device_node *np) { - struct low_i2c_host *host = find_low_i2c_host(np); + struct pmac_i2c_bus *bus, *found = NULL; - if (!host) + list_for_each_entry(bus, &pmac_i2c_busses, link) { + if (np == bus->controller) { + found = bus; + break; + } + } + if (!found) return -ENODEV; - up(&host->mutex); + pmac_i2c_close(bus); return 0; } -EXPORT_SYMBOL(pmac_low_i2c_unlock); +EXPORT_SYMBOL_GPL(pmac_low_i2c_unlock); -int pmac_low_i2c_open(struct device_node *np, int channel) +int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) { - struct low_i2c_host *host = find_low_i2c_host(np); + int rc; + + down(&bus->sem); + bus->polled = polled; + bus->opened = 1; + bus->mode = pmac_i2c_mode_std; + if (bus->open && (rc = bus->open(bus)) != 0) { + bus->opened = 0; + up(&bus->sem); + return rc; + } + return 0; +} +EXPORT_SYMBOL_GPL(pmac_i2c_open); - if (!host) - return -ENODEV; +void pmac_i2c_close(struct pmac_i2c_bus *bus) +{ + WARN_ON(!bus->opened); + if (bus->close) + bus->close(bus); + bus->opened = 0; + up(&bus->sem); +} +EXPORT_SYMBOL_GPL(pmac_i2c_close); - if (channel >= host->num_channels) - return -EINVAL; +int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode) +{ + WARN_ON(!bus->opened); - down(&host->mutex); - host->is_open = 1; - host->channel = channel; + /* Report me if you see the error below as there might be a new + * "combined4" mode that I need to implement for the SMU bus + */ + if (mode < pmac_i2c_mode_dumb || mode > pmac_i2c_mode_combined) { + printk(KERN_ERR "low_i2c: Invalid mode %d requested on" + " bus %s !\n", mode, bus->busnode->full_name); + return -EINVAL; + } + bus->mode = mode; return 0; } -EXPORT_SYMBOL(pmac_low_i2c_open); +EXPORT_SYMBOL_GPL(pmac_i2c_setmode); -int pmac_low_i2c_close(struct device_node *np) +int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, + u32 subaddr, u8 *data, int len) { - struct low_i2c_host *host = find_low_i2c_host(np); + int rc; - if (!host) - return -ENODEV; + WARN_ON(!bus->opened); - host->is_open = 0; - up(&host->mutex); + DBG("xfer() chan=%d, addrdir=0x%x, mode=%d, subsize=%d, subaddr=0x%x," + " %d bytes, bus %s\n", bus->channel, addrdir, bus->mode, subsize, + subaddr, len, bus->busnode->full_name); - return 0; + rc = bus->xfer(bus, addrdir, subsize, subaddr, data, len); + +#ifdef DEBUG + if (rc) + DBG("xfer error %d\n", rc); +#endif + return rc; } -EXPORT_SYMBOL(pmac_low_i2c_close); +EXPORT_SYMBOL_GPL(pmac_i2c_xfer); -int pmac_low_i2c_setmode(struct device_node *np, int mode) +/* + * Initialize us: probe all i2c busses on the machine and instantiate + * busses. + */ +/* This is non-static as it might be called early by smp code */ +int __init pmac_i2c_init(void) { - struct low_i2c_host *host = find_low_i2c_host(np); + static int i2c_inited; - if (!host) - return -ENODEV; - WARN_ON(!host->is_open); - host->mode = mode; + if (i2c_inited) + return 0; + i2c_inited = 1; - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_setmode); + /* Probe keywest-i2c busses */ + kw_i2c_probe(); -int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len) -{ - struct low_i2c_host *host = find_low_i2c_host(np); +#ifdef CONFIG_ADB_PMU + pmu_i2c_probe(); +#endif - if (!host) - return -ENODEV; - WARN_ON(!host->is_open); +#ifdef CONFIG_PMAC_SMU + smu_i2c_probe(); +#endif - return host->func(host, addrdir, subaddr, data, len); + return 0; } -EXPORT_SYMBOL(pmac_low_i2c_xfer); +arch_initcall(pmac_i2c_init); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index e5a5bdbdda7a..dc5cdc1484e8 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -652,27 +652,22 @@ static int __init pmac_declare_of_platform_devices(void) { struct device_node *np, *npp; - np = find_devices("uni-n"); - if (np) { - for (np = np->child; np != NULL; np = np->sibling) - if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "uni-n-i2c", - NULL); - break; - } - } - np = find_devices("valkyrie"); + np = of_find_node_by_name(NULL, "valkyrie"); if (np) of_platform_device_create(np, "valkyrie", NULL); - np = find_devices("platinum"); + np = of_find_node_by_name(NULL, "platinum"); if (np) of_platform_device_create(np, "platinum", NULL); - - npp = of_find_node_by_name(NULL, "u3"); + npp = of_find_node_by_name(NULL, "uni-n"); + if (npp == NULL) + npp = of_find_node_by_name(NULL, "u3"); + if (npp == NULL) + npp = of_find_node_by_name(NULL, "u4"); if (npp) { for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "u3-i2c", NULL); + of_platform_device_create(np, "uni-n-i2c", + NULL); of_node_put(np); break; } diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index df01bb8feb16..ab72ba86be1e 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -482,7 +482,7 @@ static void __devinit smp_core99_take_timebase(void) /* * G5s enable/disable the timebase via an i2c-connected clock chip. */ -static struct device_node *pmac_tb_clock_chip_host; +static struct pmac_i2c_bus *pmac_tb_clock_chip_host; static u8 pmac_tb_pulsar_addr; static void smp_core99_cypress_tb_freeze(int freeze) @@ -493,20 +493,20 @@ static void smp_core99_cypress_tb_freeze(int freeze) /* Strangely, the device-tree says address is 0xd2, but darwin * accesses 0xd0 ... */ - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, - pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd0 | pmac_low_i2c_read, - 0x81, &data, 1); + pmac_i2c_setmode(pmac_tb_clock_chip_host, + pmac_i2c_mode_combined); + rc = pmac_i2c_xfer(pmac_tb_clock_chip_host, + 0xd0 | pmac_i2c_read, + 1, 0x81, &data, 1); if (rc != 0) goto bail; data = (data & 0xf3) | (freeze ? 0x00 : 0x0c); - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd0 | pmac_low_i2c_write, - 0x81, &data, 1); + pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub); + rc = pmac_i2c_xfer(pmac_tb_clock_chip_host, + 0xd0 | pmac_i2c_write, + 1, 0x81, &data, 1); bail: if (rc != 0) { @@ -522,20 +522,20 @@ static void smp_core99_pulsar_tb_freeze(int freeze) u8 data; int rc; - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, - pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - pmac_tb_pulsar_addr | pmac_low_i2c_read, - 0x2e, &data, 1); + pmac_i2c_setmode(pmac_tb_clock_chip_host, + pmac_i2c_mode_combined); + rc = pmac_i2c_xfer(pmac_tb_clock_chip_host, + pmac_tb_pulsar_addr | pmac_i2c_read, + 1, 0x2e, &data, 1); if (rc != 0) goto bail; data = (data & 0x88) | (freeze ? 0x11 : 0x22); - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - pmac_tb_pulsar_addr | pmac_low_i2c_write, - 0x2e, &data, 1); + pmac_i2c_setmode(pmac_tb_clock_chip_host, pmac_i2c_mode_stdsub); + rc = pmac_i2c_xfer(pmac_tb_clock_chip_host, + pmac_tb_pulsar_addr | pmac_i2c_write, + 1, 0x2e, &data, 1); bail: if (rc != 0) { printk(KERN_ERR "Pulsar Timebase %s rc: %d\n", @@ -560,13 +560,15 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus) if (!ok) continue; + pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc); + if (pmac_tb_clock_chip_host == NULL) + continue; reg = (u32 *)get_property(cc, "reg", NULL); if (reg == NULL) continue; - switch (*reg) { case 0xd2: - if (device_is_compatible(cc, "pulsar-legacy-slewing")) { + if (device_is_compatible(cc,"pulsar-legacy-slewing")) { pmac_tb_freeze = smp_core99_pulsar_tb_freeze; pmac_tb_pulsar_addr = 0xd2; name = "Pulsar"; @@ -585,30 +587,19 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus) break; } if (pmac_tb_freeze != NULL) { - struct device_node *p = of_get_parent(cc); - of_node_put(cc); - while(p && strcmp(p->type, "i2c")) { - cc = of_get_parent(p); - of_node_put(p); - p = cc; - } - if (p == NULL) - goto no_i2c_sync; /* Open i2c bus for synchronous access */ - if (pmac_low_i2c_open(p, 0)) { - printk(KERN_ERR "Failed top open i2c bus %s for clock" - " sync, fallback to software sync !\n", - p->full_name); - of_node_put(p); + if (pmac_i2c_open(pmac_tb_clock_chip_host, 1)) { + printk(KERN_ERR "Failed top open i2c bus for clock" + " sync, fallback to software sync !\n"); goto no_i2c_sync; } - pmac_tb_clock_chip_host = p; printk(KERN_INFO "Processor timebase sync using %s i2c clock\n", name); return; } no_i2c_sync: pmac_tb_freeze = NULL; + pmac_tb_clock_chip_host = NULL; } #endif /* CONFIG_PPC64 */ @@ -752,8 +743,18 @@ static int __init smp_core99_probe(void) if (ncpus <= 1) return 1; + /* We need to perform some early initialisations before we can start + * setting up SMP as we are running before initcalls + */ + pmac_i2c_init(); + + /* Setup various bits like timebase sync method, ability to nap, ... */ smp_core99_setup(ncpus); + + /* Install IPIs */ mpic_request_ipis(); + + /* Collect l2cr and l3cr values from CPU 0 */ core99_init_caches(0); return ncpus; @@ -817,7 +818,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) /* Close i2c bus if it was used for tb sync */ if (pmac_tb_clock_chip_host) { - pmac_low_i2c_close(pmac_tb_clock_chip_host); + pmac_i2c_close(pmac_tb_clock_chip_host); pmac_tb_clock_chip_host = NULL; } diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c index bfefe7f7a53d..7d925be3fd4b 100644 --- a/drivers/i2c/busses/i2c-pmac-smu.c +++ b/drivers/i2c/busses/i2c-pmac-smu.c @@ -103,8 +103,8 @@ static s32 smu_smbus_xfer( struct i2c_adapter* adap, cmd.info.subaddr[1] = 0; cmd.info.subaddr[2] = 0; if (!read) { - cmd.info.data[0] = data->byte & 0xff; - cmd.info.data[1] = (data->byte >> 8) & 0xff; + cmd.info.data[0] = data->word & 0xff; + cmd.info.data[1] = (data->word >> 8) & 0xff; } break; /* Note that these are broken vs. the expected smbus API where @@ -116,7 +116,7 @@ static s32 smu_smbus_xfer( struct i2c_adapter* adap, case I2C_SMBUS_BLOCK_DATA: cmd.info.type = SMU_I2C_TRANSFER_STDSUB; cmd.info.datalen = data->block[0] + 1; - if (cmd.info.datalen > 6) + if (cmd.info.datalen > (SMU_I2C_WRITE_MAX + 1)) return -EINVAL; if (!read) memcpy(cmd.info.data, data->block, cmd.info.datalen); @@ -273,7 +273,13 @@ static int dispose_iface(struct device *dev) static int create_iface_of_platform(struct of_device* dev, const struct of_device_id *match) { - return create_iface(dev->node, &dev->dev); + struct device_node *node = dev->node; + + if (device_is_compatible(node, "smu-i2c") || + (node->parent != NULL && + device_is_compatible(node->parent, "smu-i2c-control"))) + return create_iface(node, &dev->dev); + return -ENODEV; } @@ -288,6 +294,9 @@ static struct of_device_id i2c_smu_match[] = { .compatible = "smu-i2c", }, + { + .compatible = "i2c-bus", + }, {}, }; static struct of_platform_driver i2c_smu_of_platform_driver = diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 96226116a646..9ecd76849e35 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -94,6 +94,8 @@ struct smu_device { static struct smu_device *smu; static DECLARE_MUTEX(smu_part_access); +static void smu_i2c_retry(unsigned long data); + /* * SMU driver low level stuff */ @@ -469,7 +471,6 @@ int __init smu_init (void) smu->of_node = np; smu->db_irq = NO_IRQ; smu->msg_irq = NO_IRQ; - init_timer(&smu->i2c_timer); /* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a * 32 bits value safely @@ -544,6 +545,10 @@ static int smu_late_init(void) if (!smu) return 0; + init_timer(&smu->i2c_timer); + smu->i2c_timer.function = smu_i2c_retry; + smu->i2c_timer.data = (unsigned long)smu; + /* * Try to request the interrupts */ @@ -570,28 +575,41 @@ static int smu_late_init(void) return 0; } -arch_initcall(smu_late_init); +/* This has to be before arch_initcall as the low i2c stuff relies on the + * above having been done before we reach arch_initcalls + */ +core_initcall(smu_late_init); /* * sysfs visibility */ +static void smu_create_i2c(struct device_node *np) +{ + char name[32]; + u32 *reg = (u32 *)get_property(np, "reg", NULL); + + if (reg != NULL) { + sprintf(name, "smu-i2c-%02x", *reg); + of_platform_device_create(np, name, &smu->of_dev->dev); + } +} + static void smu_expose_childs(void *unused) { - struct device_node *np; + struct device_node *np, *gp; for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) { - if (device_is_compatible(np, "smu-i2c")) { - char name[32]; - u32 *reg = (u32 *)get_property(np, "reg", NULL); - - if (reg == NULL) - continue; - sprintf(name, "smu-i2c-%02x", *reg); - of_platform_device_create(np, name, &smu->of_dev->dev); - } + if (device_is_compatible(np, "smu-i2c-control")) { + gp = NULL; + while ((gp = of_get_next_child(np, gp)) != NULL) + if (device_is_compatible(gp, "i2c-bus")) + smu_create_i2c(gp); + } else if (device_is_compatible(np, "smu-i2c")) + smu_create_i2c(np); if (device_is_compatible(np, "smu-sensors")) - of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev); + of_platform_device_create(np, "smu-sensors", + &smu->of_dev->dev); } } @@ -712,13 +730,13 @@ static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail) static void smu_i2c_retry(unsigned long data) { - struct smu_i2c_cmd *cmd = (struct smu_i2c_cmd *)data; + struct smu_i2c_cmd *cmd = smu->cmd_i2c_cur; DPRINTK("SMU: i2c failure, requeuing...\n"); /* requeue command simply by resetting reply_len */ cmd->pdata[0] = 0xff; - cmd->scmd.reply_len = 0x10; + cmd->scmd.reply_len = sizeof(cmd->pdata); smu_queue_cmd(&cmd->scmd); } @@ -747,10 +765,8 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc) */ if (fail && --cmd->retries > 0) { DPRINTK("SMU: i2c failure, starting timer...\n"); - smu->i2c_timer.function = smu_i2c_retry; - smu->i2c_timer.data = (unsigned long)cmd; - smu->i2c_timer.expires = jiffies + msecs_to_jiffies(5); - add_timer(&smu->i2c_timer); + BUG_ON(cmd != smu->cmd_i2c_cur); + mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5)); return; } @@ -764,7 +780,7 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc) /* Ok, initial command complete, now poll status */ scmd->reply_buf = cmd->pdata; - scmd->reply_len = 0x10; + scmd->reply_len = sizeof(cmd->pdata); scmd->data_buf = cmd->pdata; scmd->data_len = 1; cmd->pdata[0] = 0; @@ -786,7 +802,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd) cmd->scmd.done = smu_i2c_low_completion; cmd->scmd.misc = cmd; cmd->scmd.reply_buf = cmd->pdata; - cmd->scmd.reply_len = 0x10; + cmd->scmd.reply_len = sizeof(cmd->pdata); cmd->scmd.data_buf = (u8 *)(char *)&cmd->info; cmd->scmd.status = 1; cmd->stage = 0; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 3c0552016b91..aa481a88ccab 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -197,7 +197,6 @@ static int pmu_adb_reset_bus(void); #endif /* CONFIG_ADB */ static int init_pmu(void); -static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); @@ -1802,258 +1801,6 @@ pmu_present(void) return via != 0; } -struct pmu_i2c_hdr { - u8 bus; - u8 mode; - u8 bus2; - u8 address; - u8 sub_addr; - u8 comb_addr; - u8 count; -}; - -int -pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr & 0xfe; - hdr->mode = PMU_I2C_MODE_COMBINED; - hdr->bus2 = 0; - hdr->sub_addr = subaddr; - hdr->comb_addr = addr | 1; - hdr->count = len; - - req.nbytes = sizeof(struct pmu_i2c_hdr) + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) { - memcpy(data, &req.reply[1], req.reply_len - 1); - return req.reply_len - 1; - } - } - return -1; -} - -int -pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr & 0xfe; - hdr->mode = PMU_I2C_MODE_STDSUB; - hdr->bus2 = 0; - hdr->sub_addr = subaddr; - hdr->comb_addr = addr & 0xfe; - hdr->count = len; - - req.data[0] = PMU_I2C_CMD; - memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len); - req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - return len; - } - return -1; -} - -int -pmu_i2c_simple_read(int bus, int addr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr | 1; - hdr->mode = PMU_I2C_MODE_SIMPLE; - hdr->bus2 = 0; - hdr->sub_addr = 0; - hdr->comb_addr = 0; - hdr->count = len; - - req.data[0] = PMU_I2C_CMD; - req.nbytes = sizeof(struct pmu_i2c_hdr) + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_DATAREAD) { - memcpy(data, &req.reply[1], req.reply_len - 1); - return req.reply_len - 1; - } - } - return -1; -} - -int -pmu_i2c_simple_write(int bus, int addr, u8* data, int len) -{ - struct adb_request req; - struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req.data[1]; - int retry; - int rc; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - hdr->bus = bus; - hdr->address = addr & 0xfe; - hdr->mode = PMU_I2C_MODE_SIMPLE; - hdr->bus2 = 0; - hdr->sub_addr = 0; - hdr->comb_addr = 0; - hdr->count = len; - - req.data[0] = PMU_I2C_CMD; - memcpy(&req.data[sizeof(struct pmu_i2c_hdr) + 1], data, len); - req.nbytes = sizeof(struct pmu_i2c_hdr) + len + 1; - req.reply_expected = 0; - req.reply_len = 0; - req.reply[0] = 0xff; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - break; - mdelay(15); - } - if (req.reply[0] != PMU_I2C_STATUS_OK) - return -1; - - for (retry=0; retry<16; retry++) { - memset(&req, 0, sizeof(req)); - - mdelay(15); - - hdr->bus = PMU_I2C_BUS_STATUS; - req.reply[0] = 0xff; - - req.nbytes = 2; - req.reply_expected = 0; - req.reply_len = 0; - req.data[0] = PMU_I2C_CMD; - rc = pmu_queue_request(&req); - if (rc) - return rc; - while(!req.complete) - pmu_poll(); - if (req.reply[0] == PMU_I2C_STATUS_OK) - return len; - } - return -1; -} - #ifdef CONFIG_PM static LIST_HEAD(sleep_notifiers); @@ -2358,9 +2105,6 @@ pmac_suspend_devices(void) return -EBUSY; } - /* Disable clock spreading on some machines */ - pmac_tweak_clock_spreading(0); - /* Stop preemption */ preempt_disable(); @@ -2431,9 +2175,6 @@ pmac_wakeup_devices(void) mdelay(10); preempt_enable(); - /* Re-enable clock spreading on some machines */ - pmac_tweak_clock_spreading(1); - /* Resume devices */ device_resume(); @@ -3150,16 +2891,13 @@ static int __init init_pmu_sysfs(void) subsys_initcall(init_pmu_sysfs); EXPORT_SYMBOL(pmu_request); +EXPORT_SYMBOL(pmu_queue_request); EXPORT_SYMBOL(pmu_poll); EXPORT_SYMBOL(pmu_poll_adb); EXPORT_SYMBOL(pmu_wait_complete); EXPORT_SYMBOL(pmu_suspend); EXPORT_SYMBOL(pmu_resume); EXPORT_SYMBOL(pmu_unlock); -EXPORT_SYMBOL(pmu_i2c_combined_read); -EXPORT_SYMBOL(pmu_i2c_stdsub_write); -EXPORT_SYMBOL(pmu_i2c_simple_read); -EXPORT_SYMBOL(pmu_i2c_simple_write); #if defined(CONFIG_PM) && defined(CONFIG_PPC32) EXPORT_SYMBOL(pmu_enable_irled); EXPORT_SYMBOL(pmu_battery_count); diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h index f6997ed5179e..e654ad0e5b42 100644 --- a/include/asm-powerpc/pmac_feature.h +++ b/include/asm-powerpc/pmac_feature.h @@ -318,10 +318,6 @@ extern void pmac_register_agp_pm(struct pci_dev *bridge, extern void pmac_suspend_agp_for_card(struct pci_dev *dev); extern void pmac_resume_agp_for_card(struct pci_dev *dev); -/* Used by the via-pmu driver for suspend/resume - */ -extern void pmac_tweak_clock_spreading(int enable); - /* * The part below is for use by macio_asic.c only, do not rely * on the data structures or constants below in a normal driver diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h index 3fb8d51540dd..adf4fa956572 100644 --- a/include/asm-powerpc/pmac_low_i2c.h +++ b/include/asm-powerpc/pmac_low_i2c.h @@ -15,30 +15,87 @@ /* i2c mode (based on the platform functions format) */ enum { - pmac_low_i2c_mode_dumb = 1, - pmac_low_i2c_mode_std = 2, - pmac_low_i2c_mode_stdsub = 3, - pmac_low_i2c_mode_combined = 4, + pmac_i2c_mode_dumb = 1, + pmac_i2c_mode_std = 2, + pmac_i2c_mode_stdsub = 3, + pmac_i2c_mode_combined = 4, }; /* RW bit in address */ enum { - pmac_low_i2c_read = 0x01, - pmac_low_i2c_write = 0x00 + pmac_i2c_read = 0x01, + pmac_i2c_write = 0x00 }; +/* i2c bus type */ +enum { + pmac_i2c_bus_keywest = 0, + pmac_i2c_bus_pmu = 1, + pmac_i2c_bus_smu = 2, +}; + +/* i2c bus features */ +enum { + /* can_largesub : supports >1 byte subaddresses (SMU only) */ + pmac_i2c_can_largesub = 0x00000001u, + + /* multibus : device node holds multiple busses, bus number is + * encoded in bits 0xff00 of "reg" of a given device + */ + pmac_i2c_multibus = 0x00000002u, +}; + +/* i2c busses in the system */ +struct pmac_i2c_bus; +struct i2c_adapter; + /* Init, called early during boot */ -extern void pmac_init_low_i2c(void); +extern int pmac_i2c_init(void); + +/* Lookup an i2c bus for a device-node. The node can be either the bus + * node itself or a device below it. In the case of a multibus, the bus + * node itself is the controller node, else, it's a child of the controller + * node + */ +extern struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node); + +/* Get the address for an i2c device. This strips the bus number if + * necessary. The 7 bits address is returned 1 bit right shifted so that the + * direction can be directly ored in + */ +extern u8 pmac_i2c_get_dev_addr(struct device_node *device); + +/* Get infos about a bus */ +extern struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus); +extern struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus); +extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus); +extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus); + +/* i2c layer adapter attach/detach */ +extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, + struct i2c_adapter *adapter); +extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus, + struct i2c_adapter *adapter); +extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus); + +/* March a device or bus with an i2c adapter structure, to be used by drivers + * to match device-tree nodes with i2c adapters during adapter discovery + * callbacks + */ +extern int pmac_i2c_match_adapter(struct device_node *dev, + struct i2c_adapter *adapter); + -/* Locking functions exposed to i2c-keywest */ -int pmac_low_i2c_lock(struct device_node *np); -int pmac_low_i2c_unlock(struct device_node *np); +/* (legacy) Locking functions exposed to i2c-keywest */ +extern int pmac_low_i2c_lock(struct device_node *np); +extern int pmac_low_i2c_unlock(struct device_node *np); /* Access functions for platform code */ -int pmac_low_i2c_open(struct device_node *np, int channel); -int pmac_low_i2c_close(struct device_node *np); -int pmac_low_i2c_setmode(struct device_node *np, int mode); -int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len); +extern int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled); +extern void pmac_i2c_close(struct pmac_i2c_bus *bus); +extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode); +extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, + u32 subaddr, u8 *data, int len); #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h index 7fae3ce9a8c1..134c2b5be0f2 100644 --- a/include/asm-powerpc/smu.h +++ b/include/asm-powerpc/smu.h @@ -358,6 +358,9 @@ extern unsigned long smu_cmdbuf_abs; * Kenrel asynchronous i2c interface */ +#define SMU_I2C_READ_MAX 0x1d +#define SMU_I2C_WRITE_MAX 0x15 + /* SMU i2c header, exactly matches i2c header on wire */ struct smu_i2c_param { @@ -368,12 +371,9 @@ struct smu_i2c_param u8 subaddr[3]; /* subaddress */ u8 caddr; /* combined address, filled by SMU driver */ u8 datalen; /* length of transfer */ - u8 data[7]; /* data */ + u8 data[SMU_I2C_READ_MAX]; /* data */ }; -#define SMU_I2C_READ_MAX 0x0d -#define SMU_I2C_WRITE_MAX 0x05 - struct smu_i2c_cmd { /* public */ @@ -387,7 +387,7 @@ struct smu_i2c_cmd int read; int stage; int retries; - u8 pdata[0x10]; + u8 pdata[32]; struct list_head link; }; @@ -519,7 +519,7 @@ struct smu_sdbp_cpupiddata { * if not found. The data format is described below */ extern struct smu_sdbp_header *smu_get_sdb_partition(int id, - unsigned int *size); + unsigned int *size); #endif /* __KERNEL__ */ diff --git a/include/linux/pmu.h b/include/linux/pmu.h index 373bd3b9b330..217d3daf7336 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -140,7 +140,7 @@ extern int find_via_pmu(void); extern int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); - +extern int pmu_queue_request(struct adb_request *req); extern void pmu_poll(void); extern void pmu_poll_adb(void); /* For use by xmon */ extern void pmu_wait_complete(struct adb_request *req); @@ -160,12 +160,6 @@ extern void pmu_unlock(void); extern int pmu_present(void); extern int pmu_get_model(void); -extern int pmu_i2c_combined_read(int bus, int addr, int subaddr, u8* data, int len); -extern int pmu_i2c_stdsub_write(int bus, int addr, int subaddr, u8* data, int len); -extern int pmu_i2c_simple_read(int bus, int addr, u8* data, int len); -extern int pmu_i2c_simple_write(int bus, int addr, u8* data, int len); - - #ifdef CONFIG_PM /* * Stuff for putting the powerbook to sleep and waking it again. -- cgit v1.2.3 From a28d3af2a26c89aaa6470ca36edb212e05143d67 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 7 Jan 2006 11:35:26 +1100 Subject: [PATCH] 2/5 powerpc: Rework PowerMac i2c part 2 This is the continuation of the previous patch. This one removes the old PowerMac i2c drivers (i2c-keywest and i2c-pmac-smu) and replaces them both with a single stub driver that uses the new PowerMac low i2c layer. Now that i2c-keywest is gone, the low-i2c code is extended to support interrupt driver transfers. All i2c busses now appear as platform devices. Compatibility with existing drivers should be maintained as the i2c bus names have been kept identical, except for the SMU bus but in that later case, all users has been fixed. With that patch added, matching a device node to an i2c_adapter becomes trivial. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/low_i2c.c | 318 ++++++++++--- arch/powerpc/platforms/powermac/setup.c | 18 +- drivers/i2c/busses/Kconfig | 24 +- drivers/i2c/busses/Makefile | 3 +- drivers/i2c/busses/i2c-keywest.c | 754 ------------------------------ drivers/i2c/busses/i2c-keywest.h | 108 ----- drivers/i2c/busses/i2c-pmac-smu.c | 324 ------------- drivers/i2c/busses/i2c-powermac.c | 290 ++++++++++++ drivers/macintosh/Kconfig | 10 +- drivers/macintosh/smu.c | 26 +- drivers/macintosh/windfarm_lm75_sensor.c | 50 +- include/asm-powerpc/pmac_low_i2c.h | 2 + 12 files changed, 563 insertions(+), 1364 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-keywest.c delete mode 100644 drivers/i2c/busses/i2c-keywest.h delete mode 100644 drivers/i2c/busses/i2c-pmac-smu.c create mode 100644 drivers/i2c/busses/i2c-powermac.c diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index f31d6a678b9e..a25e447f907f 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -39,6 +39,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -63,6 +67,9 @@ #define DBG_LOW(x...) #endif + +static int pmac_i2c_force_poll = 1; + /* * A bus structure. Each bus in the system has such a structure associated. */ @@ -80,6 +87,7 @@ struct pmac_i2c_bus struct semaphore sem; int opened; int polled; /* open mode */ + struct platform_device *platform_dev; /* ops */ int (*open)(struct pmac_i2c_bus *bus); @@ -101,6 +109,16 @@ struct pmac_i2c_host_kw void __iomem *base; /* register base address */ int bsteps; /* register stepping */ int speed; /* speed */ + int irq; + u8 *data; + unsigned len; + int state; + int rw; + int polled; + int result; + struct completion complete; + spinlock_t lock; + struct timer_list timeout_timer; }; /* Register indices */ @@ -115,6 +133,8 @@ typedef enum { reg_data } reg_t; +/* The Tumbler audio equalizer can be really slow sometimes */ +#define KW_POLL_TIMEOUT (2*HZ) /* Mode register */ #define KW_I2C_MODE_100KHZ 0x00 @@ -158,8 +178,9 @@ enum { }; #define WRONG_STATE(name) do {\ - printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ - name, __kw_state_names[state], isr); \ + printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \ + "(isr: %02x)\n", \ + name, __kw_state_names[host->state], isr); \ } while(0) static const char *__kw_state_names[] = { @@ -171,23 +192,22 @@ static const char *__kw_state_names[] = { "state_dead" }; -static inline u8 __kw_read_reg(struct pmac_i2c_bus *bus, reg_t reg) +static inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg) { - struct pmac_i2c_host_kw *host = bus->hostdata; return readb(host->base + (((unsigned int)reg) << host->bsteps)); } -static inline void __kw_write_reg(struct pmac_i2c_bus *bus, reg_t reg, u8 val) +static inline void __kw_write_reg(struct pmac_i2c_host_kw *host, + reg_t reg, u8 val) { - struct pmac_i2c_host_kw *host = bus->hostdata; writeb(val, host->base + (((unsigned)reg) << host->bsteps)); - (void)__kw_read_reg(bus, reg_subaddr); + (void)__kw_read_reg(host, reg_subaddr); } -#define kw_write_reg(reg, val) __kw_write_reg(bus, reg, val) -#define kw_read_reg(reg) __kw_read_reg(bus, reg) +#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) +#define kw_read_reg(reg) __kw_read_reg(host, reg) -static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) +static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host) { int i, j; u8 isr; @@ -201,8 +221,8 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) * on udelay nor schedule when in polled mode ! * For now, just use a bogus loop.... */ - if (bus->polled) { - for (j = 1; j < 1000000; j++) + if (host->polled) { + for (j = 1; j < 100000; j++) mb(); } else msleep(1); @@ -210,86 +230,99 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) return isr; } -static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw, - int *rc, u8 **data, int *len, u8 isr) +static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr) { u8 ack; DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n", - __kw_state_names[state], isr); + __kw_state_names[host->state], isr); + + if (host->state == state_idle) { + printk(KERN_WARNING "low_i2c: Keywest got an out of state" + " interrupt, ignoring\n"); + kw_write_reg(reg_isr, isr); + return; + } if (isr == 0) { - if (state != state_stop) { + if (host->state != state_stop) { DBG_LOW("KW: Timeout !\n"); - *rc = -EIO; + host->result = -EIO; goto stop; } - if (state == state_stop) { + if (host->state == state_stop) { ack = kw_read_reg(reg_status); - if (!(ack & KW_I2C_STAT_BUSY)) { - state = state_idle; - kw_write_reg(reg_ier, 0x00); - } + if (ack & KW_I2C_STAT_BUSY) + kw_write_reg(reg_status, 0); + host->state = state_idle; + kw_write_reg(reg_ier, 0x00); + if (!host->polled) + complete(&host->complete); } - return state; + return; } if (isr & KW_I2C_IRQ_ADDR) { ack = kw_read_reg(reg_status); - if (state != state_addr) { + if (host->state != state_addr) { kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); WRONG_STATE("KW_I2C_IRQ_ADDR"); - *rc = -EIO; + host->result = -EIO; goto stop; } if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - *rc = -ENODEV; + host->result = -ENODEV; DBG_LOW("KW: NAK on address\n"); - return state_stop; + host->state = state_stop; + return; } else { - if (rw) { - state = state_read; - if (*len > 1) + if (host->len == 0) { + kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); + goto stop; + } + if (host->rw) { + host->state = state_read; + if (host->len > 1) kw_write_reg(reg_control, KW_I2C_CTL_AAK); } else { - state = state_write; - kw_write_reg(reg_data, **data); - (*data)++; (*len)--; + host->state = state_write; + kw_write_reg(reg_data, *(host->data++)); + host->len--; } } kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); } if (isr & KW_I2C_IRQ_DATA) { - if (state == state_read) { - **data = kw_read_reg(reg_data); - (*data)++; (*len)--; + if (host->state == state_read) { + *(host->data++) = kw_read_reg(reg_data); + host->len--; kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - if ((*len) == 0) - state = state_stop; - else if ((*len) == 1) + if (host->len == 0) + host->state = state_stop; + else if (host->len == 1) kw_write_reg(reg_control, 0); - } else if (state == state_write) { + } else if (host->state == state_write) { ack = kw_read_reg(reg_status); if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { DBG_LOW("KW: nack on data write\n"); - *rc = -EIO; + host->result = -EIO; goto stop; - } else if (*len) { - kw_write_reg(reg_data, **data); - (*data)++; (*len)--; + } else if (host->len) { + kw_write_reg(reg_data, *(host->data++)); + host->len--; } else { kw_write_reg(reg_control, KW_I2C_CTL_STOP); - state = state_stop; - *rc = 0; + host->state = state_stop; + host->result = 0; } kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); } else { kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); WRONG_STATE("KW_I2C_IRQ_DATA"); - if (state != state_stop) { - *rc = -EIO; + if (host->state != state_stop) { + host->result = -EIO; goto stop; } } @@ -297,21 +330,54 @@ static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw, if (isr & KW_I2C_IRQ_STOP) { kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); - if (state != state_stop) { + if (host->state != state_stop) { WRONG_STATE("KW_I2C_IRQ_STOP"); - *rc = -EIO; + host->result = -EIO; } - return state_idle; + host->state = state_idle; + if (!host->polled) + complete(&host->complete); } if (isr & KW_I2C_IRQ_START) kw_write_reg(reg_isr, KW_I2C_IRQ_START); - return state; - + return; stop: kw_write_reg(reg_control, KW_I2C_CTL_STOP); - return state_stop; + host->state = state_stop; + return; +} + +/* Interrupt handler */ +static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pmac_i2c_host_kw *host = dev_id; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + del_timer(&host->timeout_timer); + kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr)); + if (host->state != state_idle) { + host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; + add_timer(&host->timeout_timer); + } + spin_unlock_irqrestore(&host->lock, flags); + return IRQ_HANDLED; +} + +static void kw_i2c_timeout(unsigned long data) +{ + struct pmac_i2c_host_kw *host = (struct pmac_i2c_host_kw *)data; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr)); + if (host->state != state_idle) { + host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; + add_timer(&host->timeout_timer); + } + spin_unlock_irqrestore(&host->lock, flags); } static int kw_i2c_open(struct pmac_i2c_bus *bus) @@ -332,8 +398,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, { struct pmac_i2c_host_kw *host = bus->hostdata; u8 mode_reg = host->speed; - int state = state_addr; - int rc = 0; + int use_irq = host->irq != NO_IRQ && !bus->polled; /* Setup mode & subaddress if any */ switch(bus->mode) { @@ -371,18 +436,50 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) kw_write_reg(reg_subaddr, subaddr); - /* Start sending address & disable interrupt*/ - kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); + /* Prepare for async operations */ + host->data = data; + host->len = len; + host->state = state_addr; + host->result = 0; + host->rw = (addrdir & 1); + host->polled = bus->polled; + + /* Enable interrupt if not using polled mode and interrupt is + * available + */ + if (use_irq) { + /* Clear completion */ + INIT_COMPLETION(host->complete); + /* Ack stale interrupts */ + kw_write_reg(reg_isr, kw_read_reg(reg_isr)); + /* Arm timeout */ + host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; + add_timer(&host->timeout_timer); + /* Enable emission */ + kw_write_reg(reg_ier, KW_I2C_IRQ_MASK); + } + + /* Start sending address */ kw_write_reg(reg_control, KW_I2C_CTL_XADDR); - /* State machine, to turn into an interrupt handler in the future */ - while(state != state_idle) { - u8 isr = kw_i2c_wait_interrupt(bus); - state = kw_i2c_handle_interrupt(bus, state, addrdir & 1, &rc, - &data, &len, isr); + /* Wait for completion */ + if (use_irq) + wait_for_completion(&host->complete); + else { + while(host->state != state_idle) { + unsigned long flags; + + u8 isr = kw_i2c_wait_interrupt(host); + spin_lock_irqsave(&host->lock, flags); + kw_i2c_handle_interrupt(host, isr); + spin_unlock_irqrestore(&host->lock, flags); + } } - return rc; + /* Disable emission */ + kw_write_reg(reg_ier, 0); + + return host->result; } static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) @@ -409,6 +506,12 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) return NULL; } init_MUTEX(&host->mutex); + init_completion(&host->complete); + spin_lock_init(&host->lock); + init_timer(&host->timeout_timer); + host->timeout_timer.function = kw_i2c_timeout; + host->timeout_timer.data = (unsigned long)host; + psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); steps = psteps ? (*psteps) : 0x10; for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) @@ -427,9 +530,28 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) host->speed = KW_I2C_MODE_25KHZ; break; } + if (np->n_intrs > 0) + host->irq = np->intrs[0].line; + else + host->irq = NO_IRQ; - printk(KERN_INFO "KeyWest i2c @0x%08x %s\n", *addrp, np->full_name); host->base = ioremap((*addrp), 0x1000); + if (host->base == NULL) { + printk(KERN_ERR "low_i2c: Can't map registers for %s\n", + np->full_name); + kfree(host); + return NULL; + } + + /* Make sure IRA is disabled */ + kw_write_reg(reg_ier, 0); + + /* Request chip interrupt */ + if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host)) + host->irq = NO_IRQ; + + printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n", + *addrp, host->irq, np->full_name); return host; } @@ -591,7 +713,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, req->nbytes = sizeof(struct pmu_i2c_hdr) + 1; req->done = pmu_i2c_complete; req->arg = ∁ - if (!read) { + if (!read && len) { memcpy(hdr->data, data, len); req->nbytes += len; } @@ -637,7 +759,8 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, " bytes, expected %d !\n", rlen, len); return -EIO; } - memcpy(data, &req->reply[1], len); + if (len) + memcpy(data, &req->reply[1], len); return 0; } } @@ -713,6 +836,10 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, int read = addrdir & 1; int rc = 0; + if ((read && len > SMU_I2C_READ_MAX) || + ((!read) && len > SMU_I2C_WRITE_MAX)) + return -EINVAL; + memset(cmd, 0, sizeof(struct smu_i2c_cmd)); cmd->info.bus = bus->channel; cmd->info.devaddr = addrdir; @@ -740,7 +867,7 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, default: return -EINVAL; } - if (!read) + if (!read && len) memcpy(cmd->info.data, data, len); init_completion(&comp); @@ -752,7 +879,7 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, wait_for_completion(&comp); rc = cmd->status; - if (read) + if (read && len) memcpy(data, cmd->info.data, len); return rc < 0 ? rc : 0; } @@ -767,7 +894,7 @@ static void __init smu_i2c_probe(void) if (!smu_present()) return; - controller = of_find_node_by_name(NULL, "smu_i2c_control"); + controller = of_find_node_by_name(NULL, "smu-i2c-control"); if (controller == NULL) controller = of_find_node_by_name(NULL, "smu"); if (controller == NULL) @@ -884,6 +1011,13 @@ int pmac_i2c_get_flags(struct pmac_i2c_bus *bus) } EXPORT_SYMBOL_GPL(pmac_i2c_get_flags); +int pmac_i2c_get_channel(struct pmac_i2c_bus *bus) +{ + return bus->channel; +} +EXPORT_SYMBOL_GPL(pmac_i2c_get_channel); + + void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, struct i2c_adapter *adapter) { @@ -906,6 +1040,17 @@ struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus) } EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter); +struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter) +{ + struct pmac_i2c_bus *bus; + + list_for_each_entry(bus, &pmac_i2c_busses, link) + if (bus->adapter == adapter) + return bus; + return NULL; +} +EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus); + extern int pmac_i2c_match_adapter(struct device_node *dev, struct i2c_adapter *adapter) { @@ -956,7 +1101,7 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) int rc; down(&bus->sem); - bus->polled = polled; + bus->polled = polled || pmac_i2c_force_poll; bus->opened = 1; bus->mode = pmac_i2c_mode_std; if (bus->open && (rc = bus->open(bus)) != 0) { @@ -1034,14 +1179,43 @@ int __init pmac_i2c_init(void) kw_i2c_probe(); #ifdef CONFIG_ADB_PMU + /* Probe PMU i2c busses */ pmu_i2c_probe(); #endif #ifdef CONFIG_PMAC_SMU + /* Probe SMU i2c busses */ smu_i2c_probe(); #endif - return 0; } arch_initcall(pmac_i2c_init); +/* Since pmac_i2c_init can be called too early for the platform device + * registration, we need to do it at a later time. In our case, subsys + * happens to fit well, though I agree it's a bit of a hack... + */ +static int __init pmac_i2c_create_platform_devices(void) +{ + struct pmac_i2c_bus *bus; + int i = 0; + + /* In the case where we are initialized from smp_init(), we must + * not use the timer (and thus the irq). It's safe from now on + * though + */ + pmac_i2c_force_poll = 0; + + /* Create platform devices */ + list_for_each_entry(bus, &pmac_i2c_busses, link) { + bus->platform_dev = + platform_device_alloc("i2c-powermac", i++); + if (bus->platform_dev == NULL) + return -ENOMEM; + bus->platform_dev->dev.platform_data = bus; + platform_device_add(bus->platform_dev); + } + + return 0; +} +subsys_initcall(pmac_i2c_create_platform_devices); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index dc5cdc1484e8..3b1a9d4fcbc6 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -650,7 +650,7 @@ static int pmac_check_legacy_ioport(unsigned int baseport) static int __init pmac_declare_of_platform_devices(void) { - struct device_node *np, *npp; + struct device_node *np; np = of_find_node_by_name(NULL, "valkyrie"); if (np) @@ -658,22 +658,6 @@ static int __init pmac_declare_of_platform_devices(void) np = of_find_node_by_name(NULL, "platinum"); if (np) of_platform_device_create(np, "platinum", NULL); - npp = of_find_node_by_name(NULL, "uni-n"); - if (npp == NULL) - npp = of_find_node_by_name(NULL, "u3"); - if (npp == NULL) - npp = of_find_node_by_name(NULL, "u4"); - if (npp) { - for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { - if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "uni-n-i2c", - NULL); - of_node_put(np); - break; - } - } - of_node_put(npp); - } np = of_find_node_by_type(NULL, "smu"); if (np) { of_platform_device_create(np, "smu", NULL); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4010fe92e72b..08d5b8fed2dc 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -236,27 +236,17 @@ config I2C_IXP2000 This support is also available as a module. If so, the module will be called i2c-ixp2000. -config I2C_KEYWEST - tristate "Powermac Keywest I2C interface" +config I2C_POWERMAC + tristate "Powermac I2C interface" depends on I2C && PPC_PMAC + default y help - This supports the use of the I2C interface in the combo-I/O - chip on recent Apple machines. Say Y if you have such a machine. - - This support is also available as a module. If so, the module - will be called i2c-keywest. - -config I2C_PMAC_SMU - tristate "Powermac SMU I2C interface" - depends on I2C && PMAC_SMU - help - This supports the use of the I2C interface in the SMU - chip on recent Apple machines like the iMac G5. It is used - among others by the thermal control driver for those machines. - Say Y if you have such a machine. + This exposes the various PowerMac i2c interfaces to the linux i2c + layer and to userland. It is used by various drivers on the powemac + platform, thus should generally be enabled. This support is also available as a module. If so, the module - will be called i2c-pmac-smu. + will be called i2c-powermac. config I2C_MPC tristate "MPC107/824x/85xx/52xx" diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index f1df00f66c6c..b44831dff683 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -19,8 +19,7 @@ obj-$(CONFIG_I2C_ISA) += i2c-isa.o obj-$(CONFIG_I2C_ITE) += i2c-ite.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o -obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o -obj-$(CONFIG_I2C_PMAC_SMU) += i2c-pmac-smu.o +obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c deleted file mode 100644 index 93e7080e3bc5..000000000000 --- a/drivers/i2c/busses/i2c-keywest.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - i2c Support for Apple Keywest I2C Bus Controller - - Copyright (c) 2001 Benjamin Herrenschmidt - - Original work by - - Copyright (c) 2000 Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Changes: - - 2001/12/13 BenH New implementation - 2001/12/15 BenH Add support for "byte" and "quick" - transfers. Add i2c_xfer routine. - 2003/09/21 BenH Rework state machine with Paulus help - 2004/01/21 BenH Merge in Greg KH changes, polled mode is back - 2004/02/05 BenH Merge 64 bits fixes from the g5 ppc64 tree - - My understanding of the various modes supported by keywest are: - - - Dumb mode : not implemented, probably direct tweaking of lines - - Standard mode : simple i2c transaction of type - S Addr R/W A Data A Data ... T - - Standard sub mode : combined 8 bit subaddr write with data read - S Addr R/W A SubAddr A Data A Data ... T - - Combined mode : Subaddress and Data sequences appended with no stop - S Addr R/W A SubAddr S Addr R/W A Data A Data ... T - - Currently, this driver uses only Standard mode for i2c xfer, and - smbus byte & quick transfers ; and uses StandardSub mode for - other smbus transfers instead of combined as we need that for the - sound driver to be happy -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "i2c-keywest.h" - -#undef POLLED_MODE - -/* Some debug macros */ -#define WRONG_STATE(name) do {\ - pr_debug("KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ - name, __kw_state_names[iface->state], isr); \ - } while(0) - -#ifdef DEBUG -static const char *__kw_state_names[] = { - "state_idle", - "state_addr", - "state_read", - "state_write", - "state_stop", - "state_dead" -}; -#endif /* DEBUG */ - -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("I2C driver for Apple's Keywest"); -MODULE_LICENSE("GPL"); - -#ifdef POLLED_MODE -/* Don't schedule, the g5 fan controller is too - * timing sensitive - */ -static u8 -wait_interrupt(struct keywest_iface* iface) -{ - int i; - u8 isr; - - for (i = 0; i < 200000; i++) { - isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK; - if (isr != 0) - return isr; - udelay(10); - } - return isr; -} -#endif /* POLLED_MODE */ - -static void -do_stop(struct keywest_iface* iface, int result) -{ - write_reg(reg_control, KW_I2C_CTL_STOP); - iface->state = state_stop; - iface->result = result; -} - -/* Main state machine for standard & standard sub mode */ -static void -handle_interrupt(struct keywest_iface *iface, u8 isr) -{ - int ack; - - if (isr == 0) { - if (iface->state != state_stop) { - pr_debug("KW: Timeout !\n"); - do_stop(iface, -EIO); - } - if (iface->state == state_stop) { - ack = read_reg(reg_status); - if (!(ack & KW_I2C_STAT_BUSY)) { - iface->state = state_idle; - write_reg(reg_ier, 0x00); -#ifndef POLLED_MODE - complete(&iface->complete); -#endif /* POLLED_MODE */ - } - } - return; - } - - if (isr & KW_I2C_IRQ_ADDR) { - ack = read_reg(reg_status); - if (iface->state != state_addr) { - write_reg(reg_isr, KW_I2C_IRQ_ADDR); - WRONG_STATE("KW_I2C_IRQ_ADDR"); - do_stop(iface, -EIO); - return; - } - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - iface->state = state_stop; - iface->result = -ENODEV; - pr_debug("KW: NAK on address\n"); - } else { - /* Handle rw "quick" mode */ - if (iface->datalen == 0) { - do_stop(iface, 0); - } else if (iface->read_write == I2C_SMBUS_READ) { - iface->state = state_read; - if (iface->datalen > 1) - write_reg(reg_control, KW_I2C_CTL_AAK); - } else { - iface->state = state_write; - write_reg(reg_data, *(iface->data++)); - iface->datalen--; - } - } - write_reg(reg_isr, KW_I2C_IRQ_ADDR); - } - - if (isr & KW_I2C_IRQ_DATA) { - if (iface->state == state_read) { - *(iface->data++) = read_reg(reg_data); - write_reg(reg_isr, KW_I2C_IRQ_DATA); - iface->datalen--; - if (iface->datalen == 0) - iface->state = state_stop; - else if (iface->datalen == 1) - write_reg(reg_control, 0); - } else if (iface->state == state_write) { - /* Check ack status */ - ack = read_reg(reg_status); - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - pr_debug("KW: nack on data write (%x): %x\n", - iface->data[-1], ack); - do_stop(iface, -EIO); - } else if (iface->datalen) { - write_reg(reg_data, *(iface->data++)); - iface->datalen--; - } else { - write_reg(reg_control, KW_I2C_CTL_STOP); - iface->state = state_stop; - iface->result = 0; - } - write_reg(reg_isr, KW_I2C_IRQ_DATA); - } else { - write_reg(reg_isr, KW_I2C_IRQ_DATA); - WRONG_STATE("KW_I2C_IRQ_DATA"); - if (iface->state != state_stop) - do_stop(iface, -EIO); - } - } - - if (isr & KW_I2C_IRQ_STOP) { - write_reg(reg_isr, KW_I2C_IRQ_STOP); - if (iface->state != state_stop) { - WRONG_STATE("KW_I2C_IRQ_STOP"); - iface->result = -EIO; - } - iface->state = state_idle; - write_reg(reg_ier, 0x00); -#ifndef POLLED_MODE - complete(&iface->complete); -#endif /* POLLED_MODE */ - } - - if (isr & KW_I2C_IRQ_START) - write_reg(reg_isr, KW_I2C_IRQ_START); -} - -#ifndef POLLED_MODE - -/* Interrupt handler */ -static irqreturn_t -keywest_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - struct keywest_iface *iface = (struct keywest_iface *)dev_id; - unsigned long flags; - - spin_lock_irqsave(&iface->lock, flags); - del_timer(&iface->timeout_timer); - handle_interrupt(iface, read_reg(reg_isr)); - if (iface->state != state_idle) { - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - } - spin_unlock_irqrestore(&iface->lock, flags); - return IRQ_HANDLED; -} - -static void -keywest_timeout(unsigned long data) -{ - struct keywest_iface *iface = (struct keywest_iface *)data; - unsigned long flags; - - pr_debug("timeout !\n"); - spin_lock_irqsave(&iface->lock, flags); - handle_interrupt(iface, read_reg(reg_isr)); - if (iface->state != state_idle) { - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); - } - spin_unlock_irqrestore(&iface->lock, flags); -} - -#endif /* POLLED_MODE */ - -/* - * SMBUS-type transfer entrypoint - */ -static s32 -keywest_smbus_xfer( struct i2c_adapter* adap, - u16 addr, - unsigned short flags, - char read_write, - u8 command, - int size, - union i2c_smbus_data* data) -{ - struct keywest_chan* chan = i2c_get_adapdata(adap); - struct keywest_iface* iface = chan->iface; - int len; - u8* buffer; - u16 cur_word; - int rc = 0; - - if (iface->state == state_dead) - return -ENXIO; - - /* Prepare datas & select mode */ - iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; - switch (size) { - case I2C_SMBUS_QUICK: - len = 0; - buffer = NULL; - iface->cur_mode |= KW_I2C_MODE_STANDARD; - break; - case I2C_SMBUS_BYTE: - len = 1; - buffer = &data->byte; - iface->cur_mode |= KW_I2C_MODE_STANDARD; - break; - case I2C_SMBUS_BYTE_DATA: - len = 1; - buffer = &data->byte; - iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; - break; - case I2C_SMBUS_WORD_DATA: - len = 2; - cur_word = cpu_to_le16(data->word); - buffer = (u8 *)&cur_word; - iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; - break; - case I2C_SMBUS_BLOCK_DATA: - len = data->block[0]; - buffer = &data->block[1]; - iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; - break; - default: - return -1; - } - - /* Turn a standardsub read into a combined mode access */ - if (read_write == I2C_SMBUS_READ - && (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB) { - iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; - iface->cur_mode |= KW_I2C_MODE_COMBINED; - } - - /* Original driver had this limitation */ - if (len > 32) - len = 32; - - if (pmac_low_i2c_lock(iface->node)) - return -ENXIO; - - pr_debug("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n", - chan->chan_no, addr, len, read_write == I2C_SMBUS_READ); - - iface->data = buffer; - iface->datalen = len; - iface->state = state_addr; - iface->result = 0; - iface->read_write = read_write; - - /* Setup channel & clear pending irqs */ - write_reg(reg_isr, read_reg(reg_isr)); - write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); - write_reg(reg_status, 0); - - /* Set up address and r/w bit */ - write_reg(reg_addr, - (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); - - /* Set up the sub address */ - if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB - || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) - write_reg(reg_subaddr, command); - -#ifndef POLLED_MODE - /* Arm timeout */ - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); -#endif - - /* Start sending address & enable interrupt*/ - write_reg(reg_control, KW_I2C_CTL_XADDR); - write_reg(reg_ier, KW_I2C_IRQ_MASK); - -#ifdef POLLED_MODE - pr_debug("using polled mode...\n"); - /* State machine, to turn into an interrupt handler */ - while(iface->state != state_idle) { - unsigned long flags; - - u8 isr = wait_interrupt(iface); - spin_lock_irqsave(&iface->lock, flags); - handle_interrupt(iface, isr); - spin_unlock_irqrestore(&iface->lock, flags); - } -#else /* POLLED_MODE */ - pr_debug("using interrupt mode...\n"); - wait_for_completion(&iface->complete); -#endif /* POLLED_MODE */ - - rc = iface->result; - pr_debug("transfer done, result: %d\n", rc); - - if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ) - data->word = le16_to_cpu(cur_word); - - /* Release sem */ - pmac_low_i2c_unlock(iface->node); - - return rc; -} - -/* - * Generic i2c master transfer entrypoint - */ -static int -keywest_xfer( struct i2c_adapter *adap, - struct i2c_msg *msgs, - int num) -{ - struct keywest_chan* chan = i2c_get_adapdata(adap); - struct keywest_iface* iface = chan->iface; - struct i2c_msg *pmsg; - int i, completed; - int rc = 0; - - if (iface->state == state_dead) - return -ENXIO; - - if (pmac_low_i2c_lock(iface->node)) - return -ENXIO; - - /* Set adapter to standard mode */ - iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; - iface->cur_mode |= KW_I2C_MODE_STANDARD; - - completed = 0; - for (i = 0; rc >= 0 && i < num;) { - u8 addr; - - pmsg = &msgs[i++]; - addr = pmsg->addr; - if (pmsg->flags & I2C_M_TEN) { - printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n"); - rc = -EINVAL; - break; - } - pr_debug("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n", - chan->chan_no, - pmsg->flags & I2C_M_RD ? "read" : "write", - pmsg->len, addr, i, num); - - /* Setup channel & clear pending irqs */ - write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); - write_reg(reg_isr, read_reg(reg_isr)); - write_reg(reg_status, 0); - - iface->data = pmsg->buf; - iface->datalen = pmsg->len; - iface->state = state_addr; - iface->result = 0; - if (pmsg->flags & I2C_M_RD) - iface->read_write = I2C_SMBUS_READ; - else - iface->read_write = I2C_SMBUS_WRITE; - - /* Set up address and r/w bit */ - if (pmsg->flags & I2C_M_REV_DIR_ADDR) - addr ^= 1; - write_reg(reg_addr, - (addr << 1) | - ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00)); - -#ifndef POLLED_MODE - /* Arm timeout */ - iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; - add_timer(&iface->timeout_timer); -#endif - - /* Start sending address & enable interrupt*/ - write_reg(reg_ier, KW_I2C_IRQ_MASK); - write_reg(reg_control, KW_I2C_CTL_XADDR); - -#ifdef POLLED_MODE - pr_debug("using polled mode...\n"); - /* State machine, to turn into an interrupt handler */ - while(iface->state != state_idle) { - u8 isr = wait_interrupt(iface); - handle_interrupt(iface, isr); - } -#else /* POLLED_MODE */ - pr_debug("using interrupt mode...\n"); - wait_for_completion(&iface->complete); -#endif /* POLLED_MODE */ - - rc = iface->result; - if (rc == 0) - completed++; - pr_debug("transfer done, result: %d\n", rc); - } - - /* Release sem */ - pmac_low_i2c_unlock(iface->node); - - return completed; -} - -static u32 -keywest_func(struct i2c_adapter * adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -/* For now, we only handle combined mode (smbus) */ -static struct i2c_algorithm keywest_algorithm = { - .smbus_xfer = keywest_smbus_xfer, - .master_xfer = keywest_xfer, - .functionality = keywest_func, -}; - - -static int -create_iface(struct device_node *np, struct device *dev) -{ - unsigned long steps; - unsigned bsteps, tsize, i, nchan; - struct keywest_iface* iface; - u32 *psteps, *prate, *addrp; - int rc; - - if (np->n_intrs < 1) { - printk(KERN_ERR "%s: Missing interrupt !\n", - np->full_name); - return -ENODEV; - } - addrp = (u32 *)get_property(np, "AAPL,address", NULL); - if (addrp == NULL) { - printk(KERN_ERR "%s: Can't find address !\n", - np->full_name); - return -ENODEV; - } - - if (pmac_low_i2c_lock(np)) - return -ENODEV; - - psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); - steps = psteps ? (*psteps) : 0x10; - - /* Hrm... maybe we can be smarter here */ - for (bsteps = 0; (steps & 0x01) == 0; bsteps++) - steps >>= 1; - - if (np->parent->name[0] == 'u') - nchan = 2; - else - nchan = 1; - - tsize = sizeof(struct keywest_iface) + - (sizeof(struct keywest_chan) + 4) * nchan; - iface = kzalloc(tsize, GFP_KERNEL); - if (iface == NULL) { - printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); - pmac_low_i2c_unlock(np); - return -ENOMEM; - } - spin_lock_init(&iface->lock); - init_completion(&iface->complete); - iface->node = of_node_get(np); - iface->bsteps = bsteps; - iface->chan_count = nchan; - iface->state = state_idle; - iface->irq = np->intrs[0].line; - iface->channels = (struct keywest_chan *) - (((unsigned long)(iface + 1) + 3UL) & ~3UL); - iface->base = ioremap(*addrp, 0x1000); - if (!iface->base) { - printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); - kfree(iface); - pmac_low_i2c_unlock(np); - return -ENOMEM; - } - -#ifndef POLLED_MODE - init_timer(&iface->timeout_timer); - iface->timeout_timer.function = keywest_timeout; - iface->timeout_timer.data = (unsigned long)iface; -#endif - - /* Select interface rate */ - iface->cur_mode = KW_I2C_MODE_100KHZ; - prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); - if (prate) switch(*prate) { - case 100: - iface->cur_mode = KW_I2C_MODE_100KHZ; - break; - case 50: - iface->cur_mode = KW_I2C_MODE_50KHZ; - break; - case 25: - iface->cur_mode = KW_I2C_MODE_25KHZ; - break; - default: - printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n", - (long)*prate); - } - - /* Select standard mode by default */ - iface->cur_mode |= KW_I2C_MODE_STANDARD; - - /* Write mode */ - write_reg(reg_mode, iface->cur_mode); - - /* Switch interrupts off & clear them*/ - write_reg(reg_ier, 0x00); - write_reg(reg_isr, KW_I2C_IRQ_MASK); - -#ifndef POLLED_MODE - /* Request chip interrupt */ - rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface); - if (rc) { - printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); - iounmap(iface->base); - kfree(iface); - pmac_low_i2c_unlock(np); - return -ENODEV; - } -#endif /* POLLED_MODE */ - - pmac_low_i2c_unlock(np); - dev_set_drvdata(dev, iface); - - for (i=0; ichannels[i]; - - sprintf(chan->adapter.name, "%s %d", np->parent->name, i); - chan->iface = iface; - chan->chan_no = i; - chan->adapter.algo = &keywest_algorithm; - chan->adapter.algo_data = NULL; - chan->adapter.client_register = NULL; - chan->adapter.client_unregister = NULL; - i2c_set_adapdata(&chan->adapter, chan); - chan->adapter.dev.parent = dev; - - rc = i2c_add_adapter(&chan->adapter); - if (rc) { - printk("i2c-keywest.c: Adapter %s registration failed\n", - chan->adapter.name); - i2c_set_adapdata(&chan->adapter, NULL); - } - } - - printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", - np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps); - - return 0; -} - -static int -dispose_iface(struct device *dev) -{ - struct keywest_iface *iface = dev_get_drvdata(dev); - int i, rc; - - /* Make sure we stop all activity */ - if (pmac_low_i2c_lock(iface->node)) - return -ENODEV; - -#ifndef POLLED_MODE - spin_lock_irq(&iface->lock); - while (iface->state != state_idle) { - spin_unlock_irq(&iface->lock); - msleep(100); - spin_lock_irq(&iface->lock); - } -#endif /* POLLED_MODE */ - iface->state = state_dead; -#ifndef POLLED_MODE - spin_unlock_irq(&iface->lock); - free_irq(iface->irq, iface); -#endif /* POLLED_MODE */ - - pmac_low_i2c_unlock(iface->node); - - /* Release all channels */ - for (i=0; ichan_count; i++) { - struct keywest_chan* chan = &iface->channels[i]; - if (i2c_get_adapdata(&chan->adapter) == NULL) - continue; - rc = i2c_del_adapter(&chan->adapter); - i2c_set_adapdata(&chan->adapter, NULL); - /* We aren't that prepared to deal with this... */ - if (rc) - printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n"); - } - iounmap(iface->base); - dev_set_drvdata(dev, NULL); - of_node_put(iface->node); - kfree(iface); - - return 0; -} - -static int -create_iface_macio(struct macio_dev* dev, const struct of_device_id *match) -{ - return create_iface(dev->ofdev.node, &dev->ofdev.dev); -} - -static int -dispose_iface_macio(struct macio_dev* dev) -{ - return dispose_iface(&dev->ofdev.dev); -} - -static int -create_iface_of_platform(struct of_device* dev, const struct of_device_id *match) -{ - return create_iface(dev->node, &dev->dev); -} - -static int -dispose_iface_of_platform(struct of_device* dev) -{ - return dispose_iface(&dev->dev); -} - -static struct of_device_id i2c_keywest_match[] = -{ - { - .type = "i2c", - .compatible = "keywest" - }, - {}, -}; - -static struct macio_driver i2c_keywest_macio_driver = -{ - .owner = THIS_MODULE, - .name = "i2c-keywest", - .match_table = i2c_keywest_match, - .probe = create_iface_macio, - .remove = dispose_iface_macio -}; - -static struct of_platform_driver i2c_keywest_of_platform_driver = -{ - .owner = THIS_MODULE, - .name = "i2c-keywest", - .match_table = i2c_keywest_match, - .probe = create_iface_of_platform, - .remove = dispose_iface_of_platform -}; - -static int __init -i2c_keywest_init(void) -{ - of_register_driver(&i2c_keywest_of_platform_driver); - macio_register_driver(&i2c_keywest_macio_driver); - - return 0; -} - -static void __exit -i2c_keywest_cleanup(void) -{ - of_unregister_driver(&i2c_keywest_of_platform_driver); - macio_unregister_driver(&i2c_keywest_macio_driver); -} - -module_init(i2c_keywest_init); -module_exit(i2c_keywest_cleanup); diff --git a/drivers/i2c/busses/i2c-keywest.h b/drivers/i2c/busses/i2c-keywest.h deleted file mode 100644 index c5022e1ca6ff..000000000000 --- a/drivers/i2c/busses/i2c-keywest.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef __I2C_KEYWEST_H__ -#define __I2C_KEYWEST_H__ - -/* The Tumbler audio equalizer can be really slow sometimes */ -#define POLL_TIMEOUT (2*HZ) - -/* Register indices */ -typedef enum { - reg_mode = 0, - reg_control, - reg_status, - reg_isr, - reg_ier, - reg_addr, - reg_subaddr, - reg_data -} reg_t; - - -/* Mode register */ -#define KW_I2C_MODE_100KHZ 0x00 -#define KW_I2C_MODE_50KHZ 0x01 -#define KW_I2C_MODE_25KHZ 0x02 -#define KW_I2C_MODE_DUMB 0x00 -#define KW_I2C_MODE_STANDARD 0x04 -#define KW_I2C_MODE_STANDARDSUB 0x08 -#define KW_I2C_MODE_COMBINED 0x0C -#define KW_I2C_MODE_MODE_MASK 0x0C -#define KW_I2C_MODE_CHAN_MASK 0xF0 - -/* Control register */ -#define KW_I2C_CTL_AAK 0x01 -#define KW_I2C_CTL_XADDR 0x02 -#define KW_I2C_CTL_STOP 0x04 -#define KW_I2C_CTL_START 0x08 - -/* Status register */ -#define KW_I2C_STAT_BUSY 0x01 -#define KW_I2C_STAT_LAST_AAK 0x02 -#define KW_I2C_STAT_LAST_RW 0x04 -#define KW_I2C_STAT_SDA 0x08 -#define KW_I2C_STAT_SCL 0x10 - -/* IER & ISR registers */ -#define KW_I2C_IRQ_DATA 0x01 -#define KW_I2C_IRQ_ADDR 0x02 -#define KW_I2C_IRQ_STOP 0x04 -#define KW_I2C_IRQ_START 0x08 -#define KW_I2C_IRQ_MASK 0x0F - -/* Physical interface */ -struct keywest_iface -{ - struct device_node *node; - void __iomem * base; - unsigned bsteps; - int irq; - spinlock_t lock; - struct keywest_chan *channels; - unsigned chan_count; - u8 cur_mode; - char read_write; - u8 *data; - unsigned datalen; - int state; - int result; - struct timer_list timeout_timer; - struct completion complete; -}; - -enum { - state_idle, - state_addr, - state_read, - state_write, - state_stop, - state_dead -}; - -/* Channel on an interface */ -struct keywest_chan -{ - struct i2c_adapter adapter; - struct keywest_iface* iface; - unsigned chan_no; -}; - -/* Register access */ - -static inline u8 __read_reg(struct keywest_iface *iface, reg_t reg) -{ - return in_8(iface->base - + (((unsigned)reg) << iface->bsteps)); -} - -static inline void __write_reg(struct keywest_iface *iface, reg_t reg, u8 val) -{ - out_8(iface->base - + (((unsigned)reg) << iface->bsteps), val); - (void)__read_reg(iface, reg_subaddr); -} - -#define write_reg(reg, val) __write_reg(iface, reg, val) -#define read_reg(reg) __read_reg(iface, reg) - - - -#endif /* __I2C_KEYWEST_H__ */ diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c deleted file mode 100644 index 7d925be3fd4b..000000000000 --- a/drivers/i2c/busses/i2c-pmac-smu.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - i2c Support for Apple SMU Controller - - Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp. - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int probe; - -MODULE_AUTHOR("Benjamin Herrenschmidt "); -MODULE_DESCRIPTION("I2C driver for Apple's SMU"); -MODULE_LICENSE("GPL"); -module_param(probe, bool, 0); - - -/* Physical interface */ -struct smu_iface -{ - struct i2c_adapter adapter; - struct completion complete; - u32 busid; -}; - -static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc) -{ - struct smu_iface *iface = misc; - complete(&iface->complete); -} - -/* - * SMBUS-type transfer entrypoint - */ -static s32 smu_smbus_xfer( struct i2c_adapter* adap, - u16 addr, - unsigned short flags, - char read_write, - u8 command, - int size, - union i2c_smbus_data* data) -{ - struct smu_iface *iface = i2c_get_adapdata(adap); - struct smu_i2c_cmd cmd; - int rc = 0; - int read = (read_write == I2C_SMBUS_READ); - - cmd.info.bus = iface->busid; - cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00); - - /* Prepare datas & select mode */ - switch (size) { - case I2C_SMBUS_QUICK: - cmd.info.type = SMU_I2C_TRANSFER_SIMPLE; - cmd.info.datalen = 0; - break; - case I2C_SMBUS_BYTE: - cmd.info.type = SMU_I2C_TRANSFER_SIMPLE; - cmd.info.datalen = 1; - if (!read) - cmd.info.data[0] = data->byte; - break; - case I2C_SMBUS_BYTE_DATA: - cmd.info.type = SMU_I2C_TRANSFER_STDSUB; - cmd.info.datalen = 1; - cmd.info.sublen = 1; - cmd.info.subaddr[0] = command; - cmd.info.subaddr[1] = 0; - cmd.info.subaddr[2] = 0; - if (!read) - cmd.info.data[0] = data->byte; - break; - case I2C_SMBUS_WORD_DATA: - cmd.info.type = SMU_I2C_TRANSFER_STDSUB; - cmd.info.datalen = 2; - cmd.info.sublen = 1; - cmd.info.subaddr[0] = command; - cmd.info.subaddr[1] = 0; - cmd.info.subaddr[2] = 0; - if (!read) { - cmd.info.data[0] = data->word & 0xff; - cmd.info.data[1] = (data->word >> 8) & 0xff; - } - break; - /* Note that these are broken vs. the expected smbus API where - * on reads, the lenght is actually returned from the function, - * but I think the current API makes no sense and I don't want - * any driver that I haven't verified for correctness to go - * anywhere near a pmac i2c bus anyway ... - */ - case I2C_SMBUS_BLOCK_DATA: - cmd.info.type = SMU_I2C_TRANSFER_STDSUB; - cmd.info.datalen = data->block[0] + 1; - if (cmd.info.datalen > (SMU_I2C_WRITE_MAX + 1)) - return -EINVAL; - if (!read) - memcpy(cmd.info.data, data->block, cmd.info.datalen); - cmd.info.sublen = 1; - cmd.info.subaddr[0] = command; - cmd.info.subaddr[1] = 0; - cmd.info.subaddr[2] = 0; - break; - case I2C_SMBUS_I2C_BLOCK_DATA: - cmd.info.type = SMU_I2C_TRANSFER_STDSUB; - cmd.info.datalen = data->block[0]; - if (cmd.info.datalen > 7) - return -EINVAL; - if (!read) - memcpy(cmd.info.data, &data->block[1], - cmd.info.datalen); - cmd.info.sublen = 1; - cmd.info.subaddr[0] = command; - cmd.info.subaddr[1] = 0; - cmd.info.subaddr[2] = 0; - break; - - default: - return -EINVAL; - } - - /* Turn a standardsub read into a combined mode access */ - if (read_write == I2C_SMBUS_READ && - cmd.info.type == SMU_I2C_TRANSFER_STDSUB) - cmd.info.type = SMU_I2C_TRANSFER_COMBINED; - - /* Finish filling command and submit it */ - cmd.done = smu_i2c_done; - cmd.misc = iface; - rc = smu_queue_i2c(&cmd); - if (rc < 0) - return rc; - wait_for_completion(&iface->complete); - rc = cmd.status; - - if (!read || rc < 0) - return rc; - - switch (size) { - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - data->byte = cmd.info.data[0]; - break; - case I2C_SMBUS_WORD_DATA: - data->word = ((u16)cmd.info.data[1]) << 8; - data->word |= cmd.info.data[0]; - break; - /* Note that these are broken vs. the expected smbus API where - * on reads, the lenght is actually returned from the function, - * but I think the current API makes no sense and I don't want - * any driver that I haven't verified for correctness to go - * anywhere near a pmac i2c bus anyway ... - */ - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: - memcpy(&data->block[0], cmd.info.data, cmd.info.datalen); - break; - } - - return rc; -} - -static u32 -smu_smbus_func(struct i2c_adapter * adapter) -{ - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA; -} - -/* For now, we only handle combined mode (smbus) */ -static struct i2c_algorithm smu_algorithm = { - .smbus_xfer = smu_smbus_xfer, - .functionality = smu_smbus_func, -}; - -static int create_iface(struct device_node *np, struct device *dev) -{ - struct smu_iface* iface; - u32 *reg, busid; - int rc; - - reg = (u32 *)get_property(np, "reg", NULL); - if (reg == NULL) { - printk(KERN_ERR "i2c-pmac-smu: can't find bus number !\n"); - return -ENXIO; - } - busid = *reg; - - iface = kzalloc(sizeof(struct smu_iface), GFP_KERNEL); - if (iface == NULL) { - printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n"); - return -ENOMEM; - } - init_completion(&iface->complete); - iface->busid = busid; - - dev_set_drvdata(dev, iface); - - sprintf(iface->adapter.name, "smu-i2c-%02x", busid); - iface->adapter.algo = &smu_algorithm; - iface->adapter.algo_data = NULL; - iface->adapter.client_register = NULL; - iface->adapter.client_unregister = NULL; - i2c_set_adapdata(&iface->adapter, iface); - iface->adapter.dev.parent = dev; - - rc = i2c_add_adapter(&iface->adapter); - if (rc) { - printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration " - "failed\n", iface->adapter.name); - i2c_set_adapdata(&iface->adapter, NULL); - } - - if (probe) { - unsigned char addr; - printk("Probe: "); - for (addr = 0x00; addr <= 0x7f; addr++) { - if (i2c_smbus_xfer(&iface->adapter,addr, - 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) - printk("%02x ", addr); - } - printk("\n"); - } - - printk(KERN_INFO "SMU i2c bus %x registered\n", busid); - - return 0; -} - -static int dispose_iface(struct device *dev) -{ - struct smu_iface *iface = dev_get_drvdata(dev); - int rc; - - rc = i2c_del_adapter(&iface->adapter); - i2c_set_adapdata(&iface->adapter, NULL); - /* We aren't that prepared to deal with this... */ - if (rc) - printk("i2c-pmac-smu.c: Failed to remove bus %s !\n", - iface->adapter.name); - dev_set_drvdata(dev, NULL); - kfree(iface); - - return 0; -} - - -static int create_iface_of_platform(struct of_device* dev, - const struct of_device_id *match) -{ - struct device_node *node = dev->node; - - if (device_is_compatible(node, "smu-i2c") || - (node->parent != NULL && - device_is_compatible(node->parent, "smu-i2c-control"))) - return create_iface(node, &dev->dev); - return -ENODEV; -} - - -static int dispose_iface_of_platform(struct of_device* dev) -{ - return dispose_iface(&dev->dev); -} - - -static struct of_device_id i2c_smu_match[] = -{ - { - .compatible = "smu-i2c", - }, - { - .compatible = "i2c-bus", - }, - {}, -}; -static struct of_platform_driver i2c_smu_of_platform_driver = -{ - .name = "i2c-smu", - .match_table = i2c_smu_match, - .probe = create_iface_of_platform, - .remove = dispose_iface_of_platform -}; - - -static int __init i2c_pmac_smu_init(void) -{ - of_register_driver(&i2c_smu_of_platform_driver); - return 0; -} - - -static void __exit i2c_pmac_smu_cleanup(void) -{ - of_unregister_driver(&i2c_smu_of_platform_driver); -} - -module_init(i2c_pmac_smu_init); -module_exit(i2c_pmac_smu_cleanup); diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c new file mode 100644 index 000000000000..df786eb55295 --- /dev/null +++ b/drivers/i2c/busses/i2c-powermac.c @@ -0,0 +1,290 @@ +/* + i2c Support for Apple SMU Controller + + Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp. + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("I2C driver for Apple PowerMac"); +MODULE_LICENSE("GPL"); + +/* + * SMBUS-type transfer entrypoint + */ +static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data* data) +{ + struct pmac_i2c_bus *bus = i2c_get_adapdata(adap); + int rc = 0; + int read = (read_write == I2C_SMBUS_READ); + int addrdir = (addr << 1) | read; + u8 local[2]; + + rc = pmac_i2c_open(bus, 0); + if (rc) + return rc; + + switch (size) { + case I2C_SMBUS_QUICK: + rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); + if (rc) + goto bail; + rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0); + break; + case I2C_SMBUS_BYTE: + rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); + if (rc) + goto bail; + rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1); + break; + case I2C_SMBUS_BYTE_DATA: + rc = pmac_i2c_setmode(bus, read ? + pmac_i2c_mode_combined : + pmac_i2c_mode_stdsub); + if (rc) + goto bail; + rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1); + break; + case I2C_SMBUS_WORD_DATA: + rc = pmac_i2c_setmode(bus, read ? + pmac_i2c_mode_combined : + pmac_i2c_mode_stdsub); + if (rc) + goto bail; + if (!read) { + local[0] = data->word & 0xff; + local[1] = (data->word >> 8) & 0xff; + } + rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2); + if (rc == 0 && read) { + data->word = ((u16)local[1]) << 8; + data->word |= local[0]; + } + break; + + /* Note that these are broken vs. the expected smbus API where + * on reads, the lenght is actually returned from the function, + * but I think the current API makes no sense and I don't want + * any driver that I haven't verified for correctness to go + * anywhere near a pmac i2c bus anyway ... + * + * I'm also not completely sure what kind of phases to do between + * the actual command and the data (what I am _supposed_ to do that + * is). For now, I assume writes are a single stream and reads have + * a repeat start/addr phase (but not stop in between) + */ + case I2C_SMBUS_BLOCK_DATA: + rc = pmac_i2c_setmode(bus, read ? + pmac_i2c_mode_combined : + pmac_i2c_mode_stdsub); + if (rc) + goto bail; + rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block, + data->block[0] + 1); + + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + rc = pmac_i2c_setmode(bus, read ? + pmac_i2c_mode_combined : + pmac_i2c_mode_stdsub); + if (rc) + goto bail; + rc = pmac_i2c_xfer(bus, addrdir, 1, command, + read ? data->block : &data->block[1], + data->block[0]); + break; + + default: + rc = -EINVAL; + } + bail: + pmac_i2c_close(bus); + return rc; +} + +/* + * Generic i2c master transfer entrypoint. This driver only support single + * messages (for "lame i2c" transfers). Anything else should use the smbus + * entry point + */ +static int i2c_powermac_master_xfer( struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) +{ + struct pmac_i2c_bus *bus = i2c_get_adapdata(adap); + int rc = 0; + int read; + int addrdir; + + if (num != 1) + return -EINVAL; + if (msgs->flags & I2C_M_TEN) + return -EINVAL; + read = (msgs->flags & I2C_M_RD) != 0; + addrdir = (msgs->addr << 1) | read; + if (msgs->flags & I2C_M_REV_DIR_ADDR) + addrdir ^= 1; + + rc = pmac_i2c_open(bus, 0); + if (rc) + return rc; + rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); + if (rc) + goto bail; + rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len); + bail: + pmac_i2c_close(bus); + return rc < 0 ? rc : msgs->len; +} + +static u32 i2c_powermac_func(struct i2c_adapter * adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C; +} + +/* For now, we only handle smbus */ +static struct i2c_algorithm i2c_powermac_algorithm = { + .smbus_xfer = i2c_powermac_smbus_xfer, + .master_xfer = i2c_powermac_master_xfer, + .functionality = i2c_powermac_func, +}; + + +static int i2c_powermac_remove(struct device *dev) +{ + struct i2c_adapter *adapter = dev_get_drvdata(dev); + struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter); + int rc; + + rc = i2c_del_adapter(adapter); + pmac_i2c_detach_adapter(bus, adapter); + i2c_set_adapdata(adapter, NULL); + /* We aren't that prepared to deal with this... */ + if (rc) + printk("i2c-powermac.c: Failed to remove bus %s !\n", + adapter->name); + dev_set_drvdata(dev, NULL); + kfree(adapter); + + return 0; +} + + +static int i2c_powermac_probe(struct device *dev) +{ + struct pmac_i2c_bus *bus = dev->platform_data; + struct device_node *parent = NULL; + struct i2c_adapter *adapter; + char name[32], *basename; + int rc; + + if (bus == NULL) + return -EINVAL; + + /* Ok, now we need to make up a name for the interface that will + * match what we used to do in the past, that is basically the + * controller's parent device node for keywest. PMU didn't have a + * naming convention and SMU has a different one + */ + switch(pmac_i2c_get_type(bus)) { + case pmac_i2c_bus_keywest: + parent = of_get_parent(pmac_i2c_get_controller(bus)); + if (parent == NULL) + return -EINVAL; + basename = parent->name; + break; + case pmac_i2c_bus_pmu: + basename = "pmu"; + break; + case pmac_i2c_bus_smu: + /* This is not what we used to do but I'm fixing drivers at + * the same time as this change + */ + basename = "smu"; + break; + default: + return -EINVAL; + } + snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus)); + of_node_put(parent); + + adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if (adapter == NULL) { + printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n"); + return -ENOMEM; + } + dev_set_drvdata(dev, adapter); + strcpy(adapter->name, name); + adapter->algo = &i2c_powermac_algorithm; + i2c_set_adapdata(adapter, bus); + adapter->dev.parent = dev; + pmac_i2c_attach_adapter(bus, adapter); + rc = i2c_add_adapter(adapter); + if (rc) { + printk(KERN_ERR "i2c-powermac: Adapter %s registration " + "failed\n", name); + i2c_set_adapdata(adapter, NULL); + pmac_i2c_detach_adapter(bus, adapter); + } + + printk(KERN_INFO "PowerMac i2c bus %s registered\n", name); + return rc; +} + + +static struct device_driver i2c_powermac_driver = { + .name = "i2c-powermac", + .bus = &platform_bus_type, + .probe = i2c_powermac_probe, + .remove = i2c_powermac_remove, +}; + +static int __init i2c_powermac_init(void) +{ + driver_register(&i2c_powermac_driver); + return 0; +} + + +static void __exit i2c_powermac_cleanup(void) +{ + driver_unregister(&i2c_powermac_driver); +} + +module_init(i2c_powermac_init); +module_exit(i2c_powermac_cleanup); diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index a0ea44c3e8b1..7d4a0ac28c06 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -149,14 +149,14 @@ config MAC_EMUMOUSEBTN config THERM_WINDTUNNEL tristate "Support for thermal management on Windtunnel G4s" - depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64 + depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64 help This driver provides some thermostat and fan control for the desktop G4 "Windtunnel" config THERM_ADT746X tristate "Support for thermal mgmnt on laptops with ADT 746x chipset" - depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64 + depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64 help This driver provides some thermostat and fan control for the iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty @@ -164,7 +164,7 @@ config THERM_ADT746X config THERM_PM72 tristate "Support for thermal management on PowerMac G5" - depends on I2C && I2C_KEYWEST && PPC_PMAC64 + depends on I2C && I2C_POWERMAC && PPC_PMAC64 help This driver provides thermostat and fan control for the desktop G5 machines. @@ -175,14 +175,14 @@ config WINDFARM config WINDFARM_PM81 tristate "Support for thermal management on iMac G5" depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU - select I2C_PMAC_SMU + select I2C_POWERMAC help This driver provides thermal control for the iMacG5 config WINDFARM_PM91 tristate "Support for thermal management on PowerMac9,1" depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU - select I2C_PMAC_SMU + select I2C_POWERMAC help This driver provides thermal control for the PowerMac9,1 which is the recent (SMU based) single CPU desktop G5 diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 9ecd76849e35..db2ae71d07ef 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -584,34 +584,14 @@ core_initcall(smu_late_init); * sysfs visibility */ -static void smu_create_i2c(struct device_node *np) -{ - char name[32]; - u32 *reg = (u32 *)get_property(np, "reg", NULL); - - if (reg != NULL) { - sprintf(name, "smu-i2c-%02x", *reg); - of_platform_device_create(np, name, &smu->of_dev->dev); - } -} - static void smu_expose_childs(void *unused) { - struct device_node *np, *gp; - - for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) { - if (device_is_compatible(np, "smu-i2c-control")) { - gp = NULL; - while ((gp = of_get_next_child(np, gp)) != NULL) - if (device_is_compatible(gp, "i2c-bus")) - smu_create_i2c(gp); - } else if (device_is_compatible(np, "smu-i2c")) - smu_create_i2c(np); + struct device_node *np; + + for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) if (device_is_compatible(np, "smu-sensors")) of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev); - } - } static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL); diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index 57460e46c89f..906d3ecae6e6 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "windfarm.h" @@ -157,53 +158,21 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, static int wf_lm75_attach(struct i2c_adapter *adapter) { - u8 bus_id; - struct device_node *smu, *bus, *dev; - - /* We currently only deal with LM75's hanging off the SMU - * i2c busses. If we extend that driver to other/older - * machines, we should split this function into SMU-i2c, - * keywest-i2c, PMU-i2c, ... - */ + struct device_node *busnode, *dev; + struct pmac_i2c_bus *bus; DBG("wf_lm75: adapter %s detected\n", adapter->name); - if (strncmp(adapter->name, "smu-i2c-", 8) != 0) - return 0; - smu = of_find_node_by_type(NULL, "smu"); - if (smu == NULL) - return 0; - - /* Look for the bus in the device-tree */ - bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16); - - DBG("wf_lm75: bus ID is %x\n", bus_id); - - /* Look for sensors subdir */ - for (bus = NULL; - (bus = of_get_next_child(smu, bus)) != NULL;) { - u32 *reg; - - if (strcmp(bus->name, "i2c")) - continue; - reg = (u32 *)get_property(bus, "reg", NULL); - if (reg == NULL) - continue; - if (bus_id == *reg) - break; - } - of_node_put(smu); - if (bus == NULL) { - printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found" - " in device-tree !\n", bus_id); - return 0; - } + bus = pmac_i2c_adapter_to_bus(adapter); + if (bus == NULL) + return -ENODEV; + busnode = pmac_i2c_get_bus_node(bus); DBG("wf_lm75: bus found, looking for device...\n"); /* Now look for lm75(s) in there */ for (dev = NULL; - (dev = of_get_next_child(bus, dev)) != NULL;) { + (dev = of_get_next_child(busnode, dev)) != NULL;) { const char *loc = get_property(dev, "hwsensor-location", NULL); u32 *reg = (u32 *)get_property(dev, "reg", NULL); @@ -217,9 +186,6 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) else if (device_is_compatible(dev, "ds1775")) wf_lm75_create(adapter, *reg, 1, loc); } - - of_node_put(bus); - return 0; } diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h index adf4fa956572..480018f41e1a 100644 --- a/include/asm-powerpc/pmac_low_i2c.h +++ b/include/asm-powerpc/pmac_low_i2c.h @@ -70,6 +70,7 @@ extern struct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus); extern struct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus); extern int pmac_i2c_get_type(struct pmac_i2c_bus *bus); extern int pmac_i2c_get_flags(struct pmac_i2c_bus *bus); +extern int pmac_i2c_get_channel(struct pmac_i2c_bus *bus); /* i2c layer adapter attach/detach */ extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, @@ -77,6 +78,7 @@ extern void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, extern void pmac_i2c_detach_adapter(struct pmac_i2c_bus *bus, struct i2c_adapter *adapter); extern struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus); +extern struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter); /* March a device or bus with an i2c adapter structure, to be used by drivers * to match device-tree nodes with i2c adapters during adapter discovery -- cgit v1.2.3 From 5b9ca526917b7bc7d1da3beaccb2251a8f0b5fe2 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 7 Jan 2006 11:41:02 +1100 Subject: [PATCH] 3/5 powerpc: Add platform functions interpreter This is the platform function interpreter itself along with the backends for UniN/U3/U4, mac-io, GPIOs and i2c. It adds the ability to execute those do-platform-* scripts in the device-tree (at least for most devices for which a backend is provided). This should replace the clock spreading hacks properly. It might also have an impact on all sort of machines since some of the scripts marked "at init" will now be executed on boot (or some other on sleep/wakeup), those will possibly do things that the kernel didn't do at all, like setting some values into some i2c devices (changing thermal sensor calibration or conversion rate) etc... Thus regression testing is MUCH welcome. Also loook for errors in dmesg. That's also why I've left rather verbose debugging enabled in this version of the patch. (I do expect some Windtunnel G4s to show some errors as they have an i2c clock chip on the PMU bus that uses some primitives that the i2c backend doesn't implement yet. I really need users that have one of those machine to come back to me so we can get that done right, though the errors themselves should be harmless, I suspect the machine might not run at full speed). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/Makefile | 3 +- arch/powerpc/platforms/powermac/feature.c | 46 +- arch/powerpc/platforms/powermac/low_i2c.c | 294 +++++++- arch/powerpc/platforms/powermac/pfunc_base.c | 405 +++++++++++ arch/powerpc/platforms/powermac/pfunc_core.c | 989 +++++++++++++++++++++++++++ arch/powerpc/platforms/powermac/smp.c | 48 +- drivers/macintosh/via-pmu.c | 10 + include/asm-powerpc/pmac_feature.h | 19 + include/asm-powerpc/pmac_low_i2c.h | 3 + include/asm-powerpc/pmac_pfunc.h | 253 +++++++ 10 files changed, 2028 insertions(+), 42 deletions(-) create mode 100644 arch/powerpc/platforms/powermac/pfunc_base.c create mode 100644 arch/powerpc/platforms/powermac/pfunc_core.c create mode 100644 include/asm-powerpc/pmac_pfunc.h diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index faa1a2c82bcf..78093d7f97af 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,7 +1,8 @@ CFLAGS_bootx_init.o += -fPIC obj-y += pic.o setup.o time.o feature.o pci.o \ - sleep.o low_i2c.o cache.o + sleep.o low_i2c.o cache.o pfunc_core.o \ + pfunc_base.o obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index b271b11583ac..558dd0692092 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -58,12 +58,11 @@ extern int powersave_lowspeed; extern int powersave_nap; extern struct device_node *k2_skiplist[2]; - /* * We use a single global lock to protect accesses. Each driver has * to take care of its own locking */ -static DEFINE_SPINLOCK(feature_lock); +DEFINE_SPINLOCK(feature_lock); #define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); #define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); @@ -106,22 +105,12 @@ static const char *macio_names[] = }; +struct device_node *uninorth_node; +u32 __iomem *uninorth_base; -/* - * Uninorth reg. access. Note that Uni-N regs are big endian - */ - -#define UN_REG(r) (uninorth_base + ((r) >> 2)) -#define UN_IN(r) (in_be32(UN_REG(r))) -#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) -#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) -#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) - -static struct device_node *uninorth_node; -static u32 __iomem *uninorth_base; static u32 uninorth_rev; static int uninorth_maj; -static void __iomem *u3_ht; +static void __iomem *u3_ht_base; /* * For each motherboard family, we have a table of functions pointers @@ -1560,8 +1549,10 @@ void g5_phy_disable_cpu1(void) #ifndef CONFIG_POWER4 -static void -keylargo_shutdown(struct macio_chip *macio, int sleep_mode) + +#ifdef CONFIG_PM + +static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode) { u32 temp; @@ -1614,8 +1605,7 @@ keylargo_shutdown(struct macio_chip *macio, int sleep_mode) (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } -static void -pangea_shutdown(struct macio_chip *macio, int sleep_mode) +static void pangea_shutdown(struct macio_chip *macio, int sleep_mode) { u32 temp; @@ -1648,8 +1638,7 @@ pangea_shutdown(struct macio_chip *macio, int sleep_mode) (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } -static void -intrepid_shutdown(struct macio_chip *macio, int sleep_mode) +static void intrepid_shutdown(struct macio_chip *macio, int sleep_mode) { u32 temp; @@ -1833,6 +1822,8 @@ core99_wake_up(void) return 0; } +#endif /* CONFIG_PM */ + static long core99_sleep_state(struct device_node *node, long param, long value) { @@ -1854,10 +1845,13 @@ core99_sleep_state(struct device_node *node, long param, long value) if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) return -EPERM; +#ifdef CONFIG_PM if (value == 1) return core99_sleep(); else if (value == 0) return core99_wake_up(); + +#endif /* CONFIG_PM */ return 0; } @@ -1981,7 +1975,9 @@ static struct feature_table_entry core99_features[] = { { PMAC_FTR_USB_ENABLE, core99_usb_enable }, { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, +#ifdef CONFIG_PM { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, +#endif #ifdef CONFIG_SMP { PMAC_FTR_RESET_CPU, core99_reset_cpu }, #endif /* CONFIG_SMP */ @@ -2572,7 +2568,7 @@ static void __init probe_uninorth(void) uninorth_base = ioremap(address, 0x40000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); if (uninorth_maj == 3 || uninorth_maj == 4) - u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); + u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); printk(KERN_INFO "Found %s memory controller & host bridge" " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" : @@ -2921,9 +2917,9 @@ void __init pmac_check_ht_link(void) u8 px_bus, px_devfn; struct pci_controller *px_hose; - (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); - ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); - ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); + (void)in_be32(u3_ht_base + U3_HT_LINK_COMMAND); + ucfg = cfg = in_be32(u3_ht_base + U3_HT_LINK_CONFIG); + ufreq = freq = in_be32(u3_ht_base + U3_HT_LINK_FREQ); dump_HT_speeds("U3 HyperTransport", cfg, freq); pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index a25e447f907f..535c802b369f 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #ifdef DEBUG @@ -1162,9 +1163,291 @@ int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, } EXPORT_SYMBOL_GPL(pmac_i2c_xfer); +/* some quirks for platform function decoding */ +enum { + pmac_i2c_quirk_invmask = 0x00000001u, +}; + +static void pmac_i2c_devscan(void (*callback)(struct device_node *dev, + int quirks)) +{ + struct pmac_i2c_bus *bus; + struct device_node *np; + static struct whitelist_ent { + char *name; + char *compatible; + int quirks; + } whitelist[] = { + /* XXX Study device-tree's & apple drivers are get the quirks + * right ! + */ + { "i2c-hwclock", NULL, pmac_i2c_quirk_invmask }, + { "i2c-cpu-voltage", NULL, 0}, + { "temp-monitor", NULL, 0 }, + { "supply-monitor", NULL, 0 }, + { NULL, NULL, 0 }, + }; + + /* Only some devices need to have platform functions instanciated + * here. For now, we have a table. Others, like 9554 i2c GPIOs used + * on Xserve, if we ever do a driver for them, will use their own + * platform function instance + */ + list_for_each_entry(bus, &pmac_i2c_busses, link) { + for (np = NULL; + (np = of_get_next_child(bus->busnode, np)) != NULL;) { + struct whitelist_ent *p; + /* If multibus, check if device is on that bus */ + if (bus->flags & pmac_i2c_multibus) + if (bus != pmac_i2c_find_bus(np)) + continue; + for (p = whitelist; p->name != NULL; p++) { + if (strcmp(np->name, p->name)) + continue; + if (p->compatible && + !device_is_compatible(np, p->compatible)) + continue; + callback(np, p->quirks); + break; + } + } + } +} + +#define MAX_I2C_DATA 64 + +struct pmac_i2c_pf_inst +{ + struct pmac_i2c_bus *bus; + u8 addr; + u8 buffer[MAX_I2C_DATA]; + u8 scratch[MAX_I2C_DATA]; + int bytes; + int quirks; +}; + +static void* pmac_i2c_do_begin(struct pmf_function *func, struct pmf_args *args) +{ + struct pmac_i2c_pf_inst *inst; + struct pmac_i2c_bus *bus; + + bus = pmac_i2c_find_bus(func->node); + if (bus == NULL) { + printk(KERN_ERR "low_i2c: Can't find bus for %s (pfunc)\n", + func->node->full_name); + return NULL; + } + if (pmac_i2c_open(bus, 0)) { + printk(KERN_ERR "low_i2c: Can't open i2c bus for %s (pfunc)\n", + func->node->full_name); + return NULL; + } + + /* XXX might need GFP_ATOMIC when called during the suspend process, + * but then, there are already lots of issues with suspending when + * near OOM that need to be resolved, the allocator itself should + * probably make GFP_NOIO implicit during suspend + */ + inst = kzalloc(sizeof(struct pmac_i2c_pf_inst), GFP_KERNEL); + if (inst == NULL) { + pmac_i2c_close(bus); + return NULL; + } + inst->bus = bus; + inst->addr = pmac_i2c_get_dev_addr(func->node); + inst->quirks = (int)(long)func->driver_data; + return inst; +} + +static void pmac_i2c_do_end(struct pmf_function *func, void *instdata) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + if (inst == NULL) + return; + pmac_i2c_close(inst->bus); + if (inst) + kfree(inst); +} + +static int pmac_i2c_do_read(PMF_STD_ARGS, u32 len) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + inst->bytes = len; + return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 0, 0, + inst->buffer, len); +} + +static int pmac_i2c_do_write(PMF_STD_ARGS, u32 len, const u8 *data) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0, + (u8 *)data, len); +} + +/* This function is used to do the masking & OR'ing for the "rmw" type + * callbacks. Ze should apply the mask and OR in the values in the + * buffer before writing back. The problem is that it seems that + * various darwin drivers implement the mask/or differently, thus + * we need to check the quirks first + */ +static void pmac_i2c_do_apply_rmw(struct pmac_i2c_pf_inst *inst, + u32 len, const u8 *mask, const u8 *val) +{ + int i; + + if (inst->quirks & pmac_i2c_quirk_invmask) { + for (i = 0; i < len; i ++) + inst->scratch[i] = (inst->buffer[i] & mask[i]) | val[i]; + } else { + for (i = 0; i < len; i ++) + inst->scratch[i] = (inst->buffer[i] & ~mask[i]) + | (val[i] & mask[i]); + } +} + +static int pmac_i2c_do_rmw(PMF_STD_ARGS, u32 masklen, u32 valuelen, + u32 totallen, const u8 *maskdata, + const u8 *valuedata) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + if (masklen > inst->bytes || valuelen > inst->bytes || + totallen > inst->bytes || valuelen > masklen) + return -EINVAL; + + pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata); + + return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0, + inst->scratch, totallen); +} + +static int pmac_i2c_do_read_sub(PMF_STD_ARGS, u8 subaddr, u32 len) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + inst->bytes = len; + return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 1, subaddr, + inst->buffer, len); +} + +static int pmac_i2c_do_write_sub(PMF_STD_ARGS, u8 subaddr, u32 len, + const u8 *data) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1, + subaddr, (u8 *)data, len); +} + +static int pmac_i2c_do_set_mode(PMF_STD_ARGS, int mode) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + return pmac_i2c_setmode(inst->bus, mode); +} + +static int pmac_i2c_do_rmw_sub(PMF_STD_ARGS, u8 subaddr, u32 masklen, + u32 valuelen, u32 totallen, const u8 *maskdata, + const u8 *valuedata) +{ + struct pmac_i2c_pf_inst *inst = instdata; + + if (masklen > inst->bytes || valuelen > inst->bytes || + totallen > inst->bytes || valuelen > masklen) + return -EINVAL; + + pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata); + + return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1, + subaddr, inst->scratch, totallen); +} + +static int pmac_i2c_do_mask_and_comp(PMF_STD_ARGS, u32 len, + const u8 *maskdata, + const u8 *valuedata) +{ + struct pmac_i2c_pf_inst *inst = instdata; + int i, match; + + /* Get return value pointer, it's assumed to be a u32 */ + if (!args || !args->count || !args->u[0].p) + return -EINVAL; + + /* Check buffer */ + if (len > inst->bytes) + return -EINVAL; + + for (i = 0, match = 1; match && i < len; i ++) + if ((inst->buffer[i] & maskdata[i]) != valuedata[i]) + match = 0; + *args->u[0].p = match; + return 0; +} + +static int pmac_i2c_do_delay(PMF_STD_ARGS, u32 duration) +{ + msleep((duration + 999) / 1000); + return 0; +} + + +static struct pmf_handlers pmac_i2c_pfunc_handlers = { + .begin = pmac_i2c_do_begin, + .end = pmac_i2c_do_end, + .read_i2c = pmac_i2c_do_read, + .write_i2c = pmac_i2c_do_write, + .rmw_i2c = pmac_i2c_do_rmw, + .read_i2c_sub = pmac_i2c_do_read_sub, + .write_i2c_sub = pmac_i2c_do_write_sub, + .rmw_i2c_sub = pmac_i2c_do_rmw_sub, + .set_i2c_mode = pmac_i2c_do_set_mode, + .mask_and_compare = pmac_i2c_do_mask_and_comp, + .delay = pmac_i2c_do_delay, +}; + +static void __init pmac_i2c_dev_create(struct device_node *np, int quirks) +{ + DBG("dev_create(%s)\n", np->full_name); + + pmf_register_driver(np, &pmac_i2c_pfunc_handlers, + (void *)(long)quirks); +} + +static void __init pmac_i2c_dev_init(struct device_node *np, int quirks) +{ + DBG("dev_create(%s)\n", np->full_name); + + pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_INIT, NULL); +} + +static void pmac_i2c_dev_suspend(struct device_node *np, int quirks) +{ + DBG("dev_suspend(%s)\n", np->full_name); + pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_SLEEP, NULL); +} + +static void pmac_i2c_dev_resume(struct device_node *np, int quirks) +{ + DBG("dev_resume(%s)\n", np->full_name); + pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_WAKE, NULL); +} + +void pmac_pfunc_i2c_suspend(void) +{ + pmac_i2c_devscan(pmac_i2c_dev_suspend); +} + +void pmac_pfunc_i2c_resume(void) +{ + pmac_i2c_devscan(pmac_i2c_dev_resume); +} + /* - * Initialize us: probe all i2c busses on the machine and instantiate - * busses. + * Initialize us: probe all i2c busses on the machine, instantiate + * busses and platform functions as needed. */ /* This is non-static as it might be called early by smp code */ int __init pmac_i2c_init(void) @@ -1187,6 +1470,10 @@ int __init pmac_i2c_init(void) /* Probe SMU i2c busses */ smu_i2c_probe(); #endif + + /* Now add plaform functions for some known devices */ + pmac_i2c_devscan(pmac_i2c_dev_create); + return 0; } arch_initcall(pmac_i2c_init); @@ -1216,6 +1503,9 @@ static int __init pmac_i2c_create_platform_devices(void) platform_device_add(bus->platform_dev); } + /* Now call platform "init" functions */ + pmac_i2c_devscan(pmac_i2c_dev_init); + return 0; } subsys_initcall(pmac_i2c_create_platform_devices); diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c new file mode 100644 index 000000000000..4ffd2a9832a0 --- /dev/null +++ b/arch/powerpc/platforms/powermac/pfunc_base.c @@ -0,0 +1,405 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DBG(fmt...) printk(fmt) + +static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs) +{ + pmf_do_irq(data); + + return IRQ_HANDLED; +} + +static int macio_do_gpio_irq_enable(struct pmf_function *func) +{ + if (func->node->n_intrs < 1) + return -EINVAL; + + return request_irq(func->node->intrs[0].line, macio_gpio_irq, 0, + func->node->name, func); +} + +static int macio_do_gpio_irq_disable(struct pmf_function *func) +{ + if (func->node->n_intrs < 1) + return -EINVAL; + + free_irq(func->node->intrs[0].line, func); + return 0; +} + +static int macio_do_gpio_write(PMF_STD_ARGS, u8 value, u8 mask) +{ + u8 __iomem *addr = (u8 __iomem *)func->driver_data; + unsigned long flags; + u8 tmp; + + /* Check polarity */ + if (args && args->count && !args->u[0].v) + value = ~value; + + /* Toggle the GPIO */ + spin_lock_irqsave(&feature_lock, flags); + tmp = readb(addr); + tmp = (tmp & ~mask) | (value & mask); + DBG("Do write 0x%02x to GPIO %s (%p)\n", + tmp, func->node->full_name, addr); + writeb(tmp, addr); + spin_unlock_irqrestore(&feature_lock, flags); + + return 0; +} + +static int macio_do_gpio_read(PMF_STD_ARGS, u8 mask, int rshift, u8 xor) +{ + u8 __iomem *addr = (u8 __iomem *)func->driver_data; + u32 value; + + /* Check if we have room for reply */ + if (args == NULL || args->count == 0 || args->u[0].p == NULL) + return -EINVAL; + + value = readb(addr); + *args->u[0].p = ((value & mask) >> rshift) ^ xor; + + return 0; +} + +static int macio_do_delay(PMF_STD_ARGS, u32 duration) +{ + /* assume we can sleep ! */ + msleep((duration + 999) / 1000); + return 0; +} + +static struct pmf_handlers macio_gpio_handlers = { + .irq_enable = macio_do_gpio_irq_enable, + .irq_disable = macio_do_gpio_irq_disable, + .write_gpio = macio_do_gpio_write, + .read_gpio = macio_do_gpio_read, + .delay = macio_do_delay, +}; + +static void macio_gpio_init_one(struct macio_chip *macio) +{ + struct device_node *gparent, *gp; + + /* + * Find the "gpio" parent node + */ + + for (gparent = NULL; + (gparent = of_get_next_child(macio->of_node, gparent)) != NULL;) + if (strcmp(gparent->name, "gpio") == 0) + break; + if (gparent == NULL) + return; + + DBG("Installing GPIO functions for macio %s\n", + macio->of_node->full_name); + + /* + * Ok, got one, we dont need anything special to track them down, so + * we just create them all + */ + for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) { + u32 *reg = (u32 *)get_property(gp, "reg", NULL); + unsigned long offset; + if (reg == NULL) + continue; + offset = *reg; + /* Deal with old style device-tree. We can safely hard code the + * offset for now too even if it's a bit gross ... + */ + if (offset < 0x50) + offset += 0x50; + offset += (unsigned long)macio->base; + pmf_register_driver(gp, &macio_gpio_handlers, (void *)offset); + } + + DBG("Calling initial GPIO functions for macio %s\n", + macio->of_node->full_name); + + /* And now we run all the init ones */ + for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) + pmf_do_functions(gp, NULL, 0, PMF_FLAGS_ON_INIT, NULL); + + /* Note: We do not at this point implement the "at sleep" or "at wake" + * functions. I yet to find any for GPIOs anyway + */ +} + +static int macio_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask) +{ + struct macio_chip *macio = func->driver_data; + unsigned long flags; + + spin_lock_irqsave(&feature_lock, flags); + MACIO_OUT32(offset, (MACIO_IN32(offset) & ~mask) | (value & mask)); + spin_unlock_irqrestore(&feature_lock, flags); + return 0; +} + +static int macio_do_read_reg32(PMF_STD_ARGS, u32 offset) +{ + struct macio_chip *macio = func->driver_data; + + /* Check if we have room for reply */ + if (args == NULL || args->count == 0 || args->u[0].p == NULL) + return -EINVAL; + + *args->u[0].p = MACIO_IN32(offset); + return 0; +} + +static int macio_do_write_reg8(PMF_STD_ARGS, u32 offset, u8 value, u8 mask) +{ + struct macio_chip *macio = func->driver_data; + unsigned long flags; + + spin_lock_irqsave(&feature_lock, flags); + MACIO_OUT8(offset, (MACIO_IN8(offset) & ~mask) | (value & mask)); + spin_unlock_irqrestore(&feature_lock, flags); + return 0; +} + +static int macio_do_read_reg8(PMF_STD_ARGS, u32 offset) +{ + struct macio_chip *macio = func->driver_data; + + /* Check if we have room for reply */ + if (args == NULL || args->count == 0 || args->u[0].p == NULL) + return -EINVAL; + + *((u8 *)(args->u[0].p)) = MACIO_IN8(offset); + return 0; +} + +static int macio_do_read_reg32_msrx(PMF_STD_ARGS, u32 offset, u32 mask, + u32 shift, u32 xor) +{ + struct macio_chip *macio = func->driver_data; + + /* Check if we have room for reply */ + if (args == NULL || args->count == 0 || args->u[0].p == NULL) + return -EINVAL; + + *args->u[0].p = ((MACIO_IN32(offset) & mask) >> shift) ^ xor; + return 0; +} + +static int macio_do_read_reg8_msrx(PMF_STD_ARGS, u32 offset, u32 mask, + u32 shift, u32 xor) +{ + struct macio_chip *macio = func->driver_data; + + /* Check if we have room for reply */ + if (args == NULL || args->count == 0 || args->u[0].p == NULL) + return -EINVAL; + + *((u8 *)(args->u[0].p)) = ((MACIO_IN8(offset) & mask) >> shift) ^ xor; + return 0; +} + +static int macio_do_write_reg32_slm(PMF_STD_ARGS, u32 offset, u32 shift, + u32 mask) +{ + struct macio_chip *macio = func->driver_data; + unsigned long flags; + u32 tmp, val; + + /* Check args */ + if (args == NULL || args->count == 0) + return -EINVAL; + + spin_lock_irqsave(&feature_lock, flags); + tmp = MACIO_IN32(offset); + val = args->u[0].v << shift; + tmp = (tmp & ~mask) | (val & mask); + MACIO_OUT32(offset, tmp); + spin_unlock_irqrestore(&feature_lock, flags); + return 0; +} + +static int macio_do_write_reg8_slm(PMF_STD_ARGS, u32 offset, u32 shift, + u32 mask) +{ + struct macio_chip *macio = func->driver_data; + unsigned long flags; + u32 tmp, val; + + /* Check args */ + if (args == NULL || args->count == 0) + return -EINVAL; + + spin_lock_irqsave(&feature_lock, flags); + tmp = MACIO_IN8(offset); + val = args->u[0].v << shift; + tmp = (tmp & ~mask) | (val & mask); + MACIO_OUT8(offset, tmp); + spin_unlock_irqrestore(&feature_lock, flags); + return 0; +} + +static struct pmf_handlers macio_mmio_handlers = { + .write_reg32 = macio_do_write_reg32, + .read_reg32 = macio_do_read_reg32, + .write_reg8 = macio_do_write_reg8, + .read_reg32 = macio_do_read_reg8, + .read_reg32_msrx = macio_do_read_reg32_msrx, + .read_reg8_msrx = macio_do_read_reg8_msrx, + .write_reg32_slm = macio_do_write_reg32_slm, + .write_reg8_slm = macio_do_write_reg8_slm, + .delay = macio_do_delay, +}; + +static void macio_mmio_init_one(struct macio_chip *macio) +{ + DBG("Installing MMIO functions for macio %s\n", + macio->of_node->full_name); + + pmf_register_driver(macio->of_node, &macio_mmio_handlers, macio); +} + +static struct device_node *unin_hwclock; + +static int unin_do_write_reg32(PMF_STD_ARGS, u32 offset, u32 value, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&feature_lock, flags); + /* This is fairly bogus in darwin, but it should work for our needs + * implemeted that way: + */ + UN_OUT(offset, (UN_IN(offset) & ~mask) | (value & mask)); + spin_unlock_irqrestore(&feature_lock, flags); + return 0; +} + + +static struct pmf_handlers unin_mmio_handlers = { + .write_reg32 = unin_do_write_reg32, + .delay = macio_do_delay, +}; + +static void uninorth_install_pfunc(void) +{ + struct device_node *np; + + DBG("Installing functions for UniN %s\n", + uninorth_node->full_name); + + /* + * Install handlers for the bridge itself + */ + pmf_register_driver(uninorth_node, &unin_mmio_handlers, NULL); + pmf_do_functions(uninorth_node, NULL, 0, PMF_FLAGS_ON_INIT, NULL); + + + /* + * Install handlers for the hwclock child if any + */ + for (np = NULL; (np = of_get_next_child(uninorth_node, np)) != NULL;) + if (strcmp(np->name, "hw-clock") == 0) { + unin_hwclock = np; + break; + } + if (unin_hwclock) { + DBG("Installing functions for UniN clock %s\n", + unin_hwclock->full_name); + pmf_register_driver(unin_hwclock, &unin_mmio_handlers, NULL); + pmf_do_functions(unin_hwclock, NULL, 0, PMF_FLAGS_ON_INIT, + NULL); + } +} + +/* We export this as the SMP code might init us early */ +int __init pmac_pfunc_base_install(void) +{ + static int pfbase_inited; + int i; + + if (pfbase_inited) + return 0; + pfbase_inited = 1; + + + DBG("Installing base platform functions...\n"); + + /* + * Locate mac-io chips and install handlers + */ + for (i = 0 ; i < MAX_MACIO_CHIPS; i++) { + if (macio_chips[i].of_node) { + macio_mmio_init_one(&macio_chips[i]); + macio_gpio_init_one(&macio_chips[i]); + } + } + + /* + * Install handlers for northbridge and direct mapped hwclock + * if any. We do not implement the config space access callback + * which is only ever used for functions that we do not call in + * the current driver (enabling/disabling cells in U2, mostly used + * to restore the PCI settings, we do that differently) + */ + if (uninorth_node && uninorth_base) + uninorth_install_pfunc(); + + DBG("All base functions installed\n"); + + return 0; +} + +arch_initcall(pmac_pfunc_base_install); + +#ifdef CONFIG_PM + +/* Those can be called by pmac_feature. Ultimately, I should use a sysdev + * or a device, but for now, that's good enough until I sort out some + * ordering issues. Also, we do not bother with GPIOs, as so far I yet have + * to see a case where a GPIO function has the on-suspend or on-resume bit + */ +void pmac_pfunc_base_suspend(void) +{ + int i; + + for (i = 0 ; i < MAX_MACIO_CHIPS; i++) { + if (macio_chips[i].of_node) + pmf_do_functions(macio_chips[i].of_node, NULL, 0, + PMF_FLAGS_ON_SLEEP, NULL); + } + if (uninorth_node) + pmf_do_functions(uninorth_node, NULL, 0, + PMF_FLAGS_ON_SLEEP, NULL); + if (unin_hwclock) + pmf_do_functions(unin_hwclock, NULL, 0, + PMF_FLAGS_ON_SLEEP, NULL); +} + +void pmac_pfunc_base_resume(void) +{ + int i; + + if (unin_hwclock) + pmf_do_functions(unin_hwclock, NULL, 0, + PMF_FLAGS_ON_WAKE, NULL); + if (uninorth_node) + pmf_do_functions(uninorth_node, NULL, 0, + PMF_FLAGS_ON_WAKE, NULL); + for (i = 0 ; i < MAX_MACIO_CHIPS; i++) { + if (macio_chips[i].of_node) + pmf_do_functions(macio_chips[i].of_node, NULL, 0, + PMF_FLAGS_ON_WAKE, NULL); + } +} + +#endif /* CONFIG_PM */ diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c new file mode 100644 index 000000000000..c32c623001dc --- /dev/null +++ b/arch/powerpc/platforms/powermac/pfunc_core.c @@ -0,0 +1,989 @@ +/* + * + * FIXME: Properly make this race free with refcounting etc... + * + * FIXME: LOCKING !!! + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Debug */ +#define LOG_PARSE(fmt...) +#define LOG_ERROR(fmt...) printk(fmt) +#define LOG_BLOB(t,b,c) +#define DBG(fmt...) printk(fmt) + +/* Command numbers */ +#define PMF_CMD_LIST 0 +#define PMF_CMD_WRITE_GPIO 1 +#define PMF_CMD_READ_GPIO 2 +#define PMF_CMD_WRITE_REG32 3 +#define PMF_CMD_READ_REG32 4 +#define PMF_CMD_WRITE_REG16 5 +#define PMF_CMD_READ_REG16 6 +#define PMF_CMD_WRITE_REG8 7 +#define PMF_CMD_READ_REG8 8 +#define PMF_CMD_DELAY 9 +#define PMF_CMD_WAIT_REG32 10 +#define PMF_CMD_WAIT_REG16 11 +#define PMF_CMD_WAIT_REG8 12 +#define PMF_CMD_READ_I2C 13 +#define PMF_CMD_WRITE_I2C 14 +#define PMF_CMD_RMW_I2C 15 +#define PMF_CMD_GEN_I2C 16 +#define PMF_CMD_SHIFT_BYTES_RIGHT 17 +#define PMF_CMD_SHIFT_BYTES_LEFT 18 +#define PMF_CMD_READ_CFG 19 +#define PMF_CMD_WRITE_CFG 20 +#define PMF_CMD_RMW_CFG 21 +#define PMF_CMD_READ_I2C_SUBADDR 22 +#define PMF_CMD_WRITE_I2C_SUBADDR 23 +#define PMF_CMD_SET_I2C_MODE 24 +#define PMF_CMD_RMW_I2C_SUBADDR 25 +#define PMF_CMD_READ_REG32_MASK_SHR_XOR 26 +#define PMF_CMD_READ_REG16_MASK_SHR_XOR 27 +#define PMF_CMD_READ_REG8_MASK_SHR_XOR 28 +#define PMF_CMD_WRITE_REG32_SHL_MASK 29 +#define PMF_CMD_WRITE_REG16_SHL_MASK 30 +#define PMF_CMD_WRITE_REG8_SHL_MASK 31 +#define PMF_CMD_MASK_AND_COMPARE 32 +#define PMF_CMD_COUNT 33 + +/* This structure holds the state of the parser while walking through + * a function definition + */ +struct pmf_cmd { + const void *cmdptr; + const void *cmdend; + struct pmf_function *func; + void *instdata; + struct pmf_args *args; + int error; +}; + +#if 0 +/* Debug output */ +static void print_blob(const char *title, const void *blob, int bytes) +{ + printk("%s", title); + while(bytes--) { + printk("%02x ", *((u8 *)blob)); + blob += 1; + } + printk("\n"); +} +#endif + +/* + * Parser helpers + */ + +static u32 pmf_next32(struct pmf_cmd *cmd) +{ + u32 value; + if ((cmd->cmdend - cmd->cmdptr) < 4) { + cmd->error = 1; + return 0; + } + value = *((u32 *)cmd->cmdptr); + cmd->cmdptr += 4; + return value; +} + +static const void* pmf_next_blob(struct pmf_cmd *cmd, int count) +{ + const void *value; + if ((cmd->cmdend - cmd->cmdptr) < count) { + cmd->error = 1; + return NULL; + } + value = cmd->cmdptr; + cmd->cmdptr += count; + return value; +} + +/* + * Individual command parsers + */ + +#define PMF_PARSE_CALL(name, cmd, handlers, p...) \ + do { \ + if (cmd->error) \ + return -ENXIO; \ + if (handlers == NULL) \ + return 0; \ + if (handlers->name) \ + return handlers->name(cmd->func, cmd->instdata, \ + cmd->args, p); \ + return -1; \ + } while(0) \ + + +static int pmf_parser_write_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u8 value = (u8)pmf_next32(cmd); + u8 mask = (u8)pmf_next32(cmd); + + LOG_PARSE("pmf: write_gpio(value: %02x, mask: %02x)\n", value, mask); + + PMF_PARSE_CALL(write_gpio, cmd, h, value, mask); +} + +static int pmf_parser_read_gpio(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u8 mask = (u8)pmf_next32(cmd); + int rshift = (int)pmf_next32(cmd); + u8 xor = (u8)pmf_next32(cmd); + + LOG_PARSE("pmf: read_gpio(mask: %02x, rshift: %d, xor: %02x)\n", + mask, rshift, xor); + + PMF_PARSE_CALL(read_gpio, cmd, h, mask, rshift, xor); +} + +static int pmf_parser_write_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 value = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + + LOG_PARSE("pmf: write_reg32(offset: %08x, value: %08x, mask: %08x)\n", + offset, value, mask); + + PMF_PARSE_CALL(write_reg32, cmd, h, offset, value, mask); +} + +static int pmf_parser_read_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + + LOG_PARSE("pmf: read_reg32(offset: %08x)\n", offset); + + PMF_PARSE_CALL(read_reg32, cmd, h, offset); +} + + +static int pmf_parser_write_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u16 value = (u16)pmf_next32(cmd); + u16 mask = (u16)pmf_next32(cmd); + + LOG_PARSE("pmf: write_reg16(offset: %08x, value: %04x, mask: %04x)\n", + offset, value, mask); + + PMF_PARSE_CALL(write_reg16, cmd, h, offset, value, mask); +} + +static int pmf_parser_read_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + + LOG_PARSE("pmf: read_reg16(offset: %08x)\n", offset); + + PMF_PARSE_CALL(read_reg16, cmd, h, offset); +} + + +static int pmf_parser_write_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u8 value = (u16)pmf_next32(cmd); + u8 mask = (u16)pmf_next32(cmd); + + LOG_PARSE("pmf: write_reg8(offset: %08x, value: %02x, mask: %02x)\n", + offset, value, mask); + + PMF_PARSE_CALL(write_reg8, cmd, h, offset, value, mask); +} + +static int pmf_parser_read_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + + LOG_PARSE("pmf: read_reg8(offset: %08x)\n", offset); + + PMF_PARSE_CALL(read_reg8, cmd, h, offset); +} + +static int pmf_parser_delay(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 duration = pmf_next32(cmd); + + LOG_PARSE("pmf: delay(duration: %d us)\n", duration); + + PMF_PARSE_CALL(delay, cmd, h, duration); +} + +static int pmf_parser_wait_reg32(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 value = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + + LOG_PARSE("pmf: wait_reg32(offset: %08x, comp_value: %08x,mask: %08x)\n", + offset, value, mask); + + PMF_PARSE_CALL(wait_reg32, cmd, h, offset, value, mask); +} + +static int pmf_parser_wait_reg16(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u16 value = (u16)pmf_next32(cmd); + u16 mask = (u16)pmf_next32(cmd); + + LOG_PARSE("pmf: wait_reg16(offset: %08x, comp_value: %04x,mask: %04x)\n", + offset, value, mask); + + PMF_PARSE_CALL(wait_reg16, cmd, h, offset, value, mask); +} + +static int pmf_parser_wait_reg8(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u8 value = (u8)pmf_next32(cmd); + u8 mask = (u8)pmf_next32(cmd); + + LOG_PARSE("pmf: wait_reg8(offset: %08x, comp_value: %02x,mask: %02x)\n", + offset, value, mask); + + PMF_PARSE_CALL(wait_reg8, cmd, h, offset, value, mask); +} + +static int pmf_parser_read_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 bytes = pmf_next32(cmd); + + LOG_PARSE("pmf: read_i2c(bytes: %ud)\n", bytes); + + PMF_PARSE_CALL(read_i2c, cmd, h, bytes); +} + +static int pmf_parser_write_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 bytes = pmf_next32(cmd); + const void *blob = pmf_next_blob(cmd, bytes); + + LOG_PARSE("pmf: write_i2c(bytes: %ud) ...\n", bytes); + LOG_BLOB("pmf: data: \n", blob, bytes); + + PMF_PARSE_CALL(write_i2c, cmd, h, bytes, blob); +} + + +static int pmf_parser_rmw_i2c(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 maskbytes = pmf_next32(cmd); + u32 valuesbytes = pmf_next32(cmd); + u32 totalbytes = pmf_next32(cmd); + const void *maskblob = pmf_next_blob(cmd, maskbytes); + const void *valuesblob = pmf_next_blob(cmd, valuesbytes); + + LOG_PARSE("pmf: rmw_i2c(maskbytes: %ud, valuebytes: %ud, " + "totalbytes: %d) ...\n", + maskbytes, valuesbytes, totalbytes); + LOG_BLOB("pmf: mask data: \n", maskblob, maskbytes); + LOG_BLOB("pmf: values data: \n", valuesblob, valuesbytes); + + PMF_PARSE_CALL(rmw_i2c, cmd, h, maskbytes, valuesbytes, totalbytes, + maskblob, valuesblob); +} + +static int pmf_parser_read_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 bytes = pmf_next32(cmd); + + LOG_PARSE("pmf: read_cfg(offset: %x, bytes: %ud)\n", offset, bytes); + + PMF_PARSE_CALL(read_cfg, cmd, h, offset, bytes); +} + + +static int pmf_parser_write_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 bytes = pmf_next32(cmd); + const void *blob = pmf_next_blob(cmd, bytes); + + LOG_PARSE("pmf: write_cfg(offset: %x, bytes: %ud)\n", offset, bytes); + LOG_BLOB("pmf: data: \n", blob, bytes); + + PMF_PARSE_CALL(write_cfg, cmd, h, offset, bytes, blob); +} + +static int pmf_parser_rmw_cfg(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 maskbytes = pmf_next32(cmd); + u32 valuesbytes = pmf_next32(cmd); + u32 totalbytes = pmf_next32(cmd); + const void *maskblob = pmf_next_blob(cmd, maskbytes); + const void *valuesblob = pmf_next_blob(cmd, valuesbytes); + + LOG_PARSE("pmf: rmw_cfg(maskbytes: %ud, valuebytes: %ud," + " totalbytes: %d) ...\n", + maskbytes, valuesbytes, totalbytes); + LOG_BLOB("pmf: mask data: \n", maskblob, maskbytes); + LOG_BLOB("pmf: values data: \n", valuesblob, valuesbytes); + + PMF_PARSE_CALL(rmw_cfg, cmd, h, offset, maskbytes, valuesbytes, + totalbytes, maskblob, valuesblob); +} + + +static int pmf_parser_read_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u8 subaddr = (u8)pmf_next32(cmd); + u32 bytes = pmf_next32(cmd); + + LOG_PARSE("pmf: read_i2c_sub(subaddr: %x, bytes: %ud)\n", + subaddr, bytes); + + PMF_PARSE_CALL(read_i2c_sub, cmd, h, subaddr, bytes); +} + +static int pmf_parser_write_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u8 subaddr = (u8)pmf_next32(cmd); + u32 bytes = pmf_next32(cmd); + const void *blob = pmf_next_blob(cmd, bytes); + + LOG_PARSE("pmf: write_i2c_sub(subaddr: %x, bytes: %ud) ...\n", + subaddr, bytes); + LOG_BLOB("pmf: data: \n", blob, bytes); + + PMF_PARSE_CALL(write_i2c_sub, cmd, h, subaddr, bytes, blob); +} + +static int pmf_parser_set_i2c_mode(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u32 mode = pmf_next32(cmd); + + LOG_PARSE("pmf: set_i2c_mode(mode: %d)\n", mode); + + PMF_PARSE_CALL(set_i2c_mode, cmd, h, mode); +} + + +static int pmf_parser_rmw_i2c_sub(struct pmf_cmd *cmd, struct pmf_handlers *h) +{ + u8 subaddr = (u8)pmf_next32(cmd); + u32 maskbytes = pmf_next32(cmd); + u32 valuesbytes = pmf_next32(cmd); + u32 totalbytes = pmf_next32(cmd); + const void *maskblob = pmf_next_blob(cmd, maskbytes); + const void *valuesblob = pmf_next_blob(cmd, valuesbytes); + + LOG_PARSE("pmf: rmw_i2c_sub(subaddr: %x, maskbytes: %ud, valuebytes: %ud" + ", totalbytes: %d) ...\n", + subaddr, maskbytes, valuesbytes, totalbytes); + LOG_BLOB("pmf: mask data: \n", maskblob, maskbytes); + LOG_BLOB("pmf: values data: \n", valuesblob, valuesbytes); + + PMF_PARSE_CALL(rmw_i2c_sub, cmd, h, subaddr, maskbytes, valuesbytes, + totalbytes, maskblob, valuesblob); +} + +static int pmf_parser_read_reg32_msrx(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + u32 shift = pmf_next32(cmd); + u32 xor = pmf_next32(cmd); + + LOG_PARSE("pmf: read_reg32_msrx(offset: %x, mask: %x, shift: %x," + " xor: %x\n", offset, mask, shift, xor); + + PMF_PARSE_CALL(read_reg32_msrx, cmd, h, offset, mask, shift, xor); +} + +static int pmf_parser_read_reg16_msrx(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + u32 shift = pmf_next32(cmd); + u32 xor = pmf_next32(cmd); + + LOG_PARSE("pmf: read_reg16_msrx(offset: %x, mask: %x, shift: %x," + " xor: %x\n", offset, mask, shift, xor); + + PMF_PARSE_CALL(read_reg16_msrx, cmd, h, offset, mask, shift, xor); +} +static int pmf_parser_read_reg8_msrx(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + u32 shift = pmf_next32(cmd); + u32 xor = pmf_next32(cmd); + + LOG_PARSE("pmf: read_reg8_msrx(offset: %x, mask: %x, shift: %x," + " xor: %x\n", offset, mask, shift, xor); + + PMF_PARSE_CALL(read_reg8_msrx, cmd, h, offset, mask, shift, xor); +} + +static int pmf_parser_write_reg32_slm(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 shift = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + + LOG_PARSE("pmf: write_reg32_slm(offset: %x, shift: %x, mask: %x\n", + offset, shift, mask); + + PMF_PARSE_CALL(write_reg32_slm, cmd, h, offset, shift, mask); +} + +static int pmf_parser_write_reg16_slm(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 shift = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + + LOG_PARSE("pmf: write_reg16_slm(offset: %x, shift: %x, mask: %x\n", + offset, shift, mask); + + PMF_PARSE_CALL(write_reg16_slm, cmd, h, offset, shift, mask); +} + +static int pmf_parser_write_reg8_slm(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 offset = pmf_next32(cmd); + u32 shift = pmf_next32(cmd); + u32 mask = pmf_next32(cmd); + + LOG_PARSE("pmf: write_reg8_slm(offset: %x, shift: %x, mask: %x\n", + offset, shift, mask); + + PMF_PARSE_CALL(write_reg8_slm, cmd, h, offset, shift, mask); +} + +static int pmf_parser_mask_and_compare(struct pmf_cmd *cmd, + struct pmf_handlers *h) +{ + u32 bytes = pmf_next32(cmd); + const void *maskblob = pmf_next_blob(cmd, bytes); + const void *valuesblob = pmf_next_blob(cmd, bytes); + + LOG_PARSE("pmf: mask_and_compare(length: %ud ...\n", bytes); + LOG_BLOB("pmf: mask data: \n", maskblob, bytes); + LOG_BLOB("pmf: values data: \n", valuesblob, bytes); + + PMF_PARSE_CALL(mask_and_compare, cmd, h, + bytes, maskblob, valuesblob); +} + + +typedef int (*pmf_cmd_parser_t)(struct pmf_cmd *cmd, struct pmf_handlers *h); + +static pmf_cmd_parser_t pmf_parsers[PMF_CMD_COUNT] = +{ + NULL, + pmf_parser_write_gpio, + pmf_parser_read_gpio, + pmf_parser_write_reg32, + pmf_parser_read_reg32, + pmf_parser_write_reg16, + pmf_parser_read_reg16, + pmf_parser_write_reg8, + pmf_parser_read_reg8, + pmf_parser_delay, + pmf_parser_wait_reg32, + pmf_parser_wait_reg16, + pmf_parser_wait_reg8, + pmf_parser_read_i2c, + pmf_parser_write_i2c, + pmf_parser_rmw_i2c, + NULL, /* Bogus command */ + NULL, /* Shift bytes right: NYI */ + NULL, /* Shift bytes left: NYI */ + pmf_parser_read_cfg, + pmf_parser_write_cfg, + pmf_parser_rmw_cfg, + pmf_parser_read_i2c_sub, + pmf_parser_write_i2c_sub, + pmf_parser_set_i2c_mode, + pmf_parser_rmw_i2c_sub, + pmf_parser_read_reg32_msrx, + pmf_parser_read_reg16_msrx, + pmf_parser_read_reg8_msrx, + pmf_parser_write_reg32_slm, + pmf_parser_write_reg16_slm, + pmf_parser_write_reg8_slm, + pmf_parser_mask_and_compare, +}; + +struct pmf_device { + struct list_head link; + struct device_node *node; + struct pmf_handlers *handlers; + struct list_head functions; + struct kref ref; +}; + +static LIST_HEAD(pmf_devices); +static spinlock_t pmf_lock = SPIN_LOCK_UNLOCKED; + +static void pmf_release_device(struct kref *kref) +{ + struct pmf_device *dev = container_of(kref, struct pmf_device, ref); + kfree(dev); +} + +static inline void pmf_put_device(struct pmf_device *dev) +{ + kref_put(&dev->ref, pmf_release_device); +} + +static inline struct pmf_device *pmf_get_device(struct pmf_device *dev) +{ + kref_get(&dev->ref); + return dev; +} + +static inline struct pmf_device *pmf_find_device(struct device_node *np) +{ + struct pmf_device *dev; + + list_for_each_entry(dev, &pmf_devices, link) { + if (dev->node == np) + return pmf_get_device(dev); + } + return NULL; +} + +static int pmf_parse_one(struct pmf_function *func, + struct pmf_handlers *handlers, + void *instdata, struct pmf_args *args) +{ + struct pmf_cmd cmd; + u32 ccode; + int count, rc; + + cmd.cmdptr = func->data; + cmd.cmdend = func->data + func->length; + cmd.func = func; + cmd.instdata = instdata; + cmd.args = args; + cmd.error = 0; + + LOG_PARSE("pmf: func %s, %d bytes, %s...\n", + func->name, func->length, + handlers ? "executing" : "parsing"); + + /* One subcommand to parse for now */ + count = 1; + + while(count-- && cmd.cmdptr < cmd.cmdend) { + /* Get opcode */ + ccode = pmf_next32(&cmd); + /* Check if we are hitting a command list, fetch new count */ + if (ccode == 0) { + count = pmf_next32(&cmd) - 1; + ccode = pmf_next32(&cmd); + } + if (cmd.error) { + LOG_ERROR("pmf: parse error, not enough data\n"); + return -ENXIO; + } + if (ccode >= PMF_CMD_COUNT) { + LOG_ERROR("pmf: command code %d unknown !\n", ccode); + return -ENXIO; + } + if (pmf_parsers[ccode] == NULL) { + LOG_ERROR("pmf: no parser for command %d !\n", ccode); + return -ENXIO; + } + rc = pmf_parsers[ccode](&cmd, handlers); + if (rc != 0) { + LOG_ERROR("pmf: parser for command %d returned" + " error %d\n", ccode, rc); + return rc; + } + } + + /* We are doing an initial parse pass, we need to adjust the size */ + if (handlers == NULL) + func->length = cmd.cmdptr - func->data; + + return 0; +} + +static int pmf_add_function_prop(struct pmf_device *dev, void *driverdata, + const char *name, u32 *data, + unsigned int length) +{ + int count = 0; + struct pmf_function *func = NULL; + + DBG("pmf: Adding functions for platform-do-%s\n", name); + + while (length >= 12) { + /* Allocate a structure */ + func = kzalloc(sizeof(struct pmf_function), GFP_KERNEL); + if (func == NULL) + goto bail; + kref_init(&func->ref); + INIT_LIST_HEAD(&func->irq_clients); + func->node = dev->node; + func->driver_data = driverdata; + func->name = name; + func->phandle = data[0]; + func->flags = data[1]; + data += 2; + length -= 8; + func->data = data; + func->length = length; + func->dev = dev; + DBG("pmf: idx %d: flags=%08x, phandle=%08x " + " %d bytes remaining, parsing...\n", + count+1, func->flags, func->phandle, length); + if (pmf_parse_one(func, NULL, NULL, NULL)) { + kfree(func); + goto bail; + } + length -= func->length; + data = (u32 *)(((u8 *)data) + func->length); + list_add(&func->link, &dev->functions); + pmf_get_device(dev); + count++; + } + bail: + DBG("pmf: Added %d functions\n", count); + + return count; +} + +static int pmf_add_functions(struct pmf_device *dev, void *driverdata) +{ + struct property *pp; +#define PP_PREFIX "platform-do-" + const int plen = strlen(PP_PREFIX); + int count = 0; + + for (pp = dev->node->properties; pp != 0; pp = pp->next) { + char *name; + if (strncmp(pp->name, PP_PREFIX, plen) != 0) + continue; + name = pp->name + plen; + if (strlen(name) && pp->length >= 12) + count += pmf_add_function_prop(dev, driverdata, name, + (u32 *)pp->value, + pp->length); + } + return count; +} + + +int pmf_register_driver(struct device_node *np, + struct pmf_handlers *handlers, + void *driverdata) +{ + struct pmf_device *dev; + unsigned long flags; + int rc = 0; + + if (handlers == NULL) + return -EINVAL; + + DBG("pmf: registering driver for node %s\n", np->full_name); + + spin_lock_irqsave(&pmf_lock, flags); + dev = pmf_find_device(np); + spin_unlock_irqrestore(&pmf_lock, flags); + if (dev != NULL) { + DBG("pmf: already there !\n"); + pmf_put_device(dev); + return -EBUSY; + } + + dev = kzalloc(sizeof(struct pmf_device), GFP_KERNEL); + if (dev == NULL) { + DBG("pmf: no memory !\n"); + return -ENOMEM; + } + kref_init(&dev->ref); + dev->node = of_node_get(np); + dev->handlers = handlers; + INIT_LIST_HEAD(&dev->functions); + + rc = pmf_add_functions(dev, driverdata); + if (rc == 0) { + DBG("pmf: no functions, disposing.. \n"); + of_node_put(np); + kfree(dev); + return -ENODEV; + } + + spin_lock_irqsave(&pmf_lock, flags); + list_add(&dev->link, &pmf_devices); + spin_unlock_irqrestore(&pmf_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(pmf_register_driver); + +struct pmf_function *pmf_get_function(struct pmf_function *func) +{ + if (!try_module_get(func->dev->handlers->owner)) + return NULL; + kref_get(&func->ref); + return func; +} +EXPORT_SYMBOL_GPL(pmf_get_function); + +static void pmf_release_function(struct kref *kref) +{ + struct pmf_function *func = + container_of(kref, struct pmf_function, ref); + pmf_put_device(func->dev); + kfree(func); +} + +static inline void __pmf_put_function(struct pmf_function *func) +{ + kref_put(&func->ref, pmf_release_function); +} + +void pmf_put_function(struct pmf_function *func) +{ + if (func == NULL) + return; + module_put(func->dev->handlers->owner); + __pmf_put_function(func); +} +EXPORT_SYMBOL_GPL(pmf_put_function); + +void pmf_unregister_driver(struct device_node *np) +{ + struct pmf_device *dev; + unsigned long flags; + + DBG("pmf: unregistering driver for node %s\n", np->full_name); + + spin_lock_irqsave(&pmf_lock, flags); + dev = pmf_find_device(np); + if (dev == NULL) { + DBG("pmf: not such driver !\n"); + spin_unlock_irqrestore(&pmf_lock, flags); + return; + } + list_del(&dev->link); + + while(!list_empty(&dev->functions)) { + struct pmf_function *func = + list_entry(dev->functions.next, typeof(*func), link); + list_del(&func->link); + __pmf_put_function(func); + } + + pmf_put_device(dev); + spin_unlock_irqrestore(&pmf_lock, flags); +} +EXPORT_SYMBOL_GPL(pmf_unregister_driver); + +struct pmf_function *__pmf_find_function(struct device_node *target, + const char *name, u32 flags) +{ + struct device_node *actor = of_node_get(target); + struct pmf_device *dev; + struct pmf_function *func, *result = NULL; + char fname[64]; + u32 *prop, ph; + + /* + * Look for a "platform-*" function reference. If we can't find + * one, then we fallback to a direct call attempt + */ + snprintf(fname, 63, "platform-%s", name); + prop = (u32 *)get_property(target, fname, NULL); + if (prop == NULL) + goto find_it; + ph = *prop; + if (ph == 0) + goto find_it; + + /* + * Ok, now try to find the actor. If we can't find it, we fail, + * there is no point in falling back there + */ + of_node_put(actor); + actor = of_find_node_by_phandle(ph); + if (actor == NULL) + return NULL; + find_it: + dev = pmf_find_device(actor); + if (dev == NULL) + return NULL; + + list_for_each_entry(func, &dev->functions, link) { + if (name && strcmp(name, func->name)) + continue; + if (func->phandle && target->node != func->phandle) + continue; + if ((func->flags & flags) == 0) + continue; + result = func; + break; + } + of_node_put(actor); + pmf_put_device(dev); + return result; +} + + +int pmf_register_irq_client(struct device_node *target, + const char *name, + struct pmf_irq_client *client) +{ + struct pmf_function *func; + unsigned long flags; + + spin_lock_irqsave(&pmf_lock, flags); + func = __pmf_find_function(target, name, PMF_FLAGS_INT_GEN); + if (func == NULL) { + spin_unlock_irqrestore(&pmf_lock, flags); + return -ENODEV; + } + list_add(&client->link, &func->irq_clients); + spin_unlock_irqrestore(&pmf_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(pmf_register_irq_client); + +void pmf_unregister_irq_client(struct device_node *np, + const char *name, + struct pmf_irq_client *client) +{ + unsigned long flags; + + spin_lock_irqsave(&pmf_lock, flags); + list_del(&client->link); + spin_unlock_irqrestore(&pmf_lock, flags); +} +EXPORT_SYMBOL_GPL(pmf_unregister_irq_client); + + +void pmf_do_irq(struct pmf_function *func) +{ + unsigned long flags; + struct pmf_irq_client *client; + + /* For now, using a spinlock over the whole function. Can be made + * to drop the lock using 2 lists if necessary + */ + spin_lock_irqsave(&pmf_lock, flags); + list_for_each_entry(client, &func->irq_clients, link) { + if (!try_module_get(client->owner)) + continue; + client->handler(client->data); + module_put(client->owner); + } + spin_unlock_irqrestore(&pmf_lock, flags); +} +EXPORT_SYMBOL_GPL(pmf_do_irq); + + +int pmf_call_one(struct pmf_function *func, struct pmf_args *args) +{ + struct pmf_device *dev = func->dev; + void *instdata = NULL; + int rc = 0; + + DBG(" ** pmf_call_one(%s/%s) **\n", dev->node->full_name, func->name); + + if (dev->handlers->begin) + instdata = dev->handlers->begin(func, args); + rc = pmf_parse_one(func, dev->handlers, instdata, args); + if (dev->handlers->end) + dev->handlers->end(func, instdata); + + return rc; +} +EXPORT_SYMBOL_GPL(pmf_call_one); + +int pmf_do_functions(struct device_node *np, const char *name, + u32 phandle, u32 fflags, struct pmf_args *args) +{ + struct pmf_device *dev; + struct pmf_function *func, *tmp; + unsigned long flags; + int rc = -ENODEV; + + spin_lock_irqsave(&pmf_lock, flags); + + dev = pmf_find_device(np); + if (dev == NULL) { + spin_unlock_irqrestore(&pmf_lock, flags); + return -ENODEV; + } + list_for_each_entry_safe(func, tmp, &dev->functions, link) { + if (name && strcmp(name, func->name)) + continue; + if (phandle && func->phandle && phandle != func->phandle) + continue; + if ((func->flags & fflags) == 0) + continue; + if (pmf_get_function(func) == NULL) + continue; + spin_unlock_irqrestore(&pmf_lock, flags); + rc = pmf_call_one(func, args); + pmf_put_function(func); + spin_lock_irqsave(&pmf_lock, flags); + } + pmf_put_device(dev); + spin_unlock_irqrestore(&pmf_lock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(pmf_do_functions); + + +struct pmf_function *pmf_find_function(struct device_node *target, + const char *name) +{ + struct pmf_function *func; + unsigned long flags; + + spin_lock_irqsave(&pmf_lock, flags); + func = __pmf_find_function(target, name, PMF_FLAGS_ON_DEMAND); + if (func) + func = pmf_get_function(func); + spin_unlock_irqrestore(&pmf_lock, flags); + return func; +} +EXPORT_SYMBOL_GPL(pmf_find_function); + +int pmf_call_function(struct device_node *target, const char *name, + struct pmf_args *args) +{ + struct pmf_function *func = pmf_find_function(target, name); + int rc; + + if (func == NULL) + return -ENODEV; + + rc = pmf_call_one(func, args); + pmf_put_function(func); + return rc; +} +EXPORT_SYMBOL_GPL(pmf_call_function); + diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index ab72ba86be1e..0df2cdcd805c 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -52,8 +52,9 @@ #include #include #include +#include -#undef DEBUG +#define DEBUG #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -62,6 +63,7 @@ #endif extern void __secondary_start_pmac_0(void); +extern int pmac_pfunc_base_install(void); #ifdef CONFIG_PPC32 @@ -602,11 +604,29 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus) pmac_tb_clock_chip_host = NULL; } -#endif /* CONFIG_PPC64 */ /* - * SMP G4 and newer G5 use a GPIO to enable/disable the timebase. + * Newer G5s uses a platform function + */ + +static void smp_core99_pfunc_tb_freeze(int freeze) +{ + struct device_node *cpus; + struct pmf_args args; + + cpus = of_find_node_by_path("/cpus"); + BUG_ON(cpus == NULL); + args.count = 1; + args.u[0].v = !freeze; + pmf_call_function(cpus, "cpu-timebase", &args); + of_node_put(cpus); +} + +#else /* CONFIG_PPC64 */ + +/* + * SMP G4 use a GPIO to enable/disable the timebase. */ static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ @@ -620,6 +640,9 @@ static void smp_core99_gpio_tb_freeze(int freeze) pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); } + +#endif /* !CONFIG_PPC64 */ + /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ volatile static long int core99_l2_cache; volatile static long int core99_l3_cache; @@ -665,19 +688,15 @@ static void __init smp_core99_setup(int ncpus) machine_is_compatible("RackMac3,1")) smp_core99_setup_i2c_hwsync(ncpus); - /* GPIO based HW sync on recent G5s */ + /* pfunc based HW sync on recent G5s */ if (pmac_tb_freeze == NULL) { - struct device_node *np = - of_find_node_by_name(NULL, "timebase-enable"); - u32 *reg = (u32 *)get_property(np, "reg", NULL); - - if (np && reg && !strcmp(np->type, "gpio")) { - core99_tb_gpio = *reg; - if (core99_tb_gpio < 0x50) - core99_tb_gpio += 0x50; - pmac_tb_freeze = smp_core99_gpio_tb_freeze; + struct device_node *cpus = + of_find_node_by_path("/cpus"); + if (cpus && + get_property(cpus, "platform-cpu-timebase", NULL)) { + pmac_tb_freeze = smp_core99_pfunc_tb_freeze; printk(KERN_INFO "Processor timebase sync using" - " GPIO 0x%02x\n", core99_tb_gpio); + " platform function\n"); } } @@ -746,6 +765,7 @@ static int __init smp_core99_probe(void) /* We need to perform some early initialisations before we can start * setting up SMP as we are running before initcalls */ + pmac_pfunc_base_install(); pmac_i2c_init(); /* Setup various bits like timebase sync method, ability to nap, ... */ diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index aa481a88ccab..6eb93e45fcd3 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include #include #include @@ -2105,6 +2107,10 @@ pmac_suspend_devices(void) return -EBUSY; } + /* Call platform functions marked "on sleep" */ + pmac_pfunc_i2c_suspend(); + pmac_pfunc_base_suspend(); + /* Stop preemption */ preempt_disable(); @@ -2175,6 +2181,10 @@ pmac_wakeup_devices(void) mdelay(10); preempt_enable(); + /* Call platform functions marked "on wake" */ + pmac_pfunc_base_resume(); + pmac_pfunc_i2c_resume(); + /* Resume devices */ device_resume(); diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h index e654ad0e5b42..3221628130c4 100644 --- a/include/asm-powerpc/pmac_feature.h +++ b/include/asm-powerpc/pmac_feature.h @@ -374,5 +374,24 @@ extern struct macio_chip* macio_find(struct device_node* child, int type); #define MACIO_IN8(r) (in_8(MACIO_FCR8(macio,r))) #define MACIO_OUT8(r,v) (out_8(MACIO_FCR8(macio,r), (v))) +/* + * Those are exported by pmac feature for internal use by arch code + * only like the platform function callbacks, do not use directly in drivers + */ +extern spinlock_t feature_lock; +extern struct device_node *uninorth_node; +extern u32 __iomem *uninorth_base; + +/* + * Uninorth reg. access. Note that Uni-N regs are big endian + */ + +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + + #endif /* __PPC_ASM_PMAC_FEATURE_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h index 480018f41e1a..131011bd7e76 100644 --- a/include/asm-powerpc/pmac_low_i2c.h +++ b/include/asm-powerpc/pmac_low_i2c.h @@ -99,6 +99,9 @@ extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode); extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, u32 subaddr, u8 *data, int len); +/* Suspend/resume code called by via-pmu directly for now */ +extern void pmac_pfunc_i2c_suspend(void); +extern void pmac_pfunc_i2c_resume(void); #endif /* __KERNEL__ */ #endif /* __PMAC_LOW_I2C_H__ */ diff --git a/include/asm-powerpc/pmac_pfunc.h b/include/asm-powerpc/pmac_pfunc.h new file mode 100644 index 000000000000..d9728c80f86d --- /dev/null +++ b/include/asm-powerpc/pmac_pfunc.h @@ -0,0 +1,253 @@ +#ifndef __PMAC_PFUNC_H__ +#define __PMAC_PFUNC_H__ + +#include +#include + +/* Flags in command lists */ +#define PMF_FLAGS_ON_INIT 0x80000000u +#define PMF_FLGAS_ON_TERM 0x40000000u +#define PMF_FLAGS_ON_SLEEP 0x20000000u +#define PMF_FLAGS_ON_WAKE 0x10000000u +#define PMF_FLAGS_ON_DEMAND 0x08000000u +#define PMF_FLAGS_INT_GEN 0x04000000u +#define PMF_FLAGS_HIGH_SPEED 0x02000000u +#define PMF_FLAGS_LOW_SPEED 0x01000000u +#define PMF_FLAGS_SIDE_EFFECTS 0x00800000u + +/* + * Arguments to a platform function call. + * + * NOTE: By convention, pointer arguments point to an u32 + */ +struct pmf_args { + union { + u32 v; + u32 *p; + } u[4]; + unsigned int count; +}; + +/* + * A driver capable of interpreting commands provides a handlers + * structure filled with whatever handlers are implemented by this + * driver. Non implemented handlers are left NULL. + * + * PMF_STD_ARGS are the same arguments that are passed to the parser + * and that gets passed back to the various handlers. + * + * Interpreting a given function always start with a begin() call which + * returns an instance data to be passed around subsequent calls, and + * ends with an end() call. This allows the low level driver to implement + * locking policy or per-function instance data. + * + * For interrupt capable functions, irq_enable() is called when a client + * registers, and irq_disable() is called when the last client unregisters + * Note that irq_enable & irq_disable are called within a semaphore held + * by the core, thus you should not try to register yourself to some other + * pmf interrupt during those calls. + */ + +#define PMF_STD_ARGS struct pmf_function *func, void *instdata, \ + struct pmf_args *args + +struct pmf_function; + +struct pmf_handlers { + void * (*begin)(struct pmf_function *func, struct pmf_args *args); + void (*end)(struct pmf_function *func, void *instdata); + + int (*irq_enable)(struct pmf_function *func); + int (*irq_disable)(struct pmf_function *func); + + int (*write_gpio)(PMF_STD_ARGS, u8 value, u8 mask); + int (*read_gpio)(PMF_STD_ARGS, u8 mask, int rshift, u8 xor); + + int (*write_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask); + int (*read_reg32)(PMF_STD_ARGS, u32 offset); + int (*write_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask); + int (*read_reg16)(PMF_STD_ARGS, u32 offset); + int (*write_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask); + int (*read_reg8)(PMF_STD_ARGS, u32 offset); + + int (*delay)(PMF_STD_ARGS, u32 duration); + + int (*wait_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask); + int (*wait_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask); + int (*wait_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask); + + int (*read_i2c)(PMF_STD_ARGS, u32 len); + int (*write_i2c)(PMF_STD_ARGS, u32 len, const u8 *data); + int (*rmw_i2c)(PMF_STD_ARGS, u32 masklen, u32 valuelen, u32 totallen, + const u8 *maskdata, const u8 *valuedata); + + int (*read_cfg)(PMF_STD_ARGS, u32 offset, u32 len); + int (*write_cfg)(PMF_STD_ARGS, u32 offset, u32 len, const u8 *data); + int (*rmw_cfg)(PMF_STD_ARGS, u32 offset, u32 masklen, u32 valuelen, + u32 totallen, const u8 *maskdata, const u8 *valuedata); + + int (*read_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len); + int (*write_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len, const u8 *data); + int (*set_i2c_mode)(PMF_STD_ARGS, int mode); + int (*rmw_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 masklen, u32 valuelen, + u32 totallen, const u8 *maskdata, + const u8 *valuedata); + + int (*read_reg32_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift, + u32 xor); + int (*read_reg16_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift, + u32 xor); + int (*read_reg8_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift, + u32 xor); + + int (*write_reg32_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask); + int (*write_reg16_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask); + int (*write_reg8_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask); + + int (*mask_and_compare)(PMF_STD_ARGS, u32 len, const u8 *maskdata, + const u8 *valuedata); + + struct module *owner; +}; + + +/* + * Drivers who expose platform functions register at init time, this + * causes the platform functions for that device node to be parsed in + * advance and associated with the device. The data structures are + * partially public so a driver can walk the list of platform functions + * and eventually inspect the flags + */ +struct pmf_device; + +struct pmf_function { + /* All functions for a given driver are linked */ + struct list_head link; + + /* Function node & driver data */ + struct device_node *node; + void *driver_data; + + /* For internal use by core */ + struct pmf_device *dev; + + /* The name is the "xxx" in "platform-do-xxx", this is how + * platform functions are identified by this code. Some functions + * only operate for a given target, in which case the phandle is + * here (or 0 if the filter doesn't apply) + */ + const char *name; + u32 phandle; + + /* The flags for that function. You can have several functions + * with the same name and different flag + */ + u32 flags; + + /* The actual tokenized function blob */ + const void *data; + unsigned int length; + + /* Interrupt clients */ + struct list_head irq_clients; + + /* Refcounting */ + struct kref ref; +}; + +/* + * For platform functions that are interrupts, one can register + * irq_client structures. You canNOT use the same structure twice + * as it contains a link member. Also, the callback is called with + * a spinlock held, you must not call back into any of the pmf_* functions + * from within that callback + */ +struct pmf_irq_client { + void (*handler)(void *data); + void *data; + struct module *owner; + struct list_head link; +}; + + +/* + * Register/Unregister a function-capable driver and its handlers + */ +extern int pmf_register_driver(struct device_node *np, + struct pmf_handlers *handlers, + void *driverdata); + +extern void pmf_unregister_driver(struct device_node *np); + + +/* + * Register/Unregister interrupt clients + */ +extern int pmf_register_irq_client(struct device_node *np, + const char *name, + struct pmf_irq_client *client); + +extern void pmf_unregister_irq_client(struct device_node *np, + const char *name, + struct pmf_irq_client *client); + +/* + * Called by the handlers when an irq happens + */ +extern void pmf_do_irq(struct pmf_function *func); + + +/* + * Low level call to platform functions. + * + * The phandle can filter on the target object for functions that have + * multiple targets, the flags allow you to restrict the call to a given + * combination of flags. + * + * The args array contains as many arguments as is required by the function, + * this is dependent on the function you are calling, unfortunately Apple + * mecanism provides no way to encode that so you have to get it right at + * the call site. Some functions require no args, in which case, you can + * pass NULL. + * + * You can also pass NULL to the name. This will match any function that has + * the appropriate combination of flags & phandle or you can pass 0 to the + * phandle to match any + */ +extern int pmf_do_functions(struct device_node *np, const char *name, + u32 phandle, u32 flags, struct pmf_args *args); + + + +/* + * High level call to a platform function. + * + * This one looks for the platform-xxx first so you should call it to the + * actual target if any. It will fallback to platform-do-xxx if it can't + * find one. It will also exclusively target functions that have + * the "OnDemand" flag. + */ + +extern int pmf_call_function(struct device_node *target, const char *name, + struct pmf_args *args); + + +/* + * For low latency interrupt usage, you can lookup for on-demand functions + * using the functions below + */ + +extern struct pmf_function *pmf_find_function(struct device_node *target, + const char *name); + +extern struct pmf_function * pmf_get_function(struct pmf_function *func); +extern void pmf_put_function(struct pmf_function *func); + +extern int pmf_call_one(struct pmf_function *func, struct pmf_args *args); + + +/* Suspend/resume code called by via-pmu directly for now */ +extern void pmac_pfunc_base_suspend(void); +extern void pmac_pfunc_base_resume(void); + +#endif /* __PMAC_PFUNC_H__ */ -- cgit v1.2.3 From 9a699aefa87cb0379a67741926820c9271d748a9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 7 Jan 2006 11:45:28 +1100 Subject: [PATCH] 4/5 powerpc: Add cpufreq support for all desktop G5 This patch adds cpufreq support for all desktop "tower" G5 models. The only G5 models still lacking cpufreq support at this point are the Xserve and possibly the new iMac iSight (not tested). I'll have those added soon. That patch uses the new platform functions interpreter to implement frequency and voltage switching on most models. Note that in order to find the low frequency value, I had to hack something that might now work properly on all models, so if the frequency value reported when running low speed looks bogus to you, please report it to me. (Appart from a bogus reported value, things should work fine). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/cpufreq_64.c | 496 ++++++++++++++++++++++++--- 1 file changed, 449 insertions(+), 47 deletions(-) diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c index 39150342c6f1..a4b50c4109c2 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_64.c +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -28,6 +28,7 @@ #include #include #include +#include #undef DEBUG @@ -85,6 +86,10 @@ static u32 *g5_pmode_data; static int g5_pmode_max; static int g5_pmode_cur; +static void (*g5_switch_volt)(int speed_mode); +static int (*g5_switch_freq)(int speed_mode); +static int (*g5_query_freq)(void); + static DECLARE_MUTEX(g5_switch_mutex); @@ -92,9 +97,11 @@ static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */ static int g5_fvt_count; /* number of op. points */ static int g5_fvt_cur; /* current op. point */ -/* ----------------- real hardware interface */ +/* + * SMU based voltage switching for Neo2 platforms + */ -static void g5_switch_volt(int speed_mode) +static void g5_smu_switch_volt(int speed_mode) { struct smu_simple_cmd cmd; @@ -105,26 +112,57 @@ static void g5_switch_volt(int speed_mode) wait_for_completion(&comp); } -static int g5_switch_freq(int speed_mode) +/* + * Platform function based voltage/vdnap switching for Neo2 + */ + +static struct pmf_function *pfunc_set_vdnap0; +static struct pmf_function *pfunc_vdnap0_complete; + +static void g5_vdnap_switch_volt(int speed_mode) { - struct cpufreq_freqs freqs; - int to; + struct pmf_args args; + u32 slew, done = 0; + unsigned long timeout; - if (g5_pmode_cur == speed_mode) - return 0; + slew = (speed_mode == CPUFREQ_LOW) ? 1 : 0; + args.count = 1; + args.u[0].p = &slew; - down(&g5_switch_mutex); + pmf_call_one(pfunc_set_vdnap0, &args); - freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency; - freqs.new = g5_cpu_freqs[speed_mode].frequency; - freqs.cpu = 0; + /* It's an irq GPIO so we should be able to just block here, + * I'll do that later after I've properly tested the IRQ code for + * platform functions + */ + timeout = jiffies + HZ/10; + while(!time_after(jiffies, timeout)) { + args.count = 1; + args.u[0].p = &done; + pmf_call_one(pfunc_vdnap0_complete, &args); + if (done) + break; + msleep(1); + } + if (done == 0) + printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n"); +} - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + +/* + * SCOM based frequency switching for 970FX rev3 + */ +static int g5_scom_switch_freq(int speed_mode) +{ + unsigned long flags; + int to; /* If frequency is going up, first ramp up the voltage */ if (speed_mode < g5_pmode_cur) g5_switch_volt(speed_mode); + local_irq_save(flags); + /* Clear PCR high */ scom970_write(SCOM_PCR, 0); /* Clear PCR low */ @@ -147,6 +185,8 @@ static int g5_switch_freq(int speed_mode) udelay(100); } + local_irq_restore(flags); + /* If frequency is going down, last ramp the voltage */ if (speed_mode > g5_pmode_cur) g5_switch_volt(speed_mode); @@ -154,14 +194,10 @@ static int g5_switch_freq(int speed_mode) g5_pmode_cur = speed_mode; ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - up(&g5_switch_mutex); - return 0; } -static int g5_query_freq(void) +static int g5_scom_query_freq(void) { unsigned long psr = scom970_read(SCOM_PSR); int i; @@ -173,7 +209,104 @@ static int g5_query_freq(void) return i; } -/* ----------------- cpufreq bookkeeping */ +/* + * Platform function based voltage switching for PowerMac7,2 & 7,3 + */ + +static struct pmf_function *pfunc_cpu0_volt_high; +static struct pmf_function *pfunc_cpu0_volt_low; +static struct pmf_function *pfunc_cpu1_volt_high; +static struct pmf_function *pfunc_cpu1_volt_low; + +static void g5_pfunc_switch_volt(int speed_mode) +{ + if (speed_mode == CPUFREQ_HIGH) { + if (pfunc_cpu0_volt_high) + pmf_call_one(pfunc_cpu0_volt_high, NULL); + if (pfunc_cpu1_volt_high) + pmf_call_one(pfunc_cpu1_volt_high, NULL); + } else { + if (pfunc_cpu0_volt_low) + pmf_call_one(pfunc_cpu0_volt_low, NULL); + if (pfunc_cpu1_volt_low) + pmf_call_one(pfunc_cpu1_volt_low, NULL); + } + msleep(10); /* should be faster , to fix */ +} + +/* + * Platform function based frequency switching for PowerMac7,2 & 7,3 + */ + +static struct pmf_function *pfunc_cpu_setfreq_high; +static struct pmf_function *pfunc_cpu_setfreq_low; +static struct pmf_function *pfunc_cpu_getfreq; +static struct pmf_function *pfunc_slewing_done;; + +static int g5_pfunc_switch_freq(int speed_mode) +{ + struct pmf_args args; + u32 done = 0; + unsigned long timeout; + + /* If frequency is going up, first ramp up the voltage */ + if (speed_mode < g5_pmode_cur) + g5_switch_volt(speed_mode); + + /* Do it */ + if (speed_mode == CPUFREQ_HIGH) + pmf_call_one(pfunc_cpu_setfreq_high, NULL); + else + pmf_call_one(pfunc_cpu_setfreq_low, NULL); + + /* It's an irq GPIO so we should be able to just block here, + * I'll do that later after I've properly tested the IRQ code for + * platform functions + */ + timeout = jiffies + HZ/10; + while(!time_after(jiffies, timeout)) { + args.count = 1; + args.u[0].p = &done; + pmf_call_one(pfunc_slewing_done, &args); + if (done) + break; + msleep(1); + } + if (done == 0) + printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n"); + + /* If frequency is going down, last ramp the voltage */ + if (speed_mode > g5_pmode_cur) + g5_switch_volt(speed_mode); + + g5_pmode_cur = speed_mode; + ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul; + + return 0; +} + +static int g5_pfunc_query_freq(void) +{ + struct pmf_args args; + u32 val = 0; + + args.count = 1; + args.u[0].p = &val; + pmf_call_one(pfunc_cpu_getfreq, &args); + return val ? CPUFREQ_HIGH : CPUFREQ_LOW; +} + +/* + * Fake voltage switching for platforms with missing support + */ + +static void g5_dummy_switch_volt(int speed_mode) +{ +} + +/* + * Common interface to the cpufreq core + */ static int g5_cpufreq_verify(struct cpufreq_policy *policy) { @@ -183,13 +316,30 @@ static int g5_cpufreq_verify(struct cpufreq_policy *policy) static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int newstate = 0; + unsigned int newstate = 0; + struct cpufreq_freqs freqs; + int rc; if (cpufreq_frequency_table_target(policy, g5_cpu_freqs, target_freq, relation, &newstate)) return -EINVAL; - return g5_switch_freq(newstate); + if (g5_pmode_cur == newstate) + return 0; + + down(&g5_switch_mutex); + + freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency; + freqs.new = g5_cpu_freqs[newstate].frequency; + freqs.cpu = 0; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + rc = g5_switch_freq(newstate); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + up(&g5_switch_mutex); + + return rc; } static unsigned int g5_cpufreq_get_speed(unsigned int cpu) @@ -205,6 +355,7 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; + policy->cpus = cpu_possible_map; cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu); return cpufreq_frequency_table_cpuinfo(policy, @@ -224,19 +375,39 @@ static struct cpufreq_driver g5_cpufreq_driver = { }; -static int __init g5_cpufreq_init(void) +static int __init g5_neo2_cpufreq_init(struct device_node *cpus) { struct device_node *cpunode; unsigned int psize, ssize; - struct smu_sdbp_header *shdr; unsigned long max_freq; - u32 *valp; + char *freq_method, *volt_method; + u32 *valp, pvr_hi; + int use_volts_vdnap = 0; + int use_volts_smu = 0; int rc = -ENODEV; - /* Look for CPU and SMU nodes */ - cpunode = of_find_node_by_type(NULL, "cpu"); - if (!cpunode) { - DBG("No CPU node !\n"); + /* Check supported platforms */ + if (machine_is_compatible("PowerMac8,1") || + machine_is_compatible("PowerMac8,2") || + machine_is_compatible("PowerMac9,1")) + use_volts_smu = 1; + else if (machine_is_compatible("PowerMac11,2")) + use_volts_vdnap = 1; + else + return -ENODEV; + + /* Get first CPU node */ + for (cpunode = NULL; + (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { + u32 *reg = + (u32 *)get_property(cpunode, "reg", NULL); + if (reg == NULL || (*reg) != 0) + continue; + if (!strcmp(cpunode->type, "cpu")) + break; + } + if (cpunode == NULL) { + printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n"); return -ENODEV; } @@ -246,8 +417,9 @@ static int __init g5_cpufreq_init(void) DBG("No cpu-version property !\n"); goto bail_noprops; } - if (((*valp) >> 16) != 0x3c) { - DBG("Wrong CPU version: %08x\n", *valp); + pvr_hi = (*valp) >> 16; + if (pvr_hi != 0x3c && pvr_hi != 0x44) { + printk(KERN_ERR "cpufreq: Unsupported CPU version\n"); goto bail_noprops; } @@ -259,18 +431,50 @@ static int __init g5_cpufreq_init(void) } g5_pmode_max = psize / sizeof(u32) - 1; - /* Look for the FVT table */ - shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); - if (!shdr) - goto bail_noprops; - g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1]; - ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header); - g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt); - g5_fvt_cur = 0; - - /* Sanity checking */ - if (g5_fvt_count < 1 || g5_pmode_max < 1) - goto bail_noprops; + if (use_volts_smu) { + struct smu_sdbp_header *shdr; + + /* Look for the FVT table */ + shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (!shdr) + goto bail_noprops; + g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1]; + ssize = (shdr->len * sizeof(u32)) - + sizeof(struct smu_sdbp_header); + g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt); + g5_fvt_cur = 0; + + /* Sanity checking */ + if (g5_fvt_count < 1 || g5_pmode_max < 1) + goto bail_noprops; + + g5_switch_volt = g5_smu_switch_volt; + volt_method = "SMU"; + } else if (use_volts_vdnap) { + struct device_node *root; + + root = of_find_node_by_path("/"); + if (root == NULL) { + printk(KERN_ERR "cpufreq: Can't find root of " + "device tree\n"); + goto bail_noprops; + } + pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0"); + pfunc_vdnap0_complete = + pmf_find_function(root, "slewing-done"); + if (pfunc_set_vdnap0 == NULL || + pfunc_vdnap0_complete == NULL) { + printk(KERN_ERR "cpufreq: Can't find required " + "platform function\n"); + goto bail_noprops; + } + + g5_switch_volt = g5_vdnap_switch_volt; + volt_method = "GPIO"; + } else { + g5_switch_volt = g5_dummy_switch_volt; + volt_method = "none"; + } /* * From what I see, clock-frequency is always the maximal frequency. @@ -286,19 +490,23 @@ static int __init g5_cpufreq_init(void) g5_cpu_freqs[0].frequency = max_freq; g5_cpu_freqs[1].frequency = max_freq/2; - /* Check current frequency */ - g5_pmode_cur = g5_query_freq(); - if (g5_pmode_cur > 1) - /* We don't support anything but 1:1 and 1:2, fixup ... */ - g5_pmode_cur = 1; + /* Set callbacks */ + g5_switch_freq = g5_scom_switch_freq; + g5_query_freq = g5_scom_query_freq; + freq_method = "SCOM"; /* Force apply current frequency to make sure everything is in * sync (voltage is right for example). Firmware may leave us with * a strange setting ... */ - g5_switch_freq(g5_pmode_cur); + g5_switch_volt(CPUFREQ_HIGH); + msleep(10); + g5_pmode_cur = -1; + g5_switch_freq(g5_query_freq()); printk(KERN_INFO "Registering G5 CPU frequency driver\n"); + printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n", + freq_method, volt_method); printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", g5_cpu_freqs[1].frequency/1000, g5_cpu_freqs[0].frequency/1000, @@ -317,6 +525,200 @@ static int __init g5_cpufreq_init(void) return rc; } +static int __init g5_pm72_cpufreq_init(struct device_node *cpus) +{ + struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL; + u8 *eeprom = NULL; + u32 *valp; + u64 max_freq, min_freq, ih, il; + int has_volt = 1, rc = 0; + + /* Get first CPU node */ + for (cpunode = NULL; + (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { + if (!strcmp(cpunode->type, "cpu")) + break; + } + if (cpunode == NULL) { + printk(KERN_ERR "cpufreq: Can't find any CPU node\n"); + return -ENODEV; + } + + /* Lookup the cpuid eeprom node */ + cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0"); + if (cpuid != NULL) + eeprom = (u8 *)get_property(cpuid, "cpuid", NULL); + if (eeprom == NULL) { + printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n"); + rc = -ENODEV; + goto bail; + } + + /* Lookup the i2c hwclock */ + for (hwclock = NULL; + (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){ + char *loc = get_property(hwclock, "hwctrl-location", NULL); + if (loc == NULL) + continue; + if (strcmp(loc, "CPU CLOCK")) + continue; + if (!get_property(hwclock, "platform-get-frequency", NULL)) + continue; + break; + } + if (hwclock == NULL) { + printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n"); + rc = -ENODEV; + goto bail; + } + + DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name); + + /* Now get all the platform functions */ + pfunc_cpu_getfreq = + pmf_find_function(hwclock, "get-frequency"); + pfunc_cpu_setfreq_high = + pmf_find_function(hwclock, "set-frequency-high"); + pfunc_cpu_setfreq_low = + pmf_find_function(hwclock, "set-frequency-low"); + pfunc_slewing_done = + pmf_find_function(hwclock, "slewing-done"); + pfunc_cpu0_volt_high = + pmf_find_function(hwclock, "set-voltage-high-0"); + pfunc_cpu0_volt_low = + pmf_find_function(hwclock, "set-voltage-low-0"); + pfunc_cpu1_volt_high = + pmf_find_function(hwclock, "set-voltage-high-1"); + pfunc_cpu1_volt_low = + pmf_find_function(hwclock, "set-voltage-low-1"); + + /* Check we have minimum requirements */ + if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL || + pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) { + printk(KERN_ERR "cpufreq: Can't find platform functions !\n"); + rc = -ENODEV; + goto bail; + } + + /* Check that we have complete sets */ + if (pfunc_cpu0_volt_high == NULL || pfunc_cpu0_volt_low == NULL) { + pmf_put_function(pfunc_cpu0_volt_high); + pmf_put_function(pfunc_cpu0_volt_low); + pfunc_cpu0_volt_high = pfunc_cpu0_volt_low = NULL; + has_volt = 0; + } + if (!has_volt || + pfunc_cpu1_volt_high == NULL || pfunc_cpu1_volt_low == NULL) { + pmf_put_function(pfunc_cpu1_volt_high); + pmf_put_function(pfunc_cpu1_volt_low); + pfunc_cpu1_volt_high = pfunc_cpu1_volt_low = NULL; + } + + /* Note: The device tree also contains a "platform-set-values" + * function for which I haven't quite figured out the usage. It + * might have to be called on init and/or wakeup, I'm not too sure + * but things seem to work fine without it so far ... + */ + + /* Get max frequency from device-tree */ + valp = (u32 *)get_property(cpunode, "clock-frequency", NULL); + if (!valp) { + printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n"); + rc = -ENODEV; + goto bail; + } + + max_freq = (*valp)/1000; + + /* Now calculate reduced frequency by using the cpuid input freq + * ratio. This requires 64 bits math unless we are willing to lose + * some precision + */ + ih = *((u32 *)(eeprom + 0x10)); + il = *((u32 *)(eeprom + 0x20)); + min_freq = 0; + if (ih != 0 && il != 0) + min_freq = (max_freq * il) / ih; + + /* Sanity check */ + if (min_freq >= max_freq || min_freq < 1000) { + printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n"); + rc = -ENODEV; + goto bail; + } + g5_cpu_freqs[0].frequency = max_freq; + g5_cpu_freqs[1].frequency = min_freq; + + /* Set callbacks */ + g5_switch_volt = g5_pfunc_switch_volt; + g5_switch_freq = g5_pfunc_switch_freq; + g5_query_freq = g5_pfunc_query_freq; + + /* Force apply current frequency to make sure everything is in + * sync (voltage is right for example). Firmware may leave us with + * a strange setting ... + */ + g5_switch_volt(CPUFREQ_HIGH); + msleep(10); + g5_pmode_cur = -1; + g5_switch_freq(g5_query_freq()); + + printk(KERN_INFO "Registering G5 CPU frequency driver\n"); + printk(KERN_INFO "Frequency method: i2c/pfunc, " + "Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none"); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", + g5_cpu_freqs[1].frequency/1000, + g5_cpu_freqs[0].frequency/1000, + g5_cpu_freqs[g5_pmode_cur].frequency/1000); + + rc = cpufreq_register_driver(&g5_cpufreq_driver); + bail: + if (rc != 0) { + pmf_put_function(pfunc_cpu_getfreq); + pmf_put_function(pfunc_cpu_setfreq_high); + pmf_put_function(pfunc_cpu_setfreq_low); + pmf_put_function(pfunc_slewing_done); + pmf_put_function(pfunc_cpu0_volt_high); + pmf_put_function(pfunc_cpu0_volt_low); + pmf_put_function(pfunc_cpu1_volt_high); + pmf_put_function(pfunc_cpu1_volt_low); + } + of_node_put(hwclock); + of_node_put(cpuid); + of_node_put(cpunode); + + return rc; +} + +static int __init g5_rm31_cpufreq_init(struct device_node *cpus) +{ + /* NYI */ + return 0; +} + +static int __init g5_cpufreq_init(void) +{ + struct device_node *cpus; + int rc; + + cpus = of_find_node_by_path("/cpus"); + if (cpus == NULL) { + DBG("No /cpus node !\n"); + return -ENODEV; + } + + if (machine_is_compatible("PowerMac7,2") || + machine_is_compatible("PowerMac7,3")) + rc = g5_pm72_cpufreq_init(cpus); + else if (machine_is_compatible("RackMac3,1")) + rc = g5_rm31_cpufreq_init(cpus); + else + rc = g5_neo2_cpufreq_init(cpus); + + of_node_put(cpus); + return rc; +} + module_init(g5_cpufreq_init); -- cgit v1.2.3 From 32a33994d513606d29e87e152deb67ba5f3c8e82 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 9 Jan 2006 15:41:31 +1100 Subject: [PATCH] ppc64: Fix oprofile when compiled as a module My recent changes to oprofile broke it when built as a module. Fix it by using an enum instead of a function pointer. This way we still retain the oprofile configuration in the cputable. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 104 +++++++++++------------------------------ arch/powerpc/oprofile/common.c | 26 ++++++++++- include/asm-powerpc/cputable.h | 11 ++++- 3 files changed, 59 insertions(+), 82 deletions(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 2f82a2091440..2a16f4a192ee 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -78,10 +78,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/power3", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = RS64, }, { /* Power3+ */ .pvr_mask = 0xffff0000, @@ -93,10 +91,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/power3", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = RS64, }, { /* Northstar */ .pvr_mask = 0xffff0000, @@ -108,10 +104,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = RS64, }, { /* Pulsar */ .pvr_mask = 0xffff0000, @@ -123,10 +117,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = RS64, }, { /* I-star */ .pvr_mask = 0xffff0000, @@ -138,10 +130,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = RS64, }, { /* S-star */ .pvr_mask = 0xffff0000, @@ -153,10 +143,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = RS64, }, { /* Power4 */ .pvr_mask = 0xffff0000, @@ -168,10 +156,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/power4", - .oprofile_model = &op_model_rs64, -#endif + .oprofile_type = POWER4, }, { /* Power4+ */ .pvr_mask = 0xffff0000, @@ -183,10 +169,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/power4", - .oprofile_model = &op_model_power4, -#endif + .oprofile_type = POWER4, }, { /* PPC970 */ .pvr_mask = 0xffff0000, @@ -199,10 +183,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif + .oprofile_type = POWER4, }, #endif /* CONFIG_PPC64 */ #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4) @@ -221,10 +203,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 8, .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif + .oprofile_type = POWER4, }, #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */ #ifdef CONFIG_PPC64 @@ -238,10 +218,8 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif + .oprofile_type = POWER4, }, { /* Power5 GR */ .pvr_mask = 0xffff0000, @@ -253,10 +231,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 6, .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/power5", - .oprofile_model = &op_model_power4, -#endif + .oprofile_type = POWER4, }, { /* Power5 GS */ .pvr_mask = 0xffff0000, @@ -268,10 +244,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 128, .num_pmcs = 6, .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc64/power5", - .oprofile_model = &op_model_power4, -#endif + .oprofile_type = POWER4, }, { /* Cell Broadband Engine */ .pvr_mask = 0xffff0000, @@ -546,10 +520,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7450 2.1 */ .pvr_mask = 0xffffffff, @@ -561,10 +533,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7450 2.3 and newer */ .pvr_mask = 0xffff0000, @@ -576,10 +546,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7455 rev 1.x */ .pvr_mask = 0xffffff00, @@ -591,10 +559,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7455 rev 2.0 */ .pvr_mask = 0xffffffff, @@ -606,10 +572,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7455 others */ .pvr_mask = 0xffff0000, @@ -621,10 +585,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7447/7457 Rev 1.0 */ .pvr_mask = 0xffffffff, @@ -636,10 +598,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7447/7457 Rev 1.1 */ .pvr_mask = 0xffffffff, @@ -651,10 +611,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7447/7457 Rev 1.2 and later */ .pvr_mask = 0xffff0000, @@ -666,10 +624,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7447A */ .pvr_mask = 0xffff0000, @@ -681,10 +637,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 7448 */ .pvr_mask = 0xffff0000, @@ -696,10 +650,8 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 6, .cpu_setup = __setup_cpu_745x, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/7450", - .oprofile_model = &op_model_7450, -#endif + .oprofile_type = G4, }, { /* 82xx (8240, 8245, 8260 are all 603e cores) */ .pvr_mask = 0x7fff0000, @@ -1023,10 +975,8 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/e500", - .oprofile_model = &op_model_fsl_booke, -#endif + .oprofile_type = BOOKE, }, { /* e500v2 */ .pvr_mask = 0xffff0000, @@ -1040,10 +990,8 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .num_pmcs = 4, -#ifdef CONFIG_OPROFILE .oprofile_cpu_type = "ppc/e500", - .oprofile_model = &op_model_fsl_booke, -#endif + .oprofile_type = BOOKE, }, #endif #if !CLASSIC_PPC diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index a370778b68dd..71615eb70b2b 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -135,9 +135,31 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) int __init oprofile_arch_init(struct oprofile_operations *ops) { - if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type) + if (!cur_cpu_spec->oprofile_cpu_type) return -ENODEV; - model = cur_cpu_spec->oprofile_model; + + switch (cur_cpu_spec->oprofile_type) { +#ifdef CONFIG_PPC64 + case RS64: + model = &op_model_rs64; + break; + case POWER4: + model = &op_model_power4; + break; +#else + case G4: + model = &op_model_7450; + break; +#endif +#ifdef CONFIG_FSL_BOOKE + case BOOKE: + model = &op_model_fsl_booke; + break; +#endif + default: + return -ENODEV; + } + model->num_counters = cur_cpu_spec->num_pmcs; ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h index d8798f31b360..ef6ead34a773 100644 --- a/include/asm-powerpc/cputable.h +++ b/include/asm-powerpc/cputable.h @@ -27,10 +27,17 @@ * via the mkdefs mechanism. */ struct cpu_spec; -struct op_powerpc_model; typedef void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec); +enum powerpc_oprofile_type { + INVALID = 0, + RS64 = 1, + POWER4 = 2, + G4 = 3, + BOOKE = 4, +}; + struct cpu_spec { /* CPU is matched via (PVR & pvr_mask) == pvr_value */ unsigned int pvr_mask; @@ -56,7 +63,7 @@ struct cpu_spec { char *oprofile_cpu_type; /* Processor specific oprofile operations */ - struct op_powerpc_model *oprofile_model; + enum powerpc_oprofile_type oprofile_type; }; extern struct cpu_spec *cur_cpu_spec; -- cgit v1.2.3 From 834608f71a323b90f928d05c64d24df436df3011 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 9 Jan 2006 15:42:30 +1100 Subject: [PATCH] ppc64: POWER5+ oprofile support POWER5+ adds new PMU groups and as such needs to be treated differently by oprofile userspace. Change it to report itself as power5+. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/cputable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 2a16f4a192ee..43c74a6b07b1 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -237,14 +237,14 @@ struct cpu_spec cpu_specs[] = { { /* Power5 GS */ .pvr_mask = 0xffff0000, .pvr_value = 0x003b0000, - .cpu_name = "POWER5 (gs)", + .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, .cpu_setup = __setup_cpu_power4, - .oprofile_cpu_type = "ppc64/power5", + .oprofile_cpu_type = "ppc64/power5+", .oprofile_type = POWER4, }, { /* Cell Broadband Engine */ -- cgit v1.2.3 From bce6c5fd8cc5d3f8d02fd34a24b591fc3e23a775 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 9 Jan 2006 15:47:04 +1100 Subject: [PATCH] powerpc: DABR exceptions should report the address not the PC When taking a DABR exception we were reporting the PC. It makes more sense to report the address that caused the exception, and the gdb guys would like it that way. Signed-off-by: Anton Blanchard Signed-off-by: Paul Mackerras --- arch/powerpc/mm/fault.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 93d4fbfdb724..a4815d316722 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -81,7 +81,8 @@ static int store_updates_sp(struct pt_regs *regs) } #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) -static void do_dabr(struct pt_regs *regs, unsigned long error_code) +static void do_dabr(struct pt_regs *regs, unsigned long address, + unsigned long error_code) { siginfo_t info; @@ -99,7 +100,7 @@ static void do_dabr(struct pt_regs *regs, unsigned long error_code) info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_HWBKPT; - info.si_addr = (void __user *)regs->nip; + info.si_addr = (void __user *)address; force_sig_info(SIGTRAP, &info, current); } #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ @@ -159,7 +160,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) if (error_code & DSISR_DABRMATCH) { /* DABR match */ - do_dabr(regs, error_code); + do_dabr(regs, address, error_code); return 0; } #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ -- cgit v1.2.3 From 0a498d96a3324c16add35da0435bc7c13b6c6f3f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 9 Jan 2006 20:17:01 +1100 Subject: powerpc: set CONFIG_PPC_OF=y always for ARCH=powerpc The CONFIG_PPC_OF symbol is used to mean that the firmware device tree access functions are available. Since we always have a device tree with ARCH=powerpc, make CONFIG_PPC_OF always Y for ARCH=powerpc. This fixes some compile errors reported by Kumar Gala, but in a different way to his patch. This also makes prom_parse.o be compiled only if CONFIG_PPC_OF so that non-OF ARCH=ppc platforms will compile. Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 5 +---- arch/powerpc/kernel/Makefile | 5 ++--- arch/powerpc/kernel/head_32.S | 2 ++ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5692edb3491e..427ae0f3e8a9 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -329,9 +329,7 @@ config PPC_CELL select MMIO_NVRAM config PPC_OF - bool - depends on PPC_MULTIPLATFORM # for now - default y + def_bool y config XICS depends on PPC_PSERIES @@ -399,7 +397,6 @@ config IBMVIO config IBMEBUS depends on PPC_PSERIES bool "Support for GX bus based adapters" - default y help Bus device driver for GX bus based adapters. diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index a852b379d9eb..45b362ffa795 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -12,8 +12,7 @@ CFLAGS_btext.o += -fPIC endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ - irq.o align.o signal_32.o pmc.o vdso.o \ - prom_parse.o + irq.o align.o signal_32.o pmc.o vdso.o obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ signal_64.o ptrace32.o systbl.o \ @@ -22,7 +21,7 @@ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o obj-$(CONFIG_POWER4) += idle_power4.o -obj-$(CONFIG_PPC_OF) += of_device.o +obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o procfs-$(CONFIG_PPC64) := proc_ppc64.o obj-$(CONFIG_PROC_FS) += $(procfs-y) rtaspci-$(CONFIG_PPC64) := rtas_pci.o diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index bf37ef2b3aac..03b25f9359f8 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -120,10 +120,12 @@ __start: * because OF may have I/O devices mapped into that area * (particularly on CHRP). */ +#ifdef CONFIG_PPC_MULTIPLATFORM cmpwi 0,r5,0 beq 1f bl prom_init trap +#endif /* * Check for BootX signature when supporting PowerMac and branch to -- cgit v1.2.3 From e0fa93d6e6f0f36f39b813e561dbb890c58da58f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 9 Jan 2006 18:19:49 +1100 Subject: [PATCH] powerpc: Don't use KERNELBASE in add_memory() In add_memory() we should be using __va() to get a virtual address. Spotted by Mike Kravetz. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/mm/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 5e5bff5616a8..15aac0d78dfa 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -125,7 +125,7 @@ int __devinit add_memory(u64 start, u64 size) nid = hot_add_scn_to_nid(start); pgdata = NODE_DATA(nid); - start += KERNELBASE; + start = __va(start); create_section_mapping(start, start + size); /* this should work for most non-highmem platforms */ -- cgit v1.2.3 From be42d5fa3772241b8ecebd443f1fb36247959c54 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 9 Jan 2006 21:32:42 +1100 Subject: powerpc: unbreak iSeries compilation again We don't set CONFIG_PPC_MULTIPLATFORM on iSeries (yet). Avoid compiling in the prom_init stuff on iSeries. Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/head_64.S | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 45b362ffa795..6e03b595b6c8 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -49,7 +49,7 @@ obj-y += process.o init_task.o time.o \ prom.o traps.o setup-common.o udbg.o obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o -obj-$(CONFIG_PPC_OF) += prom_init.o +obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_6xx) += idle_6xx.o diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 7f56f9bf76df..1c066d125375 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -1506,11 +1506,13 @@ _STATIC(__mmu_off) * */ _GLOBAL(__start_initialization_multiplatform) +#ifdef CONFIG_PPC_MULTIPLATFORM /* * Are we booted from a PROM Of-type client-interface ? */ cmpldi cr0,r5,0 bne .__boot_from_prom /* yes -> prom */ +#endif /* Save parameters */ mr r31,r3 @@ -1531,6 +1533,7 @@ _GLOBAL(__start_initialization_multiplatform) bl .__mmu_off b .__after_prom_start +#ifdef CONFIG_PPC_MULTIPLATFORM _STATIC(__boot_from_prom) /* Save parameters */ mr r31,r3 @@ -1563,6 +1566,7 @@ _STATIC(__boot_from_prom) bl .prom_init /* We never return */ trap +#endif /* * At this point, r3 contains the physical address we are running at, -- cgit v1.2.3 From 66a3454e1a6d3f2096e6ecfa59572b34caca4942 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 Jan 2006 12:57:05 +0000 Subject: [ARM] Update mach-types Signed-off-by: Russell King --- arch/arm/tools/mach-types | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 465487470d0e..d0f9bb5e9023 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Fri Nov 25 14:43:04 2005 +# Last update: Mon Jan 9 12:56:42 2006 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -910,3 +910,31 @@ mbus MACH_MBUS MBUS 896 nadia2vb MACH_NADIA2VB NADIA2VB 897 r1000 MACH_R1000 R1000 898 hw90250 MACH_HW90250 HW90250 899 +omap_2430sdp MACH_OMAP_2430SDP OMAP_2430SDP 900 +davinci_evm MACH_DAVINCI_EVM DAVINCI_EVM 901 +omap_tornado MACH_OMAP_TORNADO OMAP_TORNADO 902 +olocreek MACH_OLOCREEK OLOCREEK 903 +palmz72 MACH_PALMZ72 PALMZ72 904 +nxdb500 MACH_NXDB500 NXDB500 905 +apf9328 MACH_APF9328 APF9328 906 +omap_wipoq MACH_OMAP_WIPOQ OMAP_WIPOQ 907 +omap_twip MACH_OMAP_TWIP OMAP_TWIP 908 +xscale_treo650 MACH_XSCALE_PALMTREO650 XSCALE_PALMTREO650 909 +acumen MACH_ACUMEN ACUMEN 910 +xp100 MACH_XP100 XP100 911 +fs2410 MACH_FS2410 FS2410 912 +pxa270_cerf MACH_PXA270_CERF PXA270_CERF 913 +sq2ftlpalm MACH_SQ2FTLPALM SQ2FTLPALM 914 +bsemserver MACH_BSEMSERVER BSEMSERVER 915 +netclient MACH_NETCLIENT NETCLIENT 916 +xscale_palmtt5 MACH_XSCALE_PALMTT5 XSCALE_PALMTT5 917 +xscale_palmtc MACH_OMAP_PALMTC OMAP_PALMTC 918 +omap_apollon MACH_OMAP_APOLLON OMAP_APOLLON 919 +argonlvevb MACH_ARGONLVEVB ARGONLVEVB 920 +rea_2d MACH_REA_2D REA_2D 921 +eti3e524 MACH_TI3E524 TI3E524 922 +ateb9200 MACH_ATEB9200 ATEB9200 923 +auckland MACH_AUCKLAND AUCKLAND 924 +ak3220m MACH_AK3320M AK3320M 925 +duramax MACH_DURAMAX DURAMAX 926 +n35 MACH_N35 N35 927 -- cgit v1.2.3 From 63dcf0ad2a624a36656c10491fc3326cfe199f5e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 Jan 2006 13:32:56 +0000 Subject: [ARM] Remove CONFIG_ARCH_CAMELOT from defconfigs EPXA10DB has gone, no need to keep the symbol in the defconfigs. Signed-off-by: Russell King --- arch/arm/configs/assabet_defconfig | 1 - arch/arm/configs/badge4_defconfig | 1 - arch/arm/configs/bast_defconfig | 1 - arch/arm/configs/cerfcube_defconfig | 1 - arch/arm/configs/clps7500_defconfig | 1 - arch/arm/configs/collie_defconfig | 1 - arch/arm/configs/corgi_defconfig | 1 - arch/arm/configs/ebsa110_defconfig | 1 - arch/arm/configs/edb7211_defconfig | 1 - arch/arm/configs/enp2611_defconfig | 1 - arch/arm/configs/ep80219_defconfig | 1 - arch/arm/configs/footbridge_defconfig | 1 - arch/arm/configs/fortunet_defconfig | 1 - arch/arm/configs/h3600_defconfig | 1 - arch/arm/configs/h7201_defconfig | 1 - arch/arm/configs/h7202_defconfig | 1 - arch/arm/configs/hackkit_defconfig | 1 - arch/arm/configs/integrator_defconfig | 1 - arch/arm/configs/iq31244_defconfig | 1 - arch/arm/configs/iq80321_defconfig | 1 - arch/arm/configs/iq80331_defconfig | 1 - arch/arm/configs/iq80332_defconfig | 1 - arch/arm/configs/ixdp2400_defconfig | 1 - arch/arm/configs/ixdp2401_defconfig | 1 - arch/arm/configs/ixdp2800_defconfig | 1 - arch/arm/configs/ixdp2801_defconfig | 1 - arch/arm/configs/ixp4xx_defconfig | 1 - arch/arm/configs/jornada720_defconfig | 1 - arch/arm/configs/lart_defconfig | 1 - arch/arm/configs/lpd7a400_defconfig | 1 - arch/arm/configs/lpd7a404_defconfig | 1 - arch/arm/configs/lubbock_defconfig | 1 - arch/arm/configs/lusl7200_defconfig | 1 - arch/arm/configs/mainstone_defconfig | 1 - arch/arm/configs/mx1ads_defconfig | 1 - arch/arm/configs/neponset_defconfig | 1 - arch/arm/configs/netwinder_defconfig | 1 - arch/arm/configs/omap_h2_1610_defconfig | 1 - arch/arm/configs/pleb_defconfig | 1 - arch/arm/configs/pxa255-idp_defconfig | 1 - arch/arm/configs/realview_defconfig | 1 - arch/arm/configs/rpc_defconfig | 1 - arch/arm/configs/s3c2410_defconfig | 1 - arch/arm/configs/shannon_defconfig | 1 - arch/arm/configs/shark_defconfig | 1 - arch/arm/configs/simpad_defconfig | 1 - arch/arm/configs/smdk2410_defconfig | 1 - arch/arm/configs/spitz_defconfig | 1 - arch/arm/configs/versatile_defconfig | 1 - 49 files changed, 49 deletions(-) diff --git a/arch/arm/configs/assabet_defconfig b/arch/arm/configs/assabet_defconfig index ccbb4c0d58c4..089c9d598409 100644 --- a/arch/arm/configs/assabet_defconfig +++ b/arch/arm/configs/assabet_defconfig @@ -63,7 +63,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig index 5d92af975d87..cfe6bd8e81cd 100644 --- a/arch/arm/configs/badge4_defconfig +++ b/arch/arm/configs/badge4_defconfig @@ -66,7 +66,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/bast_defconfig b/arch/arm/configs/bast_defconfig index 35e3a99bcbb6..6886001b5366 100644 --- a/arch/arm/configs/bast_defconfig +++ b/arch/arm/configs/bast_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/cerfcube_defconfig b/arch/arm/configs/cerfcube_defconfig index d8fe0f40408f..f81a60005cd3 100644 --- a/arch/arm/configs/cerfcube_defconfig +++ b/arch/arm/configs/cerfcube_defconfig @@ -65,7 +65,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/clps7500_defconfig b/arch/arm/configs/clps7500_defconfig index 908758371405..af9ae5389131 100644 --- a/arch/arm/configs/clps7500_defconfig +++ b/arch/arm/configs/clps7500_defconfig @@ -57,7 +57,6 @@ CONFIG_ARCH_CLPS7500=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig index 40dfe07a8bce..15468a0cf70e 100644 --- a/arch/arm/configs/collie_defconfig +++ b/arch/arm/configs/collie_defconfig @@ -71,7 +71,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index 06229026f78b..3c3461e83398 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -87,7 +87,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/ebsa110_defconfig b/arch/arm/configs/ebsa110_defconfig index 6f61929b97a8..afcfff6140f2 100644 --- a/arch/arm/configs/ebsa110_defconfig +++ b/arch/arm/configs/ebsa110_defconfig @@ -63,7 +63,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set CONFIG_ARCH_EBSA110=y -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/edb7211_defconfig b/arch/arm/configs/edb7211_defconfig index 78b08ed4d5f4..6ba7355ff85b 100644 --- a/arch/arm/configs/edb7211_defconfig +++ b/arch/arm/configs/edb7211_defconfig @@ -57,7 +57,6 @@ CONFIG_BASE_SMALL=0 CONFIG_ARCH_CLPS711X=y # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig index fd7c0042bcca..9592e3925c79 100644 --- a/arch/arm/configs/enp2611_defconfig +++ b/arch/arm/configs/enp2611_defconfig @@ -86,7 +86,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/ep80219_defconfig b/arch/arm/configs/ep80219_defconfig index 96342afa9c5f..fbe312e757cb 100644 --- a/arch/arm/configs/ep80219_defconfig +++ b/arch/arm/configs/ep80219_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set CONFIG_ARCH_IOP3XX=y diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig index 9737c4850721..2a612d23120b 100644 --- a/arch/arm/configs/footbridge_defconfig +++ b/arch/arm/configs/footbridge_defconfig @@ -63,7 +63,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set CONFIG_ARCH_FOOTBRIDGE=y # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/fortunet_defconfig b/arch/arm/configs/fortunet_defconfig index b6f688d850dc..65dc73a88c43 100644 --- a/arch/arm/configs/fortunet_defconfig +++ b/arch/arm/configs/fortunet_defconfig @@ -57,7 +57,6 @@ CONFIG_BASE_SMALL=0 CONFIG_ARCH_CLPS711X=y # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/h3600_defconfig b/arch/arm/configs/h3600_defconfig index b9de07de80fe..7a0da0b7facb 100644 --- a/arch/arm/configs/h3600_defconfig +++ b/arch/arm/configs/h3600_defconfig @@ -65,7 +65,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/h7201_defconfig b/arch/arm/configs/h7201_defconfig index 39c13a354541..116920aecef7 100644 --- a/arch/arm/configs/h7201_defconfig +++ b/arch/arm/configs/h7201_defconfig @@ -60,7 +60,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/h7202_defconfig b/arch/arm/configs/h7202_defconfig index fbf5c244c696..9d62ed16bf57 100644 --- a/arch/arm/configs/h7202_defconfig +++ b/arch/arm/configs/h7202_defconfig @@ -63,7 +63,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/hackkit_defconfig b/arch/arm/configs/hackkit_defconfig index fb41a36a5a68..a45b57582b86 100644 --- a/arch/arm/configs/hackkit_defconfig +++ b/arch/arm/configs/hackkit_defconfig @@ -66,7 +66,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig index 27ee76825254..d1ba7fdde818 100644 --- a/arch/arm/configs/integrator_defconfig +++ b/arch/arm/configs/integrator_defconfig @@ -65,7 +65,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set CONFIG_ARCH_INTEGRATOR=y # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/iq31244_defconfig b/arch/arm/configs/iq31244_defconfig index e71443b97390..c07628ceaf0c 100644 --- a/arch/arm/configs/iq31244_defconfig +++ b/arch/arm/configs/iq31244_defconfig @@ -65,7 +65,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set CONFIG_ARCH_IOP3XX=y diff --git a/arch/arm/configs/iq80321_defconfig b/arch/arm/configs/iq80321_defconfig index ab5ad23b27da..18fa1615fdfd 100644 --- a/arch/arm/configs/iq80321_defconfig +++ b/arch/arm/configs/iq80321_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set CONFIG_ARCH_IOP3XX=y diff --git a/arch/arm/configs/iq80331_defconfig b/arch/arm/configs/iq80331_defconfig index bb536133ef87..f50035de1fff 100644 --- a/arch/arm/configs/iq80331_defconfig +++ b/arch/arm/configs/iq80331_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set CONFIG_ARCH_IOP3XX=y diff --git a/arch/arm/configs/iq80332_defconfig b/arch/arm/configs/iq80332_defconfig index 305f01f3a729..18b3f372ed68 100644 --- a/arch/arm/configs/iq80332_defconfig +++ b/arch/arm/configs/iq80332_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set CONFIG_ARCH_IOP3XX=y diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig index e6a4d2656fe5..d9d6bb86a6fa 100644 --- a/arch/arm/configs/ixdp2400_defconfig +++ b/arch/arm/configs/ixdp2400_defconfig @@ -86,7 +86,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig index 5572cf95d5f8..2dc9d499c7d7 100644 --- a/arch/arm/configs/ixdp2401_defconfig +++ b/arch/arm/configs/ixdp2401_defconfig @@ -86,7 +86,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index 0fddbde85835..4248123815e9 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -86,7 +86,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig index 89b9aa06aa91..ea8f4b478fa3 100644 --- a/arch/arm/configs/ixdp2801_defconfig +++ b/arch/arm/configs/ixdp2801_defconfig @@ -86,7 +86,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 613afab62720..4975b914f923 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/jornada720_defconfig b/arch/arm/configs/jornada720_defconfig index b88aeba82bc0..ad1048db96fb 100644 --- a/arch/arm/configs/jornada720_defconfig +++ b/arch/arm/configs/jornada720_defconfig @@ -63,7 +63,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/lart_defconfig b/arch/arm/configs/lart_defconfig index 7033829ed145..c3a932844160 100644 --- a/arch/arm/configs/lart_defconfig +++ b/arch/arm/configs/lart_defconfig @@ -62,7 +62,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/lpd7a400_defconfig b/arch/arm/configs/lpd7a400_defconfig index d64706d3ff35..67eaa26c2647 100644 --- a/arch/arm/configs/lpd7a400_defconfig +++ b/arch/arm/configs/lpd7a400_defconfig @@ -60,7 +60,6 @@ CONFIG_BASE_SMALL=0 # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/lpd7a404_defconfig b/arch/arm/configs/lpd7a404_defconfig index 87cbedfb303f..208d591ebfce 100644 --- a/arch/arm/configs/lpd7a404_defconfig +++ b/arch/arm/configs/lpd7a404_defconfig @@ -60,7 +60,6 @@ CONFIG_BASE_SMALL=0 # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig index 4bc8717c6f57..81daadcbe0ba 100644 --- a/arch/arm/configs/lubbock_defconfig +++ b/arch/arm/configs/lubbock_defconfig @@ -63,7 +63,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/lusl7200_defconfig b/arch/arm/configs/lusl7200_defconfig index 3ca64cabc92c..42f6a77bc3c0 100644 --- a/arch/arm/configs/lusl7200_defconfig +++ b/arch/arm/configs/lusl7200_defconfig @@ -62,7 +62,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/mainstone_defconfig b/arch/arm/configs/mainstone_defconfig index 153d68594beb..b112bd75bda2 100644 --- a/arch/arm/configs/mainstone_defconfig +++ b/arch/arm/configs/mainstone_defconfig @@ -63,7 +63,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/mx1ads_defconfig b/arch/arm/configs/mx1ads_defconfig index 6517d167acf0..d16f6cd6e039 100644 --- a/arch/arm/configs/mx1ads_defconfig +++ b/arch/arm/configs/mx1ads_defconfig @@ -63,7 +63,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig index 7fb1f7c7bf43..3d35255c64ed 100644 --- a/arch/arm/configs/neponset_defconfig +++ b/arch/arm/configs/neponset_defconfig @@ -65,7 +65,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/netwinder_defconfig b/arch/arm/configs/netwinder_defconfig index 6e81acf94c2f..2cae1ead9f9b 100644 --- a/arch/arm/configs/netwinder_defconfig +++ b/arch/arm/configs/netwinder_defconfig @@ -58,7 +58,6 @@ CONFIG_BASE_SMALL=0 # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set CONFIG_ARCH_FOOTBRIDGE=y # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig index 529f0f72e1e9..ee3ecbd9002d 100644 --- a/arch/arm/configs/omap_h2_1610_defconfig +++ b/arch/arm/configs/omap_h2_1610_defconfig @@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/pleb_defconfig b/arch/arm/configs/pleb_defconfig index 10fec890578d..24e8bdd4cb91 100644 --- a/arch/arm/configs/pleb_defconfig +++ b/arch/arm/configs/pleb_defconfig @@ -63,7 +63,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/pxa255-idp_defconfig b/arch/arm/configs/pxa255-idp_defconfig index 21c327883d8c..b71d31a4bb56 100644 --- a/arch/arm/configs/pxa255-idp_defconfig +++ b/arch/arm/configs/pxa255-idp_defconfig @@ -63,7 +63,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig index 0485b2f1cc20..3f1ec4e304f7 100644 --- a/arch/arm/configs/realview_defconfig +++ b/arch/arm/configs/realview_defconfig @@ -65,7 +65,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig index 19184c1010ad..b498afdc03b6 100644 --- a/arch/arm/configs/rpc_defconfig +++ b/arch/arm/configs/rpc_defconfig @@ -66,7 +66,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index 3f97590c91f2..33f31080a98c 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/shannon_defconfig b/arch/arm/configs/shannon_defconfig index e3facc4fe792..d052c8f80515 100644 --- a/arch/arm/configs/shannon_defconfig +++ b/arch/arm/configs/shannon_defconfig @@ -62,7 +62,6 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/shark_defconfig b/arch/arm/configs/shark_defconfig index 271823f0d708..c48d17062262 100644 --- a/arch/arm/configs/shark_defconfig +++ b/arch/arm/configs/shark_defconfig @@ -66,7 +66,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/simpad_defconfig b/arch/arm/configs/simpad_defconfig index 5373eeb7d578..2e5a616cc98d 100644 --- a/arch/arm/configs/simpad_defconfig +++ b/arch/arm/configs/simpad_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/smdk2410_defconfig b/arch/arm/configs/smdk2410_defconfig index 2c60865fda19..4d123d33c7df 100644 --- a/arch/arm/configs/smdk2410_defconfig +++ b/arch/arm/configs/smdk2410_defconfig @@ -58,7 +58,6 @@ CONFIG_BASE_SMALL=0 # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index 9895539533d6..d1ace3abfd8a 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -87,7 +87,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig index d72f2c754268..2687a225aa6a 100644 --- a/arch/arm/configs/versatile_defconfig +++ b/arch/arm/configs/versatile_defconfig @@ -64,7 +64,6 @@ CONFIG_KMOD=y # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_CAMELOT is not set # CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_IOP3XX is not set -- cgit v1.2.3 From 1abee6d2d1b6366df96fce1d43eefd1819e1b055 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Mon, 28 Nov 2005 09:40:20 +0100 Subject: [BLOCK][TRIVIAL] ll_rw_blk: header included twice linux/blkdev.h included twice Signed-off-by: Nicolas Kaiser Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 91d3b4828c49..c182c9f4b2c4 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -26,7 +26,6 @@ #include #include #include -#include /* * for max sense size -- cgit v1.2.3 From 769db45b73896a88d6b40e3e648dfc50a155ec93 Mon Sep 17 00:00:00 2001 From: Coywolf Qi Hunt Date: Wed, 28 Dec 2005 10:55:49 +0100 Subject: make elv_try_merge() static, kill the dead declaration of elv_try_last_merge(). Signed-off-by: Coywolf Qi Hunt Signed-off-by: Jens Axboe --- block/elevator.c | 3 +-- include/linux/elevator.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index 39dcccc82ada..99a4d7b2f8ad 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -64,7 +64,7 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) } EXPORT_SYMBOL(elv_rq_merge_ok); -inline int elv_try_merge(struct request *__rq, struct bio *bio) +static inline int elv_try_merge(struct request *__rq, struct bio *bio) { int ret = ELEVATOR_NO_MERGE; @@ -80,7 +80,6 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio) return ret; } -EXPORT_SYMBOL(elv_try_merge); static struct elevator_type *elevator_find(const char *name) { diff --git a/include/linux/elevator.h b/include/linux/elevator.h index fb80fa44c4dd..4a6f50e31c73 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -114,8 +114,6 @@ extern ssize_t elv_iosched_store(request_queue_t *, const char *, size_t); extern int elevator_init(request_queue_t *, char *); extern void elevator_exit(elevator_t *); extern int elv_rq_merge_ok(struct request *, struct bio *); -extern int elv_try_merge(struct request *, struct bio *); -extern int elv_try_last_merge(request_queue_t *, struct bio *); /* * Return values from elevator merger -- cgit v1.2.3 From 0ea60b5ad8c3630e8f44c443f173d841be7fc701 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 14:45:10 +0100 Subject: [BLOCK] bio: init ->bi_bdev in bio_init() For SG_IO requests, bio->bi_bdev may not be explicitly initialized. So make bio_init() clear the field to make sure it's always NULL or valid. Signed-off-by: Jens Axboe --- fs/bio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/bio.c b/fs/bio.c index dfe242a21eb4..7b3069589951 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -126,6 +126,7 @@ static void bio_fs_destructor(struct bio *bio) inline void bio_init(struct bio *bio) { bio->bi_next = NULL; + bio->bi_bdev = NULL; bio->bi_flags = 1 << BIO_UPTODATE; bio->bi_rw = 0; bio->bi_vcnt = 0; -- cgit v1.2.3 From 5a57be8d100c67a033ec78f00d5a0cd387da72e9 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 14:52:21 +0100 Subject: [BLOCK] scsi_ioctl: file can be NULL from ioctl_by_bdev() Signed-off-by: Jens Axboe --- block/scsi_ioctl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index c2ac36dfe4f3..18de84c8ccd8 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -190,16 +190,21 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_write(GPCMD_SET_STREAMING), }; unsigned char type = cmd_type[cmd[0]]; + int has_write_perm = 0; /* Anybody who can open the device can do a read-safe command */ if (type & CMD_READ_SAFE) return 0; + /* + * file can be NULL from ioctl_by_bdev()... + */ + if (file) + has_write_perm = file->f_mode & FMODE_WRITE; + /* Write-safe commands just require a writable open.. */ - if (type & CMD_WRITE_SAFE) { - if (file->f_mode & FMODE_WRITE) - return 0; - } + if ((type & CMD_WRITE_SAFE) && has_write_perm) + return 0; /* And root can do any command.. */ if (capable(CAP_SYS_RAWIO)) -- cgit v1.2.3 From e9368f8288338c25d8a339c91b15e17ebf33752d Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 Jan 2006 13:56:42 +0000 Subject: [ARM] Remove asm/irq.h includes from ARM drivers Many ARM drivers do not need to include asm/irq.h - remove this unnecessary include from some ARM drivers. Signed-off-by: Russell King --- drivers/amba/bus.c | 1 - drivers/input/serio/sa1111ps2.c | 1 - drivers/net/arm/ether3.c | 1 - drivers/net/arm/etherh.c | 1 - drivers/scsi/arm/acornscsi.c | 1 - drivers/scsi/arm/arxescsi.c | 1 - drivers/scsi/arm/cumana_1.c | 1 - drivers/scsi/arm/cumana_2.c | 1 - drivers/scsi/arm/eesox.c | 1 - drivers/scsi/arm/powertec.c | 1 - drivers/video/cyber2000fb.c | 1 - drivers/video/sa1100fb.c | 15 ++++++++++----- 12 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 1bbdd1693d57..889855d8d9f9 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -15,7 +15,6 @@ #include #include -#include #include #define to_amba_device(d) container_of(d, struct amba_device, dev) diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 3f0df3330fb2..ebd9976fc811 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -20,7 +20,6 @@ #include #include -#include #include #include diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 1cc53abc3a39..f1d5b1027ff7 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -69,7 +69,6 @@ #include #include #include -#include static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n"; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 942a2819576c..6a93b666eb72 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -50,7 +50,6 @@ #include #include #include -#include #include "../8390.h" diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 09ed05727bcb..dda5a5f79c53 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -146,7 +146,6 @@ #include #include -#include #include #include "../scsi.h" diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index 804125e35fc3..a28940156703 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -33,7 +33,6 @@ #include #include -#include #include #include "../scsi.h" diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index 81e266be26d0..e6c9491dc5c0 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -13,7 +13,6 @@ #include #include -#include #include #include "../scsi.h" diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 3a7a46b0dc41..583d2d8c8335 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "../scsi.h" diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index 4d1e8f52c924..3ffec7efc9d5 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 3333d7b39139..3113bdcedb13 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "../scsi.h" diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index a9300f930ef2..55a3514157ed 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -50,7 +50,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 2ea1354e439f..087e58689e4c 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -178,7 +178,6 @@ #include #include -#include #include #include #include @@ -1455,7 +1454,11 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) static int __init sa1100fb_probe(struct platform_device *pdev) { struct sa1100fb_info *fbi; - int ret; + int ret, irq; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return -EINVAL; if (!request_mem_region(0xb0100000, 0x10000, "LCD")) return -EBUSY; @@ -1470,7 +1473,7 @@ static int __init sa1100fb_probe(struct platform_device *pdev) if (ret) goto failed; - ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT, + ret = request_irq(irq, sa1100fb_handle_irq, SA_INTERRUPT, "LCD", fbi); if (ret) { printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); @@ -1492,7 +1495,7 @@ static int __init sa1100fb_probe(struct platform_device *pdev) ret = register_framebuffer(&fbi->fb); if (ret < 0) - goto failed; + goto err_free_irq; #ifdef CONFIG_CPU_FREQ fbi->freq_transition.notifier_call = sa1100fb_freq_transition; @@ -1504,7 +1507,9 @@ static int __init sa1100fb_probe(struct platform_device *pdev) /* This driver cannot be unloaded at the moment */ return 0; -failed: + err_free_irq: + free_irq(irq, fbi); + failed: platform_set_drvdata(pdev, NULL); kfree(fbi); release_mem_region(0xb0100000, 0x10000); -- cgit v1.2.3 From 50465d0da69e8d8b5493c5b752f0aa6d039c3914 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 Jan 2006 13:59:36 +0000 Subject: [ARM] Update am79c961 to use struct platform_driver Signed-off-by: Russell King --- drivers/net/arm/am79c961a.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 877891a29aaa..53e3afc1b7b7 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -668,9 +668,8 @@ static void __init am79c961_banner(void) printk(KERN_INFO "%s", version); } -static int __init am79c961_probe(struct device *_dev) +static int __init am79c961_probe(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(_dev); struct resource *res; struct net_device *dev; struct dev_priv *priv; @@ -758,15 +757,16 @@ out: return ret; } -static struct device_driver am79c961_driver = { - .name = "am79c961", - .bus = &platform_bus_type, +static struct platform_driver am79c961_driver = { .probe = am79c961_probe, + .driver = { + .name = "am79c961", + }, }; static int __init am79c961_init(void) { - return driver_register(&am79c961_driver); + return platform_driver_register(&am79c961_driver); } __initcall(am79c961_init); -- cgit v1.2.3 From 50365c57860cd931c2d806057e0987634797e9af Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 Jan 2006 14:15:14 +0000 Subject: [ARM] Make Acorn partition types depend on ACORN_PARTITION balamurugan reported a problem where it was possible to have the various Acorn partition types selected in the configuration, but ACORN_PARTITION disabled. Since ACORN_PARTITION controls whether we build fs/partitions/acorn.c, this lead to undefined references to the adfspart_check_TYPE symbols. Fix this by making the Acorn partition type symbols depend on ACORN_PARTITION. Signed-off-by: Russell King --- fs/partitions/Kconfig | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig index e227a04261ab..7490cc9208b3 100644 --- a/fs/partitions/Kconfig +++ b/fs/partitions/Kconfig @@ -21,26 +21,30 @@ config ACORN_PARTITION Support hard disks partitioned under Acorn operating systems. config ACORN_PARTITION_CUMANA - bool "Cumana partition support" if PARTITION_ADVANCED && ACORN_PARTITION + bool "Cumana partition support" if PARTITION_ADVANCED default y if ARCH_ACORN + depends on ACORN_PARTITION help Say Y here if you would like to use hard disks under Linux which were partitioned using the Cumana interface on Acorn machines. config ACORN_PARTITION_EESOX - bool "EESOX partition support" if PARTITION_ADVANCED && ACORN_PARTITION + bool "EESOX partition support" if PARTITION_ADVANCED default y if ARCH_ACORN + depends on ACORN_PARTITION config ACORN_PARTITION_ICS - bool "ICS partition support" if PARTITION_ADVANCED && ACORN_PARTITION + bool "ICS partition support" if PARTITION_ADVANCED default y if ARCH_ACORN + depends on ACORN_PARTITION help Say Y here if you would like to use hard disks under Linux which were partitioned using the ICS interface on Acorn machines. config ACORN_PARTITION_ADFS - bool "Native filecore partition support" if PARTITION_ADVANCED && ACORN_PARTITION + bool "Native filecore partition support" if PARTITION_ADVANCED default y if ARCH_ACORN + depends on ACORN_PARTITION help The Acorn Disc Filing System is the standard file system of the RiscOS operating system which runs on Acorn's ARM-based Risc PC @@ -48,15 +52,17 @@ config ACORN_PARTITION_ADFS `Y' here, Linux will support disk partitions created under ADFS. config ACORN_PARTITION_POWERTEC - bool "PowerTec partition support" if PARTITION_ADVANCED && ACORN_PARTITION + bool "PowerTec partition support" if PARTITION_ADVANCED default y if ARCH_ACORN + depends on ACORN_PARTITION help Support reading partition tables created on Acorn machines using the PowerTec SCSI drive. config ACORN_PARTITION_RISCIX - bool "RISCiX partition support" if PARTITION_ADVANCED && ACORN_PARTITION + bool "RISCiX partition support" if PARTITION_ADVANCED default y if ARCH_ACORN + depends on ACORN_PARTITION help Once upon a time, there was a native Unix port for the Acorn series of machines called RISCiX. If you say 'Y' here, Linux will be able @@ -224,5 +230,3 @@ config EFI_PARTITION Say Y here if you would like to use hard disks under Linux which were partitioned using EFI GPT. Presently only useful on the IA-64 platform. - -# define_bool CONFIG_ACORN_PARTITION_CUMANA y -- cgit v1.2.3 From 356cebea1123804e4aa85b43ab39bbd0ac8e667c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 15:30:20 +0100 Subject: [BLOCK] Kill blk_attempt_remerge() It's a broken interface, it's done way too late. And apparently it triggers slab problems in recent kernels as well (most likely after the generic dispatch code was merged). So kill it, ide-cd is the only user of it. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 24 ------------------------ drivers/ide/ide-cd.c | 10 ---------- include/linux/blkdev.h | 1 - 3 files changed, 35 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c182c9f4b2c4..c44d6fe9f6ce 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2734,30 +2734,6 @@ static inline int attempt_front_merge(request_queue_t *q, struct request *rq) return 0; } -/** - * blk_attempt_remerge - attempt to remerge active head with next request - * @q: The &request_queue_t belonging to the device - * @rq: The head request (usually) - * - * Description: - * For head-active devices, the queue can easily be unplugged so quickly - * that proper merging is not done on the front request. This may hurt - * performance greatly for some devices. The block layer cannot safely - * do merging on that first request for these queues, but the driver can - * call this function and make it happen any way. Only the driver knows - * when it is safe to do so. - **/ -void blk_attempt_remerge(request_queue_t *q, struct request *rq) -{ - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - attempt_back_merge(q, rq); - spin_unlock_irqrestore(q->queue_lock, flags); -} - -EXPORT_SYMBOL(blk_attempt_remerge); - static void init_request_from_bio(struct request *req, struct bio *bio) { req->flags |= REQ_CMD; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index d31117eb95aa..e4d55ad32d2f 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1332,8 +1332,6 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block) if (cdrom_read_from_buffer(drive)) return ide_stopped; - blk_attempt_remerge(drive->queue, rq); - /* Clear the local sector buffer. */ info->nsectors_buffered = 0; @@ -1874,14 +1872,6 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) return ide_stopped; } - /* - * for dvd-ram and such media, it's a really big deal to get - * big writes all the time. so scour the queue and attempt to - * remerge requests, often the plugging will not have had time - * to do this properly - */ - blk_attempt_remerge(drive->queue, rq); - info->nsectors_buffered = 0; /* use dma, if possible. we don't need to check more, since we diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index fb0985377421..96b233991685 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -592,7 +592,6 @@ extern void generic_make_request(struct bio *bio); extern void blk_put_request(struct request *); extern void __blk_put_request(request_queue_t *, struct request *); extern void blk_end_sync_rq(struct request *rq, int error); -extern void blk_attempt_remerge(request_queue_t *, struct request *); extern struct request *blk_get_request(request_queue_t *, int, gfp_t); extern void blk_insert_request(request_queue_t *, struct request *, int, void *); extern void blk_requeue_request(request_queue_t *, struct request *); -- cgit v1.2.3 From ff856bad67cb65cb4dc4ef88b808804fc4265782 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 16:02:34 +0100 Subject: [BLOCK] ll_rw_blk: Enable out-of-order request completions through softirq Request completion can be a quite heavy process, since it needs to iterate through the entire request and complete the bio's it holds. This patch adds blk_complete_request() which moves this processing into a dedicated block softirq. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 106 +++++++++++++++++++++++++++++++++++++++++++++- include/linux/blkdev.h | 21 +++++++-- include/linux/interrupt.h | 1 + 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 91d3b4828c49..8e136450abc2 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include /* * for max sense size @@ -62,13 +64,15 @@ static wait_queue_head_t congestion_wqh[2] = { /* * Controlling structure to kblockd */ -static struct workqueue_struct *kblockd_workqueue; +static struct workqueue_struct *kblockd_workqueue; unsigned long blk_max_low_pfn, blk_max_pfn; EXPORT_SYMBOL(blk_max_low_pfn); EXPORT_SYMBOL(blk_max_pfn); +static DEFINE_PER_CPU(struct list_head, blk_cpu_done); + /* Amount of time in which a process may batch requests */ #define BLK_BATCH_TIME (HZ/50UL) @@ -207,6 +211,13 @@ void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn) EXPORT_SYMBOL(blk_queue_merge_bvec); +void blk_queue_softirq_done(request_queue_t *q, softirq_done_fn *fn) +{ + q->softirq_done_fn = fn; +} + +EXPORT_SYMBOL(blk_queue_softirq_done); + /** * blk_queue_make_request - define an alternate make_request function for a device * @q: the request queue for the device to be affected @@ -270,6 +281,7 @@ EXPORT_SYMBOL(blk_queue_make_request); static inline void rq_init(request_queue_t *q, struct request *rq) { INIT_LIST_HEAD(&rq->queuelist); + INIT_LIST_HEAD(&rq->donelist); rq->errors = 0; rq->rq_status = RQ_ACTIVE; @@ -286,6 +298,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq) rq->sense = NULL; rq->end_io = NULL; rq->end_io_data = NULL; + rq->completion_data = NULL; } /** @@ -3286,6 +3299,87 @@ int end_that_request_chunk(struct request *req, int uptodate, int nr_bytes) EXPORT_SYMBOL(end_that_request_chunk); +/* + * splice the completion data to a local structure and hand off to + * process_completion_queue() to complete the requests + */ +static void blk_done_softirq(struct softirq_action *h) +{ + struct list_head *cpu_list; + LIST_HEAD(local_list); + + local_irq_disable(); + cpu_list = &__get_cpu_var(blk_cpu_done); + list_splice_init(cpu_list, &local_list); + local_irq_enable(); + + while (!list_empty(&local_list)) { + struct request *rq = list_entry(local_list.next, struct request, donelist); + + list_del_init(&rq->donelist); + rq->q->softirq_done_fn(rq); + } +} + +#ifdef CONFIG_HOTPLUG_CPU + +static int blk_cpu_notify(struct notifier_block *self, unsigned long action, + void *hcpu) +{ + /* + * If a CPU goes away, splice its entries to the current CPU + * and trigger a run of the softirq + */ + if (action == CPU_DEAD) { + int cpu = (unsigned long) hcpu; + + local_irq_disable(); + list_splice_init(&per_cpu(blk_cpu_done, cpu), + &__get_cpu_var(blk_cpu_done)); + raise_softirq_irqoff(BLOCK_SOFTIRQ); + local_irq_enable(); + } + + return NOTIFY_OK; +} + + +static struct notifier_block __devinitdata blk_cpu_notifier = { + .notifier_call = blk_cpu_notify, +}; + +#endif /* CONFIG_HOTPLUG_CPU */ + +/** + * blk_complete_request - end I/O on a request + * @req: the request being processed + * + * Description: + * Ends all I/O on a request. It does not handle partial completions, + * unless the driver actually implements this in its completionc callback + * through requeueing. Theh actual completion happens out-of-order, + * through a softirq handler. The user must have registered a completion + * callback through blk_queue_softirq_done(). + **/ + +void blk_complete_request(struct request *req) +{ + struct list_head *cpu_list; + unsigned long flags; + + BUG_ON(!req->q->softirq_done_fn); + + local_irq_save(flags); + + cpu_list = &__get_cpu_var(blk_cpu_done); + list_add_tail(&req->donelist, cpu_list); + raise_softirq_irqoff(BLOCK_SOFTIRQ); + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(blk_complete_request); + /* * queue lock must be held */ @@ -3364,6 +3458,8 @@ EXPORT_SYMBOL(kblockd_flush); int __init blk_dev_init(void) { + int i; + kblockd_workqueue = create_workqueue("kblockd"); if (!kblockd_workqueue) panic("Failed to create kblockd\n"); @@ -3377,6 +3473,14 @@ int __init blk_dev_init(void) iocontext_cachep = kmem_cache_create("blkdev_ioc", sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL); + for (i = 0; i < NR_CPUS; i++) + INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); + + open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL); +#ifdef CONFIG_HOTPLUG_CPU + register_cpu_notifier(&blk_cpu_notifier); +#endif + blk_max_low_pfn = max_low_pfn; blk_max_pfn = max_pfn; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index fb0985377421..804cc4ec9533 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -118,9 +118,9 @@ struct request_list { * try to put the fields that are referenced together in the same cacheline */ struct request { - struct list_head queuelist; /* looking for ->queue? you must _not_ - * access it directly, use - * blkdev_dequeue_request! */ + struct list_head queuelist; + struct list_head donelist; + unsigned long flags; /* see REQ_ bits below */ /* Maintain bio traversal state for part by part I/O submission. @@ -141,6 +141,7 @@ struct request { struct bio *biotail; void *elevator_private; + void *completion_data; unsigned short ioprio; @@ -291,6 +292,7 @@ typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *); typedef void (activity_fn) (void *data, int rw); typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *); typedef void (prepare_flush_fn) (request_queue_t *, struct request *); +typedef void (softirq_done_fn)(struct request *); enum blk_queue_state { Queue_down, @@ -332,6 +334,7 @@ struct request_queue activity_fn *activity_fn; issue_flush_fn *issue_flush_fn; prepare_flush_fn *prepare_flush_fn; + softirq_done_fn *softirq_done_fn; /* * Dispatch queue sorting @@ -646,6 +649,17 @@ extern int end_that_request_first(struct request *, int, int); extern int end_that_request_chunk(struct request *, int, int); extern void end_that_request_last(struct request *, int); extern void end_request(struct request *req, int uptodate); +extern void blk_complete_request(struct request *); + +static inline int rq_all_done(struct request *rq, unsigned int nr_bytes) +{ + if (blk_fs_request(rq)) + return (nr_bytes >= (rq->hard_nr_sectors << 9)); + else if (blk_pc_request(rq)) + return nr_bytes >= rq->data_len; + + return 0; +} /* * end_that_request_first/chunk() takes an uptodate argument. we account @@ -694,6 +708,7 @@ extern void blk_queue_segment_boundary(request_queue_t *, unsigned long); extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn); extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *); extern void blk_queue_dma_alignment(request_queue_t *, int); +extern void blk_queue_softirq_done(request_queue_t *, softirq_done_fn *); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); extern int blk_queue_ordered(request_queue_t *, unsigned, prepare_flush_fn *); extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index e50a95fbeb11..f02204706984 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -112,6 +112,7 @@ enum TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, + BLOCK_SOFTIRQ, SCSI_SOFTIRQ, TASKLET_SOFTIRQ }; -- cgit v1.2.3 From 1aea6434eebd25e532d2e5ddabf2733af4e1ff0b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 16:03:03 +0100 Subject: [SCSI] Kill the SCSI softirq handling This patch moves the SCSI softirq handling to the block layer version. There should be no functional changes. Signed-off-by: Jens Axboe --- drivers/scsi/scsi.c | 109 ++++------------------------------------------ drivers/scsi/scsi_lib.c | 36 +++++++++++++++ drivers/scsi/scsi_priv.h | 1 + include/linux/interrupt.h | 1 - 4 files changed, 45 insertions(+), 102 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 180676d7115a..ee5f4dfdab14 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -69,7 +69,6 @@ #include "scsi_logging.h" static void scsi_done(struct scsi_cmnd *cmd); -static int scsi_retry_command(struct scsi_cmnd *cmd); /* * Definitions and constants. @@ -752,7 +751,7 @@ static void scsi_done(struct scsi_cmnd *cmd) * isn't running --- used by scsi_times_out */ void __scsi_done(struct scsi_cmnd *cmd) { - unsigned long flags; + struct request *rq = cmd->request; /* * Set the serial numbers back to zero @@ -763,71 +762,14 @@ void __scsi_done(struct scsi_cmnd *cmd) if (cmd->result) atomic_inc(&cmd->device->ioerr_cnt); + BUG_ON(!rq); + /* - * Next, enqueue the command into the done queue. - * It is a per-CPU queue, so we just disable local interrupts - * and need no spinlock. + * The uptodate/nbytes values don't matter, as we allow partial + * completes and thus will check this in the softirq callback */ - local_irq_save(flags); - list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q)); - raise_softirq_irqoff(SCSI_SOFTIRQ); - local_irq_restore(flags); -} - -/** - * scsi_softirq - Perform post-interrupt processing of finished SCSI commands. - * - * This is the consumer of the done queue. - * - * This is called with all interrupts enabled. This should reduce - * interrupt latency, stack depth, and reentrancy of the low-level - * drivers. - */ -static void scsi_softirq(struct softirq_action *h) -{ - int disposition; - LIST_HEAD(local_q); - - local_irq_disable(); - list_splice_init(&__get_cpu_var(scsi_done_q), &local_q); - local_irq_enable(); - - while (!list_empty(&local_q)) { - struct scsi_cmnd *cmd = list_entry(local_q.next, - struct scsi_cmnd, eh_entry); - /* The longest time any command should be outstanding is the - * per command timeout multiplied by the number of retries. - * - * For a typical command, this is 2.5 minutes */ - unsigned long wait_for - = cmd->allowed * cmd->timeout_per_command; - list_del_init(&cmd->eh_entry); - - disposition = scsi_decide_disposition(cmd); - if (disposition != SUCCESS && - time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { - sdev_printk(KERN_ERR, cmd->device, - "timing out command, waited %lus\n", - wait_for/HZ); - disposition = SUCCESS; - } - - scsi_log_completion(cmd, disposition); - switch (disposition) { - case SUCCESS: - scsi_finish_command(cmd); - break; - case NEEDS_RETRY: - scsi_retry_command(cmd); - break; - case ADD_TO_MLQUEUE: - scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); - break; - default: - if (!scsi_eh_scmd_add(cmd, 0)) - scsi_finish_command(cmd); - } - } + rq->completion_data = cmd; + blk_complete_request(rq); } /* @@ -840,7 +782,7 @@ static void scsi_softirq(struct softirq_action *h) * level drivers should not become re-entrant as a result of * this. */ -static int scsi_retry_command(struct scsi_cmnd *cmd) +int scsi_retry_command(struct scsi_cmnd *cmd) { /* * Restore the SCSI command state. @@ -1273,38 +1215,6 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery) } EXPORT_SYMBOL(scsi_device_cancel); -#ifdef CONFIG_HOTPLUG_CPU -static int scsi_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - int cpu = (unsigned long)hcpu; - - switch(action) { - case CPU_DEAD: - /* Drain scsi_done_q. */ - local_irq_disable(); - list_splice_init(&per_cpu(scsi_done_q, cpu), - &__get_cpu_var(scsi_done_q)); - raise_softirq_irqoff(SCSI_SOFTIRQ); - local_irq_enable(); - break; - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block __devinitdata scsi_cpu_nb = { - .notifier_call = scsi_cpu_notify, -}; - -#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb) -#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb) -#else -#define register_scsi_cpu() -#define unregister_scsi_cpu() -#endif /* CONFIG_HOTPLUG_CPU */ - MODULE_DESCRIPTION("SCSI core"); MODULE_LICENSE("GPL"); @@ -1338,8 +1248,6 @@ static int __init init_scsi(void) INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); devfs_mk_dir("scsi"); - open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); - register_scsi_cpu(); printk(KERN_NOTICE "SCSI subsystem initialized\n"); return 0; @@ -1367,7 +1275,6 @@ static void __exit exit_scsi(void) devfs_remove("scsi"); scsi_exit_procfs(); scsi_exit_queue(); - unregister_scsi_cpu(); } subsys_initcall(init_scsi); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba93d6e66d48..00c9bf383e23 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1493,6 +1493,41 @@ static void scsi_kill_request(struct request *req, request_queue_t *q) __scsi_done(cmd); } +static void scsi_softirq_done(struct request *rq) +{ + struct scsi_cmnd *cmd = rq->completion_data; + unsigned long wait_for = cmd->allowed * cmd->timeout_per_command; + int disposition; + + INIT_LIST_HEAD(&cmd->eh_entry); + + disposition = scsi_decide_disposition(cmd); + if (disposition != SUCCESS && + time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { + sdev_printk(KERN_ERR, cmd->device, + "timing out command, waited %lus\n", + wait_for/HZ); + disposition = SUCCESS; + } + + scsi_log_completion(cmd, disposition); + + switch (disposition) { + case SUCCESS: + scsi_finish_command(cmd); + break; + case NEEDS_RETRY: + scsi_retry_command(cmd); + break; + case ADD_TO_MLQUEUE: + scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); + break; + default: + if (!scsi_eh_scmd_add(cmd, 0)) + scsi_finish_command(cmd); + } +} + /* * Function: scsi_request_fn() * @@ -1667,6 +1702,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + blk_queue_softirq_done(q, scsi_softirq_done); if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index f04e7e11f57a..14a6198cb8d2 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -44,6 +44,7 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq); extern void __scsi_release_request(struct scsi_request *sreq); extern void __scsi_done(struct scsi_cmnd *cmd); +extern int scsi_retry_command(struct scsi_cmnd *cmd); #ifdef CONFIG_SCSI_LOGGING void scsi_log_send(struct scsi_cmnd *cmd); void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f02204706984..2c08fdc2bdf7 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -113,7 +113,6 @@ enum NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, - SCSI_SOFTIRQ, TASKLET_SOFTIRQ }; -- cgit v1.2.3 From 8672d57138b34447719cd7749f3d21070e1175a1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 16:03:35 +0100 Subject: [IDE] Use the block layer deferred softirq request completion This patch makes IDE use the new blk_complete_request() interface. There's still room for improvement, as __ide_end_request() really could drop the lock after getting HWGROUP->rq (why does it need to hold it in the first place? If ->rq access isn't serialized, we are screwed anyways). Signed-off-by: Jens Axboe --- drivers/ide/ide-io.c | 42 +++++++++++++++++++++++++++++++++++------- drivers/ide/ide-probe.c | 2 ++ include/linux/ide.h | 1 + 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index b5dc6df8e67d..dea2d4dcc698 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -55,9 +55,22 @@ #include #include +void ide_softirq_done(struct request *rq) +{ + request_queue_t *q = rq->q; + + add_disk_randomness(rq->rq_disk); + end_that_request_chunk(rq, rq->errors, rq->data_len); + + spin_lock_irq(q->queue_lock); + end_that_request_last(rq, rq->errors); + spin_unlock_irq(q->queue_lock); +} + int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, int nr_sectors) { + unsigned int nbytes; int ret = 1; BUG_ON(!(rq->flags & REQ_STARTED)); @@ -81,17 +94,28 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, HWGROUP(drive)->hwif->ide_dma_on(drive); } - if (!end_that_request_first(rq, uptodate, nr_sectors)) { - add_disk_randomness(rq->rq_disk); - - if (blk_rq_tagged(rq)) - blk_queue_end_tag(drive->queue, rq); - + /* + * For partial completions (or non fs/pc requests), use the regular + * direct completion path. + */ + nbytes = nr_sectors << 9; + if (rq_all_done(rq, nbytes)) { + rq->errors = uptodate; + rq->data_len = nbytes; blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - end_that_request_last(rq, uptodate); + blk_complete_request(rq); ret = 0; + } else { + if (!end_that_request_first(rq, uptodate, nr_sectors)) { + add_disk_randomness(rq->rq_disk); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq, uptodate); + ret = 0; + } } + return ret; } EXPORT_SYMBOL(__ide_end_request); @@ -113,6 +137,10 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) unsigned long flags; int ret = 1; + /* + * room for locking improvements here, the calls below don't + * need the queue lock held at all + */ spin_lock_irqsave(&ide_lock, flags); rq = HWGROUP(drive)->rq; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 02167a5b751d..1ddaa71a8f45 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1011,6 +1011,8 @@ static int ide_init_queue(ide_drive_t *drive) blk_queue_max_hw_segments(q, max_sg_entries); blk_queue_max_phys_segments(q, max_sg_entries); + blk_queue_softirq_done(q, ide_softirq_done); + /* assign drive queue */ drive->queue = q; diff --git a/include/linux/ide.h b/include/linux/ide.h index 4dd6694963c0..ef8d0cbb832f 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1001,6 +1001,7 @@ extern int noautodma; extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs); extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs); +extern void ide_softirq_done(struct request *rq); /* * This is used on exit from the driver to designate the next irq handler -- cgit v1.2.3 From a9925a06ea52a44b4bf4a941342e8240eaf22417 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 9 Jan 2006 16:04:06 +0100 Subject: [BLOCK] CCISS: update for blk softirq completions Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 72 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 88452c79fb64..e4e9f255bd1f 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2178,16 +2178,48 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c) start_io(h); } + +static void cciss_softirq_done(struct request *rq) +{ + CommandList_struct *cmd = rq->completion_data; + ctlr_info_t *h = hba[cmd->ctlr]; + u64bit temp64; + int i, ddir; + + if (cmd->Request.Type.Direction == XFER_READ) + ddir = PCI_DMA_FROMDEVICE; + else + ddir = PCI_DMA_TODEVICE; + + /* command did not need to be retried */ + /* unmap the DMA mapping for all the scatter gather elements */ + for(i=0; iHeader.SGList; i++) { + temp64.val32.lower = cmd->SG[i].Addr.lower; + temp64.val32.upper = cmd->SG[i].Addr.upper; + pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); + } + + complete_buffers(rq->bio, rq->errors); + +#ifdef CCISS_DEBUG + printk("Done with %p\n", rq); +#endif /* CCISS_DEBUG */ + + spin_lock_irq(&h->lock); + end_that_request_last(rq, rq->errors); + cmd_free(h, cmd,1); + spin_unlock_irq(&h->lock); +} + /* checks the status of the job and calls complete buffers to mark all - * buffers for the completed job. + * buffers for the completed job. Note that this function does not need + * to hold the hba/queue lock. */ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, int timeout) { int status = 1; - int i; int retry_cmd = 0; - u64bit temp64; if (timeout) status = 0; @@ -2295,24 +2327,10 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, resend_cciss_cmd(h,cmd); return; } - /* command did not need to be retried */ - /* unmap the DMA mapping for all the scatter gather elements */ - for(i=0; iHeader.SGList; i++) { - temp64.val32.lower = cmd->SG[i].Addr.lower; - temp64.val32.upper = cmd->SG[i].Addr.upper; - pci_unmap_page(hba[cmd->ctlr]->pdev, - temp64.val, cmd->SG[i].Len, - (cmd->Request.Type.Direction == XFER_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - } - complete_buffers(cmd->rq->bio, status); - -#ifdef CCISS_DEBUG - printk("Done with %p\n", cmd->rq); -#endif /* CCISS_DEBUG */ - end_that_request_last(cmd->rq, status ? 1 : -EIO); - cmd_free(h,cmd,1); + cmd->rq->completion_data = cmd; + cmd->rq->errors = status; + blk_complete_request(cmd->rq); } /* @@ -3199,15 +3217,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, drv->queue = q; q->backing_dev_info.ra_pages = READ_AHEAD; - blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + + /* This is a hardware imposed limit. */ + blk_queue_max_hw_segments(q, MAXSGENTRIES); - /* This is a hardware imposed limit. */ - blk_queue_max_hw_segments(q, MAXSGENTRIES); + /* This is a limit in the driver and could be eliminated. */ + blk_queue_max_phys_segments(q, MAXSGENTRIES); - /* This is a limit in the driver and could be eliminated. */ - blk_queue_max_phys_segments(q, MAXSGENTRIES); + blk_queue_max_sectors(q, 512); - blk_queue_max_sectors(q, 512); + blk_queue_softirq_done(q, cciss_softirq_done); q->queuedata = hba[i]; sprintf(disk->disk_name, "cciss/c%dd%d", i, j); -- cgit v1.2.3 From 17fa6e2f115ad734ef802b663071159a1a64d06f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 6 Jan 2006 16:57:39 -0800 Subject: [PATCH] sk98lin: routine called from probe marked __init Sk98lin driver has a routine marked __init that is called from the probe code. If using pci hotplug, this could be called after the initialization so it needs to be marked __devinit. So if you hot added a sk98lin board, the kernel would crash. I don't have hot plug hardware to actually try this feat. Also, there are two routines, only called from SkGeBoardInit that can be marked __devinit. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/skge.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 9a76ac180b11..3302d644011f 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -282,10 +282,11 @@ SK_U32 Val) /* pointer to store the read value */ * Description: * This function initialize the PCI resources and IO * - * Returns: N/A - * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication */ -int SkGeInitPCI(SK_AC *pAC) +static __devinit int SkGeInitPCI(SK_AC *pAC) { struct SK_NET_DEVICE *dev = pAC->dev[0]; struct pci_dev *pdev = pAC->PciDev; @@ -492,7 +493,7 @@ module_param_array(AutoSizing, charp, NULL, 0); * 0, if everything is ok * !=0, on error */ -static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC) +static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC) { short i; unsigned long Flags; @@ -633,8 +634,7 @@ SK_BOOL DualNet; * SK_TRUE, if all memory could be allocated * SK_FALSE, if not */ -static SK_BOOL BoardAllocMem( -SK_AC *pAC) +static __devinit SK_BOOL BoardAllocMem(SK_AC *pAC) { caddr_t pDescrMem; /* pointer to descriptor memory area */ size_t AllocLength; /* length of complete descriptor area */ @@ -727,8 +727,7 @@ size_t AllocLength; /* length of complete descriptor area */ * * Returns: N/A */ -static void BoardInitMem( -SK_AC *pAC) /* pointer to adapter context */ +static __devinit void BoardInitMem(SK_AC *pAC) { int i; /* loop counter */ int RxDescrSize; /* the size of a rx descriptor rounded up to alignment*/ -- cgit v1.2.3 From bce7c95e4dd4d5e924deb2929b639b4caca09c93 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 6 Jan 2006 16:57:40 -0800 Subject: [PATCH] sk98lin: not doing high dma properly Sk98lin 64bit memory handling is wrong. It doesn't set the highdma flag; i.e. the kernel always does bounce buffers. It doesn't fallback to 32 bit mask if it can't get 64 bit mask. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/skge.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 3302d644011f..9a879530ef6d 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -4775,16 +4775,30 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, struct net_device *dev = NULL; static int boards_found = 0; int error = -ENODEV; + int using_dac = 0; char DeviceStr[80]; if (pci_enable_device(pdev)) goto out; /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) && - pci_set_dma_mask(pdev, DMA_32BIT_MASK)) - goto out_disable_device; - + if (sizeof(dma_addr_t) > sizeof(u32) && + !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + using_dac = 1; + error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (error < 0) { + printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA " + "for consistent allocations\n", pci_name(pdev)); + goto out_disable_device; + } + } else { + error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (error) { + printk(KERN_ERR "sk98lin %s no usable DMA configuration\n", + pci_name(pdev)); + goto out_disable_device; + } + } if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { printk(KERN_ERR "Unable to allocate etherdev " @@ -4843,6 +4857,9 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, #endif } + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + pAC->Index = boards_found++; if (SkGeBoardInit(dev, pAC)) @@ -4919,6 +4936,9 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, #endif } + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + if (register_netdev(dev)) { printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n"); free_netdev(dev); -- cgit v1.2.3 From decf67aa2f4d498c02c2ad24a187a66c217f330c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 6 Jan 2006 16:57:41 -0800 Subject: [PATCH] sk98lin: error handling on dual port board Sk98lin driver error recovery on two port boards is bad. If it fails the second allocation, it will not release resources properly. Also it registers the second port in the pci driver data If second port fails, might as well go with one port. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/skge.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 9a879530ef6d..87bfe4c24a77 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -4899,15 +4899,17 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, boards_found++; + pci_set_drvdata(pdev, dev); + /* More then one port found */ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { - printk(KERN_ERR "Unable to allocate etherdev " + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { + printk(KERN_ERR "sk98lin: unable to allocate etherdev " "structure!\n"); - goto out; + goto single_port; } - pAC->dev[1] = dev; pNet = netdev_priv(dev); pNet->PortNr = 1; pNet->NetNr = 1; @@ -4939,20 +4941,25 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, if (using_dac) dev->features |= NETIF_F_HIGHDMA; - if (register_netdev(dev)) { - printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n"); + error = register_netdev(dev); + if (error) { + printk(KERN_ERR "sk98lin: Could not register device" + " for second port. (%d)\n", error); free_netdev(dev); - pAC->dev[1] = pAC->dev[0]; - } else { - memcpy(&dev->dev_addr, - &pAC->Addr.Net[1].CurrentMacAddress, 6); - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - - printk("%s: %s\n", dev->name, DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + goto single_port; } + + pAC->dev[1] = dev; + memcpy(&dev->dev_addr, + &pAC->Addr.Net[1].CurrentMacAddress, 6); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + printk("%s: %s\n", dev->name, DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); } +single_port: + /* Save the hardware revision */ pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + (pAC->GIni.GIPciHwRev & 0x0F); @@ -4964,7 +4971,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA)); memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA)); - pci_set_drvdata(pdev, dev); return 0; out_free_resources: -- cgit v1.2.3 From 26fc354914219a91254afd0df573fc801bb1183a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 6 Jan 2006 16:57:42 -0800 Subject: [PATCH] sk98lin: use kzalloc Trivial use of kzalloc. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/skge.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 87bfe4c24a77..9f89c23191d0 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -4807,14 +4807,13 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, } pNet = netdev_priv(dev); - pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); + pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL); if (!pNet->pAC) { printk(KERN_ERR "Unable to allocate adapter " "structure!\n"); goto out_free_netdev; } - memset(pNet->pAC, 0, sizeof(SK_AC)); pAC = pNet->pAC; pAC->PciDev = pdev; -- cgit v1.2.3 From 162875570e65b56a7f4d804fc32aebf7a434cf89 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 6 Jan 2006 16:57:43 -0800 Subject: [PATCH] sk98lin: error handling on probe The sk98lin driver doesn't do proper error number handling during initialization. Note: -EAGAIN is a bogus return value for hardware errors. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/skge.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 9f89c23191d0..455417d5fcfb 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -530,7 +530,7 @@ SK_BOOL DualNet; if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) { printk("HWInit (0) failed.\n"); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - return(-EAGAIN); + return -EIO; } SkI2cInit( pAC, pAC->IoBase, SK_INIT_DATA); SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA); @@ -552,7 +552,7 @@ SK_BOOL DualNet; if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { printk("sk98lin: HWInit (1) failed.\n"); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - return(-EAGAIN); + return -EIO; } SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO); SkEventInit(pAC, pAC->IoBase, SK_INIT_IO); @@ -584,20 +584,20 @@ SK_BOOL DualNet; } else { printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n", pAC->GIni.GIMacsFound); - return -EAGAIN; + return -EIO; } if (Ret) { printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n", dev->irq); - return -EAGAIN; + return Ret; } pAC->AllocFlag |= SK_ALLOC_IRQ; /* Alloc memory for this board (Mem for RxD/TxD) : */ if(!BoardAllocMem(pAC)) { printk("No memory for descriptor rings.\n"); - return(-EAGAIN); + return -ENOMEM; } BoardInitMem(pAC); @@ -613,7 +613,7 @@ SK_BOOL DualNet; DualNet)) { BoardFreeMem(pAC); printk("sk98lin: SkGeInitAssignRamToQueues failed.\n"); - return(-EAGAIN); + return -EIO; } return (0); @@ -4800,8 +4800,10 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, } } - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { - printk(KERN_ERR "Unable to allocate etherdev " + error = -ENOMEM; + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { + printk(KERN_ERR "sk98lin: unable to allocate etherdev " "structure!\n"); goto out_disable_device; } @@ -4809,7 +4811,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, pNet = netdev_priv(dev); pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL); if (!pNet->pAC) { - printk(KERN_ERR "Unable to allocate adapter " + printk(KERN_ERR "sk98lin: unable to allocate adapter " "structure!\n"); goto out_free_netdev; } @@ -4822,6 +4824,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, pAC->CheckQueue = SK_FALSE; dev->irq = pdev->irq; + error = SkGeInitPCI(pAC); if (error) { printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error); @@ -4861,17 +4864,20 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, pAC->Index = boards_found++; - if (SkGeBoardInit(dev, pAC)) + error = SkGeBoardInit(dev, pAC); + if (error) goto out_free_netdev; /* Read Adapter name from VPD */ if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) { + error = -EIO; printk(KERN_ERR "sk98lin: Could not read VPD data.\n"); goto out_free_resources; } /* Register net device */ - if (register_netdev(dev)) { + error = register_netdev(dev); + if (error) { printk(KERN_ERR "sk98lin: Could not register device.\n"); goto out_free_resources; } -- cgit v1.2.3 From df22b8aaba3f41cc61f57f5ead78be45edcb7db5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 6 Jan 2006 16:57:44 -0800 Subject: [PATCH] sk98lin: error handling of pci setup Don't enable the pci device twice (already done in the probe routine). Propogate the error codes from pci_request_region back to initial probing. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/skge.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 455417d5fcfb..197edd74fbb5 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -292,17 +292,12 @@ static __devinit int SkGeInitPCI(SK_AC *pAC) struct pci_dev *pdev = pAC->PciDev; int retval; - if (pci_enable_device(pdev) != 0) { - return 1; - } - dev->mem_start = pci_resource_start (pdev, 0); pci_set_master(pdev); - if (pci_request_regions(pdev, "sk98lin") != 0) { - retval = 2; - goto out_disable; - } + retval = pci_request_regions(pdev, "sk98lin"); + if (retval) + goto out; #ifdef SK_BIG_ENDIAN /* @@ -321,9 +316,8 @@ static __devinit int SkGeInitPCI(SK_AC *pAC) * Remap the regs into kernel space. */ pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000); - - if (!pAC->IoBase){ - retval = 3; + if (!pAC->IoBase) { + retval = -EIO; goto out_release; } @@ -331,8 +325,7 @@ static __devinit int SkGeInitPCI(SK_AC *pAC) out_release: pci_release_regions(pdev); - out_disable: - pci_disable_device(pdev); + out: return retval; } -- cgit v1.2.3 From a4bf26f30e398afa293b85103c885f03d4660a07 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 31 Dec 2005 11:35:20 +0100 Subject: [PATCH] ieee80211: enable hw wep where host has to build IV This patch fixes some of the ieee80211 crypto related code so that instead of having the host fully do crypto operations, the host_build_iv flag works properly (for WEP in this patch) which, if turned on, requires the hardware to do all crypto operations, but the ieee80211 layer builds the IV. The hardware also has to build the ICV. Previously, the host_build_iv flag couldn't be used at all for WEP, and not alone (with both host_decrypt and host_encrypt disabled) because the crypto algorithm wasn't assigned. This is also fixed. I have tested this patch both in host crypto mode and in hw crypto mode (with the Broadcom chipset). [resent, signing digitally caused it to be MIME-junked, sorry] Signed-Off-By: Johannes Berg Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_crypt_wep.c | 61 ++++++++++++++++++++++++++----------- net/ieee80211/ieee80211_tx.c | 2 +- net/ieee80211/ieee80211_wx.c | 2 +- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 073aebdf0f67..f8dca31be5dd 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -75,22 +75,14 @@ static void prism2_wep_deinit(void *priv) kfree(priv); } -/* Perform WEP encryption on given skb that has at least 4 bytes of headroom - * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, - * so the payload length increases with 8 bytes. - * - * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) - */ -static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ +static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv) { struct prism2_wep_data *wep = priv; - u32 crc, klen, len; - u8 key[WEP_KEY_LEN + 3]; - u8 *pos, *icv; - struct scatterlist sg; - - if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || - skb->len < hdr_len) + u32 klen, len; + u8 *pos; + + if (skb_headroom(skb) < 4 || skb->len < hdr_len) return -1; len = skb->len - hdr_len; @@ -112,15 +104,47 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) } /* Prepend 24-bit IV to RC4 key and TX frame */ - *pos++ = key[0] = (wep->iv >> 16) & 0xff; - *pos++ = key[1] = (wep->iv >> 8) & 0xff; - *pos++ = key[2] = wep->iv & 0xff; + *pos++ = (wep->iv >> 16) & 0xff; + *pos++ = (wep->iv >> 8) & 0xff; + *pos++ = wep->iv & 0xff; *pos++ = wep->key_idx << 6; + return 0; +} + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct prism2_wep_data *wep = priv; + u32 crc, klen, len; + u8 *pos, *icv; + struct scatterlist sg; + u8 key[WEP_KEY_LEN + 3]; + + /* other checks are in prism2_wep_build_iv */ + if (skb_tailroom(skb) < 4) + return -1; + + /* add the IV to the frame */ + if (prism2_wep_build_iv(skb, hdr_len, priv)) + return -1; + + /* Copy the IV into the first 3 bytes of the key */ + memcpy(key, skb->data + hdr_len, 3); + /* Copy rest of the WEP key (the secret part) */ memcpy(key + 3, wep->key, wep->key_len); + + len = skb->len - hdr_len - 4; + pos = skb->data + hdr_len + 4; + klen = 3 + wep->key_len; - /* Append little-endian CRC32 and encrypt it to produce ICV */ + /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */ crc = ~crc32_le(~0, pos, len); icv = skb_put(skb, 4); icv[0] = crc; @@ -231,6 +255,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_wep = { .name = "WEP", .init = prism2_wep_init, .deinit = prism2_wep_deinit, + .build_iv = prism2_wep_build_iv, .encrypt_mpdu = prism2_wep_encrypt, .decrypt_mpdu = prism2_wep_decrypt, .encrypt_msdu = NULL, diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 445f206e65e0..e5b33c8d5dbc 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -288,7 +288,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Determine total amount of storage required for TXB packets */ bytes = skb->len + SNAP_SIZE + sizeof(u16); - if (host_encrypt) + if (host_encrypt || host_build_iv) fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_PROTECTED; else diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 181755f2aa8b..406d5b964905 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -284,7 +284,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, }; int i, key, key_provided, len; struct ieee80211_crypt_data **crypt; - int host_crypto = ieee->host_encrypt || ieee->host_decrypt; + int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; IEEE80211_DEBUG_WX("SET_ENCODE\n"); -- cgit v1.2.3 From 38843888e3e9fb7006d72d55b8e6ffcc925cf18a Mon Sep 17 00:00:00 2001 From: Eugene Surovegin Date: Tue, 27 Dec 2005 12:36:41 -0800 Subject: [PATCH] PPC44x EMAC driver: disable TX status deferral in half-duplex mode Disable TX status deferral (EMACx_MR[MWSW=001]) in half-duplex mode. I have two reports when EMAC stops transmitting when connected to a hub. TX ring debug printouts show complete mess when this happens, probably hardware collision handling doesn't work quite well in this mode. This is relevant only for SoCs with EMAC4 core (440GX, 440SP, 440SPe). Tested on 440GX. Signed-off-by: Eugene Surovegin Signed-off-by: Jeff Garzik --- drivers/net/ibm_emac/ibm_emac.h | 3 ++- drivers/net/ibm_emac/ibm_emac_core.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h index 644edbff4f94..c2dae6092c4c 100644 --- a/drivers/net/ibm_emac/ibm_emac.h +++ b/drivers/net/ibm_emac/ibm_emac.h @@ -110,6 +110,7 @@ struct emac_regs { #define EMAC_MR1_TFS_2K 0x00080000 #define EMAC_MR1_TR0_MULT 0x00008000 #define EMAC_MR1_JPSM 0x00000000 +#define EMAC_MR1_MWSW_001 0x00000000 #define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) #else #define EMAC_MR1_RFS_4K 0x00180000 @@ -130,7 +131,7 @@ struct emac_regs { (freq) <= 83 ? EMAC_MR1_OBCI_83 : \ (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P) #define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \ - EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb)) + EMAC_MR1_OBCI(opb)) #endif /* EMACx_TMR0 */ diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 1da8a66f91e1..591c5864ffb1 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -408,7 +408,7 @@ static int emac_configure(struct ocp_enet_private *dev) /* Mode register */ r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; if (dev->phy.duplex == DUPLEX_FULL) - r |= EMAC_MR1_FDE; + r |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001; dev->stop_timeout = STOP_TIMEOUT_10; switch (dev->phy.speed) { case SPEED_1000: -- cgit v1.2.3 From b887030aec0971a47ca97a18e93ff446bc7d049e Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Wed, 4 Jan 2006 19:13:04 -0800 Subject: [PATCH] sata_nv, spurious interrupts at system startup with MAXTOR 6H500F0 drive This patch works around a problem with spurious interrupts seen at boot time when a MAXTOR 6H500F0 drive is present. An ATA interrupt condition is mysteriously present at start of day. If we took too long in issuing the first command, the kernel would basically get tired of the spurious interrupts and turn the interrupt off. Issuing the first command essentially causes the interrupt condition to get acknowledged. I haven't seen this happen with any other drives. What I basically do is ack ATA status by reading it regardless of whether we're expecting to have to handle an interrupt. This clears the start-of-day anomalous interrupt condition, and keeps the kernel from disabling that interrupt due to too many spurious interrupts. Also, I fixed a bug where hotplug interrupts weren't getting acknowledged as handled in the ISR. This was not the cause of the spurious interrupts, but it's the right thing to do anyway. Signed-Off-By: Andrew Chew Signed-off-by: Jeff Garzik --- drivers/scsi/sata_nv.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index c0cf52cb975a..bbbb55eeb73a 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -29,6 +29,12 @@ * NV-specific details such as register offsets, SATA phy location, * hotplug info, etc. * + * 0.10 + * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB + * drive. Also made the check_hotplug() callbacks return whether there + * was a hotplug interrupt or not. This was not the source of the + * spurious interrupts, but is the right thing to do anyway. + * * 0.09 * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. * @@ -124,10 +130,10 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void nv_host_stop (struct ata_host_set *host_set); static void nv_enable_hotplug(struct ata_probe_ent *probe_ent); static void nv_disable_hotplug(struct ata_host_set *host_set); -static void nv_check_hotplug(struct ata_host_set *host_set); +static int nv_check_hotplug(struct ata_host_set *host_set); static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent); static void nv_disable_hotplug_ck804(struct ata_host_set *host_set); -static void nv_check_hotplug_ck804(struct ata_host_set *host_set); +static int nv_check_hotplug_ck804(struct ata_host_set *host_set); enum nv_host_type { @@ -176,7 +182,7 @@ struct nv_host_desc enum nv_host_type host_type; void (*enable_hotplug)(struct ata_probe_ent *probe_ent); void (*disable_hotplug)(struct ata_host_set *host_set); - void (*check_hotplug)(struct ata_host_set *host_set); + int (*check_hotplug)(struct ata_host_set *host_set); }; static struct nv_host_desc nv_device_tbl[] = { @@ -309,12 +315,16 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) handled += ata_host_intr(ap, qc); + else + // No request pending? Clear interrupt status + // anyway, in case there's one pending. + ap->ops->check_status(ap); } } if (host->host_desc->check_hotplug) - host->host_desc->check_hotplug(host_set); + handled += host->host_desc->check_hotplug(host_set); spin_unlock_irqrestore(&host_set->lock, flags); @@ -497,7 +507,7 @@ static void nv_disable_hotplug(struct ata_host_set *host_set) outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); } -static void nv_check_hotplug(struct ata_host_set *host_set) +static int nv_check_hotplug(struct ata_host_set *host_set) { u8 intr_status; @@ -522,7 +532,11 @@ static void nv_check_hotplug(struct ata_host_set *host_set) if (intr_status & NV_INT_STATUS_SDEV_REMOVED) printk(KERN_WARNING "nv_sata: " "Secondary device removed\n"); + + return 1; } + + return 0; } static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent) @@ -560,7 +574,7 @@ static void nv_disable_hotplug_ck804(struct ata_host_set *host_set) pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); } -static void nv_check_hotplug_ck804(struct ata_host_set *host_set) +static int nv_check_hotplug_ck804(struct ata_host_set *host_set) { u8 intr_status; @@ -585,7 +599,11 @@ static void nv_check_hotplug_ck804(struct ata_host_set *host_set) if (intr_status & NV_INT_STATUS_SDEV_REMOVED) printk(KERN_WARNING "nv_sata: " "Secondary device removed\n"); + + return 1; } + + return 0; } static int __init nv_init(void) -- cgit v1.2.3 From b9c4c609660e00377f0b30dfbbec0f1918b56aba Mon Sep 17 00:00:00 2001 From: Christoph Dworzak Date: Fri, 6 Jan 2006 14:49:22 -0500 Subject: [PATCH] tulip: enable multiport NIC BIOS fixups for x86_64 A BIOS bug affecting some multiport tulip NICs requires an irq fixup in tulip_core.c. This has only been enabled for i686, but it is needed for x86_64 as well. Signed-off-by: John W. Linville Signed-off-by: Jeff Garzik --- drivers/net/tulip/tulip_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 125ed00e95a5..c67c91251d04 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1564,7 +1564,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->dev_addr, 6); } #endif -#if defined(__i386__) /* Patch up x86 BIOS bug. */ +#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */ if (last_irq) irq = last_irq; #endif -- cgit v1.2.3 From 8fad6939af311a8be5785d41531baa5a6918f833 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 6 Jan 2006 11:57:11 -0500 Subject: [PATCH] update bonding.txt to not show ip address on slaves ifenslave, as of abi version 2, does not set the ip address on the slave interfaces. The documentation example however still shows that the ensalved interfaces should have the same IP as the master. The patch simply removes the lines from the example which should no longer appear. Signed-off-by: Eric Paris bonding.txt | 2 -- 1 files changed, 2 deletions(-) Signed-off-by: Jeff Garzik --- Documentation/networking/bonding.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index b0fe41da007b..8d8b4e5ea184 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -945,7 +945,6 @@ bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 collisions:0 txqueuelen:0 eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 - inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 @@ -953,7 +952,6 @@ eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 Interrupt:10 Base address:0x1080 eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 - inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 -- cgit v1.2.3 From b6d08c0e98c8b9a4a066544737cf6642df1ea5bd Mon Sep 17 00:00:00 2001 From: Franck Date: Thu, 5 Jan 2006 22:45:39 -0800 Subject: [PATCH] Add MIPS dependency for dm9000 driver Add MIPS dependency for dm9000 ethernet controller. Indeed this controller is used by some embedded platforms based on MIPS CPUs. Signed-off-by: Franck Bui-Huu Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1960961bf28e..62bb582ca359 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -844,7 +844,7 @@ config SMC9194 config DM9000 tristate "DM9000 support" - depends on ARM && NET_ETHERNET + depends on (ARM || MIPS) && NET_ETHERNET select CRC32 select MII ---help--- -- cgit v1.2.3 From f65fd8fbb2356d1b4412bc83810cf39a529de412 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 5 Jan 2006 22:45:41 -0800 Subject: [PATCH] drivers/net/Kconfig: indentation fix This patch fixes a wrong indentation. Signed-off-by: Adrian Bunk Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 62bb582ca359..733bc25b2bf9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -129,7 +129,7 @@ config NET_SB1000 If you don't have this card, of course say N. - source "drivers/net/arcnet/Kconfig" +source "drivers/net/arcnet/Kconfig" source "drivers/net/phy/Kconfig" -- cgit v1.2.3 From cceb904f9b804f18250214fcd988eca72864970c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 5 Jan 2006 22:45:42 -0800 Subject: [PATCH] drivers/net/bonding/bonding.h: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk Cc: "David S. Miller" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/bonding/bonding.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 015c7f1d1bc0..f20bb85c1ea5 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -205,7 +205,7 @@ struct bonding { * * Caller must hold bond lock for read */ -extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) +static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { struct slave *slave = NULL; int i; @@ -219,7 +219,7 @@ extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n return slave; } -extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) +static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) { if (!slave || !slave->dev->master) { return NULL; @@ -228,13 +228,13 @@ extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } -extern inline void bond_set_slave_inactive_flags(struct slave *slave) +static inline void bond_set_slave_inactive_flags(struct slave *slave) { slave->state = BOND_STATE_BACKUP; slave->dev->flags |= IFF_NOARP; } -extern inline void bond_set_slave_active_flags(struct slave *slave) +static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; slave->dev->flags &= ~IFF_NOARP; -- cgit v1.2.3 From 504ddff4c0b8e31fa2a2775d6d484faeb126a265 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 5 Jan 2006 22:45:43 -0800 Subject: [PATCH] drivers/net/gianfar.h: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk Cc: "David S. Miller" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/gianfar.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 94a91da84fbb..cb9d66ac3ab9 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -718,14 +718,14 @@ struct gfar_private { uint32_t msg_enable; }; -extern inline u32 gfar_read(volatile unsigned *addr) +static inline u32 gfar_read(volatile unsigned *addr) { u32 val; val = in_be32(addr); return val; } -extern inline void gfar_write(volatile unsigned *addr, u32 val) +static inline void gfar_write(volatile unsigned *addr, u32 val) { out_be32(addr, val); } -- cgit v1.2.3 From 32a4ec97461f00aa63747fc8978011ea771bd543 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 5 Jan 2006 22:45:44 -0800 Subject: [PATCH] e1000: Fix invalid memory reference Fix an invalid memory reference in the e1000 driver which would cause kernel panic. Signed-off-by: Kenji Kaneshige Cc: Jeb Cramer Cc: John Ronciak Cc: Ganesh Venkatesan Cc: Jeff Garzik Acked-by: Jeff Kirsher Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_param.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 38695d5b4637..ccbbe5ad8e0f 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -545,7 +545,7 @@ e1000_check_fiber_options(struct e1000_adapter *adapter) static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter) { - int speed, dplx; + int speed, dplx, an; int bd = adapter->bd_number; { /* Speed */ @@ -641,8 +641,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .p = an_list }} }; - int an = AutoNeg[bd]; - e1000_validate_option(&an, &opt, adapter); + if (num_AutoNeg > bd) { + an = AutoNeg[bd]; + e1000_validate_option(&an, &opt, adapter); + } else { + an = opt.def; + } adapter->hw.autoneg_advertised = an; } -- cgit v1.2.3 From 3bb8a18ae825ebf3550fe7894b35cd1c87356a16 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 5 Jan 2006 22:45:45 -0800 Subject: [PATCH] remove bouncing mail address of mv643xx_eth maintainer Remove bouncing mail address of mv643xx maintainer. Signed-off-by: Olaf Hering Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- MAINTAINERS | 1 - drivers/net/mv643xx_eth.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 76dc820bc889..270e28c0506a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1697,7 +1697,6 @@ S: Maintained MARVELL MV64340 ETHERNET DRIVER P: Manish Lachwani -M: Manish_Lachwani@pmc-sierra.com L: linux-mips@linux-mips.org L: netdev@vger.kernel.org S: Supported diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 3cb9b3fe0cf1..22c3a37bba5a 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -6,7 +6,7 @@ * Copyright (C) 2002 rabeeh@galileo.co.il * * Copyright (C) 2003 PMC-Sierra, Inc., - * written by Manish Lachwani (lachwani@pmc-sierra.com) + * written by Manish Lachwani * * Copyright (C) 2003 Ralf Baechle * -- cgit v1.2.3 From fa45459e5e4507402350f1cdaf44b7455602770c Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Thu, 5 Jan 2006 22:45:45 -0800 Subject: [PATCH] forcedeth: TSO fix for large buffers This contains a bug fix for large buffers. Originally, if a tx buffer to be sent was larger then the maximum size of the tx descriptor, it would overwrite other control bits. In this patch, the buffer is split over multiple descriptors. Also, the fragments are now setup in forward order. Signed-off-by: Ayaz Abdulla Signed-off-by: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 164 +++++++++++++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 64 deletions(-) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index c39344adecce..3682ec61e8a8 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -101,6 +101,7 @@ * 0.46: 20 Oct 2005: Add irq optimization modes. * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single + * 0.49: 10 Dec 2005: Fix tso for large buffers. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -112,7 +113,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.48" +#define FORCEDETH_VERSION "0.49" #define DRV_NAME "forcedeth" #include @@ -349,6 +350,8 @@ typedef union _ring_type { #define NV_TX2_VALID (1<<31) #define NV_TX2_TSO (1<<28) #define NV_TX2_TSO_SHIFT 14 +#define NV_TX2_TSO_MAX_SHIFT 14 +#define NV_TX2_TSO_MAX_SIZE (1<tx_ring.ex[i].FlagLen = 0; np->tx_skbuff[i] = NULL; + np->tx_dma[i] = 0; } } @@ -945,30 +950,27 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx(dev); } -static void nv_release_txskb(struct net_device *dev, unsigned int skbnr) +static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) { struct fe_priv *np = netdev_priv(dev); - struct sk_buff *skb = np->tx_skbuff[skbnr]; - unsigned int j, entry, fragments; - - dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n", - dev->name, skbnr, np->tx_skbuff[skbnr]); - - entry = skbnr; - if ((fragments = skb_shinfo(skb)->nr_frags) != 0) { - for (j = fragments; j >= 1; j--) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1]; - pci_unmap_page(np->pci_dev, np->tx_dma[entry], - frag->size, - PCI_DMA_TODEVICE); - entry = (entry - 1) % TX_RING; - } + + dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n", + dev->name, skbnr); + + if (np->tx_dma[skbnr]) { + pci_unmap_page(np->pci_dev, np->tx_dma[skbnr], + np->tx_dma_len[skbnr], + PCI_DMA_TODEVICE); + np->tx_dma[skbnr] = 0; + } + + if (np->tx_skbuff[skbnr]) { + dev_kfree_skb_irq(np->tx_skbuff[skbnr]); + np->tx_skbuff[skbnr] = NULL; + return 1; + } else { + return 0; } - pci_unmap_single(np->pci_dev, np->tx_dma[entry], - skb->len - skb->data_len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - np->tx_skbuff[skbnr] = NULL; } static void nv_drain_tx(struct net_device *dev) @@ -981,10 +983,8 @@ static void nv_drain_tx(struct net_device *dev) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; - if (np->tx_skbuff[i]) { - nv_release_txskb(dev, i); + if (nv_release_txskb(dev, i)) np->stats.tx_dropped++; - } } } @@ -1021,68 +1021,105 @@ static void drain_ring(struct net_device *dev) static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); + u32 tx_flags = 0; u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); unsigned int fragments = skb_shinfo(skb)->nr_frags; - unsigned int nr = (np->next_tx + fragments) % TX_RING; + unsigned int nr = (np->next_tx - 1) % TX_RING; + unsigned int start_nr = np->next_tx % TX_RING; unsigned int i; + u32 offset = 0; + u32 bcnt; + u32 size = skb->len-skb->data_len; + u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + + /* add fragments to entries count */ + for (i = 0; i < fragments; i++) { + entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) + + ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + } spin_lock_irq(&np->lock); - if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) { + if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) { spin_unlock_irq(&np->lock); netif_stop_queue(dev); return NETDEV_TX_BUSY; } - np->tx_skbuff[nr] = skb; - - if (fragments) { - dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments); - /* setup descriptors in reverse order */ - for (i = fragments; i >= 1; i--) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; - np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size, - PCI_DMA_TODEVICE); + /* setup the header buffer */ + do { + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + nr = (nr + 1) % TX_RING; + + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + PCI_DMA_TODEVICE); + np->tx_dma_len[nr] = bcnt; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } + tx_flags = np->tx_flags; + offset += bcnt; + size -= bcnt; + } while(size); + + /* setup the fragments */ + for (i = 0; i < fragments; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 size = frag->size; + offset = 0; + + do { + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + nr = (nr + 1) % TX_RING; + + np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->tx_dma_len[nr] = bcnt; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); } else { np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); } - - nr = (nr - 1) % TX_RING; + offset += bcnt; + size -= bcnt; + } while (size); + } - if (np->desc_ver == DESC_VER_1) - tx_flags_extra &= ~NV_TX_LASTPACKET; - else - tx_flags_extra &= ~NV_TX2_LASTPACKET; - } + /* set last fragment flag */ + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra); + } else { + np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra); } + np->tx_skbuff[nr] = skb; + #ifdef NETIF_F_TSO if (skb_shinfo(skb)->tso_size) - tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); else #endif - tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); + tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len, - PCI_DMA_TODEVICE); - + /* set tx flags */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); } else { - np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); } - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n", - dev->name, np->next_tx, tx_flags_extra); + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", + dev->name, np->next_tx, entries, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -1093,7 +1130,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dprintk("\n"); } - np->next_tx += 1 + fragments; + np->next_tx += entries; dev->trans_start = jiffies; spin_unlock_irq(&np->lock); @@ -1140,7 +1177,6 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_packets++; np->stats.tx_bytes += skb->len; } - nv_release_txskb(dev, i); } } else { if (Flags & NV_TX2_LASTPACKET) { @@ -1156,9 +1192,9 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_packets++; np->stats.tx_bytes += skb->len; } - nv_release_txskb(dev, i); } } + nv_release_txskb(dev, i); np->nic_tx++; } if (np->next_tx - np->nic_tx < TX_LIMIT_START) @@ -2456,7 +2492,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; #ifdef NETIF_F_TSO - /* disabled dev->features |= NETIF_F_TSO; */ + dev->features |= NETIF_F_TSO; #endif } -- cgit v1.2.3 From 64916f1ebe93592153c72bcdb189a31e4d40049a Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Thu, 5 Jan 2006 22:45:47 -0800 Subject: [PATCH] fix a few "warning: 'cleanup_card' defined but not used" These warnings are emitted if non-modular network drivers are built. Fixes just move cleanup_card() definitions into #ifdef MODULE region. /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/wd.c:131: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/3c503.c:152: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/ne.c:216: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/hp.c:106: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/hp-plus.c:142: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/smc-ultra.c:172: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/e2100.c:144: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/es3210.c:159: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/lne390.c:149: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/lance.c:313: warning: 'cleanup_card' defined but not used /.1/usr/srcdevel/kernel/linux-2.6.15-rc7.src/drivers/net/ac3200.c:127: warning: 'cleanup_card' defined but not used Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/3c503.c | 16 ++++++++-------- drivers/net/ac3200.c | 16 ++++++++-------- drivers/net/e2100.c | 14 +++++++------- drivers/net/es3210.c | 14 +++++++------- drivers/net/hp-plus.c | 12 ++++++------ drivers/net/hp.c | 12 ++++++------ drivers/net/lance.c | 22 +++++++++++----------- drivers/net/lne390.c | 14 +++++++------- drivers/net/ne.c | 18 +++++++++--------- drivers/net/ne2.c | 16 ++++++++-------- drivers/net/smc-ultra.c | 24 ++++++++++++------------ drivers/net/wd.c | 14 +++++++------- 12 files changed, 96 insertions(+), 96 deletions(-) diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 5c5eebdb6914..dcc98afa65d7 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -148,14 +148,6 @@ el2_pio_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: el2_close() handles free_irq */ - release_region(dev->base_addr, EL2_IO_EXTENT); - if (ei_status.mem) - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init el2_probe(int unit) { @@ -726,6 +718,14 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: el2_close() handles free_irq */ + release_region(dev->base_addr, EL2_IO_EXTENT); + if (ei_status.mem) + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 8a0af5453e21..7952dc6d77e3 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -123,14 +123,6 @@ static int __init do_ac3200_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* Someday free_irq may be in ac_close_card() */ - free_irq(dev->irq, dev); - release_region(dev->base_addr, AC_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init ac3200_probe(int unit) { @@ -406,6 +398,14 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* Someday free_irq may be in ac_close_card() */ + free_irq(dev->irq, dev); + release_region(dev->base_addr, AC_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index f5a4dd7d8564..e5c5cd2a2712 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -140,13 +140,6 @@ static int __init do_e2100_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: e21_close() handles free_irq */ - iounmap(ei_status.mem); - release_region(dev->base_addr, E21_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init e2100_probe(int unit) { @@ -463,6 +456,13 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: e21_close() handles free_irq */ + iounmap(ei_status.mem); + release_region(dev->base_addr, E21_IO_EXTENT); +} + void cleanup_module(void) { diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 50f8e23bb9e5..6b0ab1eac3fb 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -155,13 +155,6 @@ static int __init do_es_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr, ES_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init es_probe(int unit) { @@ -456,6 +449,13 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, ES_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 0abf5dd08b4c..74e167e7dea7 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -138,12 +138,6 @@ static int __init do_hpp_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: hpp_close() handles free_irq */ - release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init hp_plus_probe(int unit) { @@ -473,6 +467,12 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: hpp_close() handles free_irq */ + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + void cleanup_module(void) { diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 59cf841b14ab..cf9fb3698a6b 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -102,12 +102,6 @@ static int __init do_hp_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init hp_probe(int unit) { @@ -444,6 +438,12 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + void cleanup_module(void) { diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 1d75ca0bb939..d1d714faa6ce 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -309,17 +309,6 @@ static void lance_tx_timeout (struct net_device *dev); -static void cleanup_card(struct net_device *dev) -{ - struct lance_private *lp = dev->priv; - if (dev->dma != 4) - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(lp->tx_bounce_buffs); - kfree((void*)lp->rx_buffs); - kfree(lp); -} - #ifdef MODULE #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ @@ -367,6 +356,17 @@ int init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + struct lance_private *lp = dev->priv; + if (dev->dma != 4) + free_dma(dev->dma); + release_region(dev->base_addr, LANCE_TOTAL_SIZE); + kfree(lp->tx_bounce_buffs); + kfree((void*)lp->rx_buffs); + kfree(lp); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 309d254842cf..646e89fc3562 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -145,13 +145,6 @@ static int __init do_lne390_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr, LNE390_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init lne390_probe(int unit) { @@ -440,6 +433,13 @@ int init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, LNE390_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 0de8fdd2aa86..94f782d51f0f 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -212,15 +212,6 @@ static int __init do_ne_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init ne_probe(int unit) { @@ -859,6 +850,15 @@ int init_module(void) return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 6d62ada85de6..e6df375a1d4b 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -278,14 +278,6 @@ static int __init do_ne2_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - mca_mark_as_unused(ei_status.priv); - mca_set_adapter_procfn( ei_status.priv, NULL, NULL); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init ne2_probe(int unit) { @@ -812,6 +804,14 @@ int init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + mca_mark_as_unused(ei_status.priv); + mca_set_adapter_procfn( ei_status.priv, NULL, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index ba8593ac3f8a..3db30cd0625e 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -168,18 +168,6 @@ static int __init do_ultra_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: ultra_close_card() does free_irq */ -#ifdef __ISAPNP__ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); -#endif - release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init ultra_probe(int unit) { @@ -594,6 +582,18 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: ultra_close_card() does free_irq */ +#ifdef __ISAPNP__ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); +#endif + release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/wd.c b/drivers/net/wd.c index b03feae459fc..7caa8dc88a58 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -127,13 +127,6 @@ static int __init do_wd_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init wd_probe(int unit) { @@ -538,6 +531,13 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { -- cgit v1.2.3 From 166c3436d683cfe5316c7723ed746a93db053f12 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 9 Jan 2006 11:04:31 -0500 Subject: [patch] ipw2100: support WEXT-18 enc_capa v3 This patch allows ipw2100 driver to advertise the WPA-related encryption options that it does really support. It's necessary to work correctly with NetworkManager and other programs that actually check driver & card capabilities. Signed-off-by: Dan Williams Signed-off-by: Jeff Garzik --- drivers/net/wireless/ipw2100.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 44cd3fcd1572..cf05661fb1bd 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -7153,7 +7153,7 @@ static int ipw2100_wx_get_range(struct net_device *dev, /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; + range->we_version_source = 18; // range->retry_capa; /* What retry options are supported */ // range->retry_flags; /* How to decode max/min retry limit */ @@ -7184,6 +7184,9 @@ static int ipw2100_wx_get_range(struct net_device *dev, IW_EVENT_CAPA_MASK(SIOCGIWAP)); range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + IPW_DEBUG_WX("GET Range\n"); return 0; -- cgit v1.2.3 From 73a59c1c4af06c675a168d698d3ebfbb3270ddbe Mon Sep 17 00:00:00 2001 From: SAN People Date: Mon, 9 Jan 2006 17:05:41 +0000 Subject: [ARM] 3240/2: AT91RM9200 support for 2.6 (Core) Patch from SAN People Following changes were made to clock.c: 1) Replaced with 2) Removed old unused clk_enable & clk_disable. 3) Replaced clk_use/clk_unuse with clk_enable/clk_disable. Otherwise it's the same as the previous patch. Signed-off-by: Andrew Victor Signed-off-by: Russell King --- arch/arm/Kconfig | 11 +- arch/arm/Makefile | 1 + arch/arm/boot/compressed/Makefile | 4 + arch/arm/boot/compressed/head-at91rm9200.S | 57 +++ arch/arm/mach-at91rm9200/Kconfig | 54 ++ arch/arm/mach-at91rm9200/Makefile | 27 + arch/arm/mach-at91rm9200/Makefile.boot | 9 + arch/arm/mach-at91rm9200/clock.c | 620 +++++++++++++++++++++++ arch/arm/mach-at91rm9200/common.c | 115 +++++ arch/arm/mach-at91rm9200/devices.c | 291 +++++++++++ arch/arm/mach-at91rm9200/generic.h | 18 + arch/arm/mach-at91rm9200/gpio.c | 302 +++++++++++ arch/arm/mach-at91rm9200/irq.c | 170 +++++++ arch/arm/mach-at91rm9200/time.c | 127 +++++ arch/arm/mm/Kconfig | 4 +- include/asm-arm/arch-at91rm9200/at91rm9200.h | 261 ++++++++++ include/asm-arm/arch-at91rm9200/at91rm9200_sys.h | 328 ++++++++++++ include/asm-arm/arch-at91rm9200/board.h | 80 +++ include/asm-arm/arch-at91rm9200/debug-macro.S | 38 ++ include/asm-arm/arch-at91rm9200/dma.h | 27 + include/asm-arm/arch-at91rm9200/entry-macro.S | 25 + include/asm-arm/arch-at91rm9200/gpio.h | 193 +++++++ include/asm-arm/arch-at91rm9200/hardware.h | 92 ++++ include/asm-arm/arch-at91rm9200/io.h | 33 ++ include/asm-arm/arch-at91rm9200/irqs.h | 52 ++ include/asm-arm/arch-at91rm9200/memory.h | 41 ++ include/asm-arm/arch-at91rm9200/param.h | 28 + include/asm-arm/arch-at91rm9200/pio.h | 115 +++++ include/asm-arm/arch-at91rm9200/system.h | 51 ++ include/asm-arm/arch-at91rm9200/timex.h | 28 + include/asm-arm/arch-at91rm9200/uncompress.h | 55 ++ include/asm-arm/arch-at91rm9200/vmalloc.h | 26 + 32 files changed, 3280 insertions(+), 3 deletions(-) create mode 100644 arch/arm/boot/compressed/head-at91rm9200.S create mode 100644 arch/arm/mach-at91rm9200/Kconfig create mode 100644 arch/arm/mach-at91rm9200/Makefile create mode 100644 arch/arm/mach-at91rm9200/Makefile.boot create mode 100644 arch/arm/mach-at91rm9200/clock.c create mode 100644 arch/arm/mach-at91rm9200/common.c create mode 100644 arch/arm/mach-at91rm9200/devices.c create mode 100644 arch/arm/mach-at91rm9200/generic.h create mode 100644 arch/arm/mach-at91rm9200/gpio.c create mode 100644 arch/arm/mach-at91rm9200/irq.c create mode 100644 arch/arm/mach-at91rm9200/time.c create mode 100644 include/asm-arm/arch-at91rm9200/at91rm9200.h create mode 100644 include/asm-arm/arch-at91rm9200/at91rm9200_sys.h create mode 100644 include/asm-arm/arch-at91rm9200/board.h create mode 100644 include/asm-arm/arch-at91rm9200/debug-macro.S create mode 100644 include/asm-arm/arch-at91rm9200/dma.h create mode 100644 include/asm-arm/arch-at91rm9200/entry-macro.S create mode 100644 include/asm-arm/arch-at91rm9200/gpio.h create mode 100644 include/asm-arm/arch-at91rm9200/hardware.h create mode 100644 include/asm-arm/arch-at91rm9200/io.h create mode 100644 include/asm-arm/arch-at91rm9200/irqs.h create mode 100644 include/asm-arm/arch-at91rm9200/memory.h create mode 100644 include/asm-arm/arch-at91rm9200/param.h create mode 100644 include/asm-arm/arch-at91rm9200/pio.h create mode 100644 include/asm-arm/arch-at91rm9200/system.h create mode 100644 include/asm-arm/arch-at91rm9200/timex.h create mode 100644 include/asm-arm/arch-at91rm9200/uncompress.h create mode 100644 include/asm-arm/arch-at91rm9200/vmalloc.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 70f388d168db..e149f152e70b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -210,6 +210,12 @@ config ARCH_AAEC2000 help This enables support for systems based on the Agilent AAEC-2000 +config ARCH_AT91RM9200 + bool "AT91RM9200" + help + Say Y here if you intend to run this kernel on an AT91RM9200-based + board. + endchoice source "arch/arm/mach-clps711x/Kconfig" @@ -248,6 +254,8 @@ source "arch/arm/mach-aaec2000/Kconfig" source "arch/arm/mach-realview/Kconfig" +source "arch/arm/mach-at91rm9200/Kconfig" + # Definitions to make life easier config ARCH_ACORN bool @@ -413,7 +421,8 @@ config LEDS ARCH_EBSA285 || ARCH_IMX || ARCH_INTEGRATOR || \ ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \ ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \ - ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE + ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \ + ARCH_AT91RM9200 help If you say Y here, the LEDs on your machine will be used to provide useful information about your current system status. diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 1c056d631153..1fa2a1011584 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -99,6 +99,7 @@ endif machine-$(CONFIG_ARCH_H720X) := h720x machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 machine-$(CONFIG_ARCH_REALVIEW) := realview + machine-$(CONFIG_ARCH_AT91RM9200) := at91rm9200 ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 0009a80498cc..35ffe0f4ece7 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -46,6 +46,10 @@ ifeq ($(CONFIG_PXA_SHARPSL),y) OBJS += head-sharpsl.o endif +ifeq ($(CONFIG_ARCH_AT91RM9200),y) +OBJS += head-at91rm9200.o +endif + ifeq ($(CONFIG_DEBUG_ICEDCC),y) OBJS += ice-dcc.o endif diff --git a/arch/arm/boot/compressed/head-at91rm9200.S b/arch/arm/boot/compressed/head-at91rm9200.S new file mode 100644 index 000000000000..2119ea62b547 --- /dev/null +++ b/arch/arm/boot/compressed/head-at91rm9200.S @@ -0,0 +1,57 @@ +/* + * linux/arch/arm/boot/compressed/head-at91rm9200.S + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include + + .section ".start", "ax" + + @ Atmel AT91RM9200-DK : 262 + mov r3, #(MACH_TYPE_AT91RM9200DK & 0xff) + orr r3, r3, #(MACH_TYPE_AT91RM9200DK & 0xff00) + cmp r7, r3 + beq 99f + + @ Cogent CSB337 : 399 + mov r3, #(MACH_TYPE_CSB337 & 0xff) + orr r3, r3, #(MACH_TYPE_CSB337 & 0xff00) + cmp r7, r3 + beq 99f + + @ Cogent CSB637 : 648 + mov r3, #(MACH_TYPE_CSB637 & 0xff) + orr r3, r3, #(MACH_TYPE_CSB637 & 0xff00) + cmp r7, r3 + beq 99f + + @ Atmel AT91RM9200-EK : 705 + mov r3, #(MACH_TYPE_AT91RM9200EK & 0xff) + orr r3, r3, #(MACH_TYPE_AT91RM9200EK & 0xff00) + cmp r7, r3 + beq 99f + + @ Conitec Carmeva : 769 + mov r3, #(MACH_TYPE_CARMEVA & 0xff) + orr r3, r3, #(MACH_TYPE_CARMEVA & 0xff00) + cmp r7, r3 + beq 99f + + @ KwikByte KB920x : 612 + mov r3, #(MACH_TYPE_KB9200 & 0xff) + orr r3, r3, #(MACH_TYPE_KB9200 & 0xff00) + cmp r7, r3 + beq 99f + + @ Unknown board, use the AT91RM9200DK board + @ mov r7, #MACH_TYPE_AT91RM9200 + mov r7, #(MACH_TYPE_AT91RM9200DK & 0xff) + orr r7, r7, #(MACH_TYPE_AT91RM9200DK & 0xff00) + +99: diff --git a/arch/arm/mach-at91rm9200/Kconfig b/arch/arm/mach-at91rm9200/Kconfig new file mode 100644 index 000000000000..4b7218fc3eb1 --- /dev/null +++ b/arch/arm/mach-at91rm9200/Kconfig @@ -0,0 +1,54 @@ +if ARCH_AT91RM9200 + +menu "AT91RM9200 Implementations" + +comment "AT91RM9200 Board Type" + +config ARCH_AT91RM9200DK + bool "Atmel AT91RM9200-DK Development board" + depends on ARCH_AT91RM9200 + help + Select this if you are using Atmel's AT91RM9200-DK Development board + +config MACH_AT91RM9200EK + bool "Atmel AT91RM9200-EK Evaluation Kit" + depends on ARCH_AT91RM9200 + help + Select this if you are using Atmel's AT91RM9200-EK Evaluation Kit + +config MACH_CSB337 + bool "Cogent CSB337 board" + depends on ARCH_AT91RM9200 + help + Select this if you are using Cogent's CSB337 board + +config MACH_CSB637 + bool "Cogent CSB637 board" + depends on ARCH_AT91RM9200 + help + Select this if you are using Cogent's CSB637 board + +config MACH_CARMEVA + bool "Conitec's ARM&EVA" + depends on ARCH_AT91RM9200 + help + Select this if you are using Conitec's AT91RM9200-MCU-Module + +config MACH_KB9200 + bool "KwikByte's KB920x" + depends on ARCH_AT91RM9200 + help + Select this if you are using KwikByte's KB920x board + + +comment "AT91RM9200 Feature Selections" + +config AT91_PROGRAMMABLE_CLOCKS + bool "Programmable Clocks" + help + Select this if you need to program one or more of the PCK0..PCK3 + programmable clock outputs. + +endmenu + +endif diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91rm9200/Makefile new file mode 100644 index 000000000000..1f2805ca6e21 --- /dev/null +++ b/arch/arm/mach-at91rm9200/Makefile @@ -0,0 +1,27 @@ +# +# Makefile for the linux kernel. +# + +obj-y := clock.o irq.o time.o gpio.o common.o devices.o +obj-m := +obj-n := +obj- := + +# Board-specific support +#obj-$(CONFIG_ARCH_AT91RM9200DK) += board-dk.o +#obj-$(CONFIG_MACH_AT91RM9200EK) += board-ek.o +#obj-$(CONFIG_MACH_CSB337) += board-csb337.o +#obj-$(CONFIG_MACH_CSB637) += board-csb637.o +#obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o +#obj-$(CONFIG_MACH_KB9200) += board-kb9202.o + +# LEDs support +#led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o +#led-$(CONFIG_MACH_AT91RM9200EK) += leds.o +#led-$(CONFIG_MACH_CSB337) += leds.o +#led-$(CONFIG_MACH_CSB637) += leds.o +#led-$(CONFIG_MACH_KB9200) += leds.o +obj-$(CONFIG_LEDS) += $(led-y) + +# VGA support +#obj-$(CONFIG_FB_S1D13XXX) += ics1523.o diff --git a/arch/arm/mach-at91rm9200/Makefile.boot b/arch/arm/mach-at91rm9200/Makefile.boot new file mode 100644 index 000000000000..e667dcc7cd34 --- /dev/null +++ b/arch/arm/mach-at91rm9200/Makefile.boot @@ -0,0 +1,9 @@ +# Note: the following conditions must always be true: +# ZRELADDR == virt_to_phys(TEXTADDR) +# PARAMS_PHYS must be within 4MB of ZRELADDR +# INITRD_PHYS must be in RAM + + zreladdr-y := 0x20008000 +params_phys-y := 0x20000100 +initrd_phys-y := 0x20410000 + diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91rm9200/clock.c new file mode 100644 index 000000000000..ec8195a2a3cc --- /dev/null +++ b/arch/arm/mach-at91rm9200/clock.c @@ -0,0 +1,620 @@ +/* + * linux/arch/arm/mach-at91rm9200/clock.c + * + * Copyright (C) 2005 David Brownell + * Copyright (C) 2005 Ivan Kokshaysky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include /* for master clock global */ + +#include "generic.h" + +#undef DEBUG + +/* + * There's a lot more which can be done with clocks, including cpufreq + * integration, slow clock mode support (for system suspend), letting + * PLLB be used at other rates (on boards that don't need USB), etc. + */ + +struct clk { + const char *name; + unsigned long rate_hz; + struct clk *parent; + u32 pmc_mask; + void (*mode)(struct clk *, int); + unsigned id:2; /* PCK0..3, or 32k/main/a/b */ + unsigned primary:1; + unsigned pll:1; + unsigned programmable:1; + u16 users; +}; + +static spinlock_t clk_lock; +static u32 at91_pllb_usb_init; + +/* + * Four primary clock sources: two crystal oscillators (32K, main), and + * two PLLs. PLLA usually runs the master clock; and PLLB must run at + * 48 MHz (unless no USB function clocks are needed). The main clock and + * both PLLs are turned off to run in "slow clock mode" (system suspend). + */ +static struct clk clk32k = { + .name = "clk32k", + .rate_hz = AT91_SLOW_CLOCK, + .users = 1, /* always on */ + .id = 0, + .primary = 1, +}; +static struct clk main_clk = { + .name = "main", + .pmc_mask = 1 << 0, /* in PMC_SR */ + .users = 1, + .id = 1, + .primary = 1, +}; +static struct clk plla = { + .name = "plla", + .parent = &main_clk, + .pmc_mask = 1 << 1, /* in PMC_SR */ + .id = 2, + .primary = 1, + .pll = 1, +}; + +static void pllb_mode(struct clk *clk, int is_on) +{ + u32 value; + + if (is_on) { + is_on = AT91_PMC_LOCKB; + value = at91_pllb_usb_init; + } else + value = 0; + + at91_sys_write(AT91_CKGR_PLLBR, value); + + do { + cpu_relax(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on); +} + +static struct clk pllb = { + .name = "pllb", + .parent = &main_clk, + .pmc_mask = 1 << 2, /* in PMC_SR */ + .mode = pllb_mode, + .id = 3, + .primary = 1, + .pll = 1, +}; + +static void pmc_sys_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_SCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask); +} + +/* USB function clocks (PLLB must be 48 MHz) */ +static struct clk udpck = { + .name = "udpck", + .parent = &pllb, + .pmc_mask = AT91_PMC_UDP, + .mode = pmc_sys_mode, +}; +static struct clk uhpck = { + .name = "uhpck", + .parent = &pllb, + .pmc_mask = AT91_PMC_UHP, + .mode = pmc_sys_mode, +}; + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS +/* + * The four programmable clocks can be parented by any primary clock. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .mode = pmc_sys_mode, + .programmable = 1, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .mode = pmc_sys_mode, + .programmable = 1, + .id = 1, +}; +static struct clk pck2 = { + .name = "pck2", + .pmc_mask = AT91_PMC_PCK2, + .mode = pmc_sys_mode, + .programmable = 1, + .id = 2, +}; +static struct clk pck3 = { + .name = "pck3", + .pmc_mask = AT91_PMC_PCK3, + .mode = pmc_sys_mode, + .programmable = 1, + .id = 3, +}; +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + + +/* + * The master clock is divided from the CPU clock (by 1-4). It's used for + * memory, interfaces to on-chip peripherals, the AIC, and sometimes more + * (e.g baud rate generation). It's sourced from one of the primary clocks. + */ +static struct clk mck = { + .name = "mck", + .pmc_mask = 1 << 3, /* in PMC_SR */ + .users = 1, /* (must be) always on */ +}; + +static void pmc_periph_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_PCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask); +} + +static struct clk udc_clk = { + .name = "udc_clk", + .parent = &mck, + .pmc_mask = 1 << AT91_ID_UDP, + .mode = pmc_periph_mode, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .parent = &mck, + .pmc_mask = 1 << AT91_ID_UHP, + .mode = pmc_periph_mode, +}; + +static struct clk *const clock_list[] = { + /* four primary clocks -- MUST BE FIRST! */ + &clk32k, + &main_clk, + &plla, + &pllb, + + /* PLLB children (USB) */ + &udpck, + &uhpck, + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + /* programmable clocks */ + &pck0, + &pck1, + &pck2, + &pck3, +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + + /* MCK and peripherals */ + &mck, + // usart0..usart3 + // mmc + &udc_clk, + // i2c + // spi + // ssc0..ssc2 + // tc0..tc5 + &ohci_clk, + // ether +}; + + +/* clocks are all static for now; no refcounting necessary */ +struct clk *clk_get(struct device *dev, const char *id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clock_list); i++) { + if (strcmp(id, clock_list[i]->name) == 0) + return clock_list[i]; + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +static void __clk_enable(struct clk *clk) +{ + if (clk->parent) + __clk_enable(clk->parent); + if (clk->users++ == 0 && clk->mode) + clk->mode(clk, 1); +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clk_lock, flags); + __clk_enable(clk); + spin_unlock_irqrestore(&clk_lock, flags); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +static void __clk_disable(struct clk *clk) +{ + BUG_ON(clk->users == 0); + if (--clk->users == 0 && clk->mode) + clk->mode(clk, 0); + if (clk->parent) + __clk_disable(clk->parent); +} + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clk_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clk_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long flags; + unsigned long rate; + + spin_lock_irqsave(&clk_lock, flags); + for (;;) { + rate = clk->rate_hz; + if (rate || !clk->parent) + break; + clk = clk->parent; + } + spin_unlock_irqrestore(&clk_lock, flags); + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +/*------------------------------------------------------------------------*/ + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + +/* + * For now, only the programmable clocks support reparenting (MCK could + * do this too, with care) or rate changing (the PLLs could do this too, + * ditto MCK but that's more for cpufreq). Drivers may reparent to get + * a better rate match; we don't. + */ + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + + if (!clk->programmable) + return -EINVAL; + spin_lock_irqsave(&clk_lock, flags); + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual && actual <= rate) + break; + actual >>= 1; + } + + spin_unlock_irqrestore(&clk_lock, flags); + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + + if (!clk->programmable) + return -EINVAL; + if (clk->users) + return -EBUSY; + spin_lock_irqsave(&clk_lock, flags); + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual && actual <= rate) { + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + pckr &= 0x03; + pckr |= prescale << 2; + at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); + clk->rate_hz = actual; + break; + } + actual >>= 1; + } + + spin_unlock_irqrestore(&clk_lock, flags); + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_set_rate); + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + + if (clk->users) + return -EBUSY; + if (!parent->primary || !clk->programmable) + return -EINVAL; + spin_lock_irqsave(&clk_lock, flags); + + clk->rate_hz = parent->rate_hz; + clk->parent = parent; + at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id); + + spin_unlock_irqrestore(&clk_lock, flags); + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + +/*------------------------------------------------------------------------*/ + +#ifdef CONFIG_DEBUG_FS + +static int at91_clk_show(struct seq_file *s, void *unused) +{ + u32 scsr, pcsr, sr; + unsigned i; + + seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR)); + seq_printf(s, "PCSR = %8x\n", pcsr = at91_sys_read(AT91_PMC_PCSR)); + + seq_printf(s, "MOR = %8x\n", at91_sys_read(AT91_CKGR_MOR)); + seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); + seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); + seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); + + seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); + for (i = 0; i < 4; i++) + seq_printf(s, "PCK%d = %8x\n", i, at91_sys_read(AT91_PMC_PCKR(i))); + seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); + + seq_printf(s, "\n"); + + for (i = 0; i < ARRAY_SIZE(clock_list); i++) { + char *state; + struct clk *clk = clock_list[i]; + + if (clk->mode == pmc_sys_mode) + state = (scsr & clk->pmc_mask) ? "on" : "off"; + else if (clk->mode == pmc_periph_mode) + state = (pcsr & clk->pmc_mask) ? "on" : "off"; + else if (clk->pmc_mask) + state = (sr & clk->pmc_mask) ? "on" : "off"; + else if (clk == &clk32k || clk == &main_clk) + state = "on"; + else + state = ""; + + seq_printf(s, "%-10s users=%d %-3s %9ld Hz %s\n", + clk->name, clk->users, state, clk_get_rate(clk), + clk->parent ? clk->parent->name : ""); + } + return 0; +} + +static int at91_clk_open(struct inode *inode, struct file *file) +{ + return single_open(file, at91_clk_show, NULL); +} + +static struct file_operations at91_clk_operations = { + .open = at91_clk_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init at91_clk_debugfs_init(void) +{ + /* /sys/kernel/debug/at91_clk */ + (void) debugfs_create_file("at91_clk", S_IFREG | S_IRUGO, NULL, NULL, &at91_clk_operations); + + return 0; +} +postcore_initcall(at91_clk_debugfs_init); + +#endif + +/*------------------------------------------------------------------------*/ + +static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg) +{ + unsigned mul, div; + + div = reg & 0xff; + mul = (reg >> 16) & 0x7ff; + if (div && mul) { + freq /= div; + freq *= mul + 1; + } else + freq = 0; + if (pll == &pllb && (reg & (1 << 28))) + freq /= 2; + return freq; +} + +static unsigned __init at91_pll_calc(unsigned main_freq, unsigned out_freq) +{ + unsigned i, div = 0, mul = 0, diff = 1 << 30; + unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + + /* PLL output max 240 MHz (or 180 MHz per errata) */ + if (out_freq > 240000000) + goto fail; + + for (i = 1; i < 256; i++) { + int diff1; + unsigned input, mul1; + + /* + * PLL input between 1MHz and 32MHz per spec, but lower + * frequences seem necessary in some cases so allow 100K. + */ + input = main_freq / i; + if (input < 100000) + continue; + if (input > 32000000) + continue; + + mul1 = out_freq / input; + if (mul1 > 2048) + continue; + if (mul1 < 2) + goto fail; + + diff1 = out_freq - input * mul1; + if (diff1 < 0) + diff1 = -diff1; + if (diff > diff1) { + diff = diff1; + div = i; + mul = mul1; + if (diff == 0) + break; + } + } + if (i == 256 && diff > (out_freq >> 5)) + goto fail; + return ret | ((mul - 1) << 16) | div; +fail: + return 0; +} + +int __init at91_clock_init(unsigned long main_clock) +{ + unsigned tmp, freq, mckr; + + spin_lock_init(&clk_lock); + + /* + * When the bootloader initialized the main oscillator correctly, + * there's no problem using the cycle counter. But if it didn't, + * or when using oscillator bypass mode, we must be told the speed + * of the main clock. + */ + if (!main_clock) { + do { + tmp = at91_sys_read(AT91_CKGR_MCFR); + } while (!(tmp & 0x10000)); + main_clock = (tmp & 0xffff) * (AT91_SLOW_CLOCK / 16); + } + main_clk.rate_hz = main_clock; + + /* report if PLLA is more than mildly overclocked */ + plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR)); + if (plla.rate_hz > 209000000) + pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); + + /* + * USB clock init: choose 48 MHz PLLB value, turn all clocks off, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | 0x10000000; + pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init); + at91_sys_write(AT91_PMC_PCDR, (1 << AT91_ID_UHP) | (1 << AT91_ID_UDP)); + at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP | AT91_PMC_UDP); + at91_sys_write(AT91_CKGR_PLLBR, 0); + at91_sys_write(AT91_PMC_SCER, AT91_PMC_MCKUDP); + + /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ + mckr = at91_sys_read(AT91_PMC_MCKR); + mck.parent = clock_list[mckr & AT91_PMC_CSS]; + mck.parent->users++; + freq = mck.parent->rate_hz; + freq /= (1 << ((mckr >> 2) & 3)); /* prescale */ + mck.rate_hz = freq / (1 + ((mckr >> 8) & 3)); /* mdiv */ + + printk("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n", + freq / 1000000, (unsigned) mck.rate_hz / 1000000, + (unsigned) main_clock / 1000000, + ((unsigned) main_clock % 1000000) / 1000); + + /* FIXME get rid of master_clock global */ + at91_master_clock = mck.rate_hz; + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + /* establish PCK0..PCK3 parentage */ + for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) { + struct clk *clk = clock_list[tmp], *parent; + u32 pckr; + + if (!clk->programmable) + continue; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + parent = clock_list[pckr & 3]; + clk->parent = parent; + clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3)); + } +#else + /* disable unused clocks */ + at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3); +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + + /* FIXME several unused clocks may still be active... provide + * a CONFIG option to turn off all unused clocks at some point + * before driver init starts. + */ + + return 0; +} diff --git a/arch/arm/mach-at91rm9200/common.c b/arch/arm/mach-at91rm9200/common.c new file mode 100644 index 000000000000..3848fd2d5596 --- /dev/null +++ b/arch/arm/mach-at91rm9200/common.c @@ -0,0 +1,115 @@ +/* + * arch/arm/mach-at91rm9200/common.c + * + * Copyright (C) 2005 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include + +#include +#include + +#include + +static struct map_desc at91rm9200_io_desc[] __initdata = { + { + .virtual = AT91_VA_BASE_SYS, + .pfn = __phys_to_pfn(AT91_BASE_SYS), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_SPI, + .pfn = __phys_to_pfn(AT91_BASE_SPI), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_SSC2, + .pfn = __phys_to_pfn(AT91_BASE_SSC2), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_SSC1, + .pfn = __phys_to_pfn(AT91_BASE_SSC1), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_SSC0, + .pfn = __phys_to_pfn(AT91_BASE_SSC0), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_US3, + .pfn = __phys_to_pfn(AT91_BASE_US3), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_US2, + .pfn = __phys_to_pfn(AT91_BASE_US2), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_US1, + .pfn = __phys_to_pfn(AT91_BASE_US1), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_US0, + .pfn = __phys_to_pfn(AT91_BASE_US0), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_EMAC, + .pfn = __phys_to_pfn(AT91_BASE_EMAC), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_TWI, + .pfn = __phys_to_pfn(AT91_BASE_TWI), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_MCI, + .pfn = __phys_to_pfn(AT91_BASE_MCI), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_UDP, + .pfn = __phys_to_pfn(AT91_BASE_UDP), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_TCB1, + .pfn = __phys_to_pfn(AT91_BASE_TCB1), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = AT91_VA_BASE_TCB0, + .pfn = __phys_to_pfn(AT91_BASE_TCB0), + .length = SZ_16K, + .type = MT_DEVICE, + }, +}; + +void __init at91rm9200_map_io(void) +{ + iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc)); +} + + +unsigned long at91_master_clock; + +EXPORT_SYMBOL(at91_master_clock); + + +int at91_serial_map[AT91_NR_UART]; +int at91_console_port; + +EXPORT_SYMBOL(at91_serial_map); +EXPORT_SYMBOL(at91_console_port); diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c new file mode 100644 index 000000000000..8df3e5245651 --- /dev/null +++ b/arch/arm/mach-at91rm9200/devices.c @@ -0,0 +1,291 @@ +/* + * arch/arm/mach-at91rm9200/devices.c + * + * Copyright (C) 2005 Thibaut VARENE + * Copyright (C) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include + +#include +#include + +#include +#include + + +/* -------------------------------------------------------------------- + * USB Host + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +static u64 ohci_dmamask = 0xffffffffUL; +static struct at91_usbh_data usbh_data; + +static struct resource at91rm9200_usbh_resource[] = { + [0] = { + .start = AT91_UHP_BASE, + .end = AT91_UHP_BASE + SZ_1M -1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91_ID_UHP, + .end = AT91_ID_UHP, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91rm9200_usbh_device = { + .name = "at91rm9200-ohci", + .id = -1, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &usbh_data, + }, + .resource = at91rm9200_usbh_resource, + .num_resources = ARRAY_SIZE(at91rm9200_usbh_resource), +}; + +void __init at91_add_device_usbh(struct at91_usbh_data *data) +{ + if (!data) + return; + + usbh_data = *data; + platform_device_register(&at91rm9200_usbh_device); +} +#else +void __init at91_add_device_usbh(struct at91_usbh_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_AT91 +static struct at91_udc_data udc_data; + +static struct resource at91_udc_resources[] = { + { + .start = AT91_BASE_UDP, + .end = AT91_BASE_UDP + SZ_16K - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at91rm9200_udc_device = { + .name = "at91_udc", + .id = -1, + .dev = { + .platform_data = &udc_data, + }, + .resource = at91_udc_resources, + .num_resources = ARRAY_SIZE(at91_udc_resources), +}; + +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (!data) + return; + + if (data->vbus_pin) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + if (data->pullup_pin) + at91_set_gpio_output(data->pullup_pin, 0); + + udc_data = *data; + platform_device_register(&at91rm9200_udc_device); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * Ethernet + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_ARM_AT91_ETHER) || defined(CONFIG_ARM_AT91_ETHER_MODULE) +static u64 eth_dmamask = 0xffffffffUL; +static struct at91_eth_data eth_data; + +static struct platform_device at91rm9200_eth_device = { + .name = "at91_ether", + .id = -1, + .dev = { + .dma_mask = ð_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = ð_data, + }, + .num_resources = 0, +}; + +void __init at91_add_device_eth(struct at91_eth_data *data) +{ + if (!data) + return; + + if (data->phy_irq_pin) { + at91_set_gpio_input(data->phy_irq_pin, 0); + at91_set_deglitch(data->phy_irq_pin, 1); + } + + /* Pins used for MII and RMII */ + at91_set_A_periph(AT91_PIN_PA16, 0); /* EMDIO */ + at91_set_A_periph(AT91_PIN_PA15, 0); /* EMDC */ + at91_set_A_periph(AT91_PIN_PA14, 0); /* ERXER */ + at91_set_A_periph(AT91_PIN_PA13, 0); /* ERX1 */ + at91_set_A_periph(AT91_PIN_PA12, 0); /* ERX0 */ + at91_set_A_periph(AT91_PIN_PA11, 0); /* ECRS_ECRSDV */ + at91_set_A_periph(AT91_PIN_PA10, 0); /* ETX1 */ + at91_set_A_periph(AT91_PIN_PA9, 0); /* ETX0 */ + at91_set_A_periph(AT91_PIN_PA8, 0); /* ETXEN */ + at91_set_A_periph(AT91_PIN_PA7, 0); /* ETXCK_EREFCK */ + + if (!data->is_rmii) { + at91_set_B_periph(AT91_PIN_PB19, 0); /* ERXCK */ + at91_set_B_periph(AT91_PIN_PB18, 0); /* ECOL */ + at91_set_B_periph(AT91_PIN_PB17, 0); /* ERXDV */ + at91_set_B_periph(AT91_PIN_PB16, 0); /* ERX3 */ + at91_set_B_periph(AT91_PIN_PB15, 0); /* ERX2 */ + at91_set_B_periph(AT91_PIN_PB14, 0); /* ETXER */ + at91_set_B_periph(AT91_PIN_PB13, 0); /* ETX3 */ + at91_set_B_periph(AT91_PIN_PB12, 0); /* ETX2 */ + } + + eth_data = *data; + platform_device_register(&at91rm9200_eth_device); +} +#else +void __init at91_add_device_eth(struct at91_eth_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * Compact Flash / PCMCIA + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE) +static struct at91_cf_data cf_data; + +static struct platform_device at91rm9200_cf_device = { + .name = "at91_cf", + .id = -1, + .dev = { + .platform_data = &cf_data, + }, + .num_resources = 0, +}; + +void __init at91_add_device_cf(struct at91_cf_data *data) +{ + if (!data) + return; + + /* input/irq */ + if (data->irq_pin) { + at91_set_gpio_input(data->irq_pin, 1); + at91_set_deglitch(data->irq_pin, 1); + } + at91_set_gpio_input(data->det_pin, 1); + at91_set_deglitch(data->det_pin, 1); + + /* outputs, initially off */ + if (data->vcc_pin) + at91_set_gpio_output(data->vcc_pin, 0); + at91_set_gpio_output(data->rst_pin, 0); + + cf_data = *data; + platform_device_register(&at91rm9200_cf_device); +} +#else +void __init at91_add_device_cf(struct at91_cf_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * MMC / SD + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MMC_AT91RM9200) || defined(CONFIG_MMC_AT91RM9200_MODULE) +static u64 mmc_dmamask = 0xffffffffUL; +static struct at91_mmc_data mmc_data; + +static struct resource at91_mmc_resources[] = { + { + .start = AT91_BASE_MCI, + .end = AT91_BASE_MCI + SZ_16K - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at91rm9200_mmc_device = { + .name = "at91rm9200_mci", + .id = -1, + .dev = { + .dma_mask = &mmc_dmamask, + .coherent_dma_mask = 0xffffffff, + .platform_data = &mmc_data, + }, + .resource = at91_mmc_resources, + .num_resources = ARRAY_SIZE(at91_mmc_resources), +}; + +void __init at91_add_device_mmc(struct at91_mmc_data *data) +{ + if (!data) + return; + + /* input/irq */ + if (data->det_pin) { + at91_set_gpio_input(data->det_pin, 1); + at91_set_deglitch(data->det_pin, 1); + } + if (data->wp_pin) + at91_set_gpio_input(data->wp_pin, 1); + + /* CLK */ + at91_set_A_periph(AT91_PIN_PA27, 0); + + if (data->is_b) { + /* CMD */ + at91_set_B_periph(AT91_PIN_PA8, 0); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_B_periph(AT91_PIN_PA9, 0); + if (data->wire4) { + at91_set_B_periph(AT91_PIN_PA10, 0); + at91_set_B_periph(AT91_PIN_PA11, 0); + at91_set_B_periph(AT91_PIN_PA12, 0); + } + } else { + /* CMD */ + at91_set_A_periph(AT91_PIN_PA28, 0); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA29, 0); + if (data->wire4) { + at91_set_B_periph(AT91_PIN_PB3, 0); + at91_set_B_periph(AT91_PIN_PB4, 0); + at91_set_B_periph(AT91_PIN_PB5, 0); + } + } + + mmc_data = *data; + platform_device_register(&at91rm9200_mmc_device); +} +#else +void __init at91_add_device_mmc(struct at91_mmc_data *data) {} +#endif + +/* -------------------------------------------------------------------- */ diff --git a/arch/arm/mach-at91rm9200/generic.h b/arch/arm/mach-at91rm9200/generic.h new file mode 100644 index 000000000000..9bd541eba0a0 --- /dev/null +++ b/arch/arm/mach-at91rm9200/generic.h @@ -0,0 +1,18 @@ +/* + * linux/arch/arm/mach-at91rm9200/generic.h + * + * Copyright (C) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +void at91_gpio_irq_setup(unsigned banks); + +struct sys_timer; +extern struct sys_timer at91rm9200_timer; + +extern void __init at91rm9200_map_io(void); + +extern int __init at91_clock_init(unsigned long main_clock); diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c new file mode 100644 index 000000000000..2fd2ef583e4d --- /dev/null +++ b/arch/arm/mach-at91rm9200/gpio.c @@ -0,0 +1,302 @@ +/* + * linux/arch/arm/mach-at91rm9200/gpio.c + * + * Copyright (C) 2005 HP Labs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +static const u32 pio_controller_offset[4] = { + AT91_PIOA, + AT91_PIOB, + AT91_PIOC, + AT91_PIOD, +}; + +static inline void __iomem *pin_to_controller(unsigned pin) +{ + void __iomem *sys_base = (void __iomem *) AT91_VA_BASE_SYS; + + pin -= PIN_BASE; + pin /= 32; + if (likely(pin < BGA_GPIO_BANKS)) + return sys_base + pio_controller_offset[pin]; + + return NULL; +} + +static inline unsigned pin_to_mask(unsigned pin) +{ + pin -= PIN_BASE; + return 1 << (pin % 32); +} + + +/*--------------------------------------------------------------------------*/ + +/* Not all hardware capabilities are exposed through these calls; they + * only encapsulate the most common features and modes. (So if you + * want to change signals in groups, do it directly.) + * + * Bootloaders will usually handle some of the pin multiplexing setup. + * The intent is certainly that by the time Linux is fully booted, all + * pins should have been fully initialized. These setup calls should + * only be used by board setup routines, or possibly in driver probe(). + * + * For bootloaders doing all that setup, these calls could be inlined + * as NOPs so Linux won't duplicate any setup code + */ + + +/* + * mux the pin to the "A" internal peripheral role. + */ +int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(mask, pio + PIO_ASR); + __raw_writel(mask, pio + PIO_PDR); + return 0; +} +EXPORT_SYMBOL(at91_set_A_periph); + + +/* + * mux the pin to the "B" internal peripheral role. + */ +int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(mask, pio + PIO_BSR); + __raw_writel(mask, pio + PIO_PDR); + return 0; +} +EXPORT_SYMBOL(at91_set_B_periph); + + +/* + * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and + * configure it for an input. + */ +int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(mask, pio + PIO_ODR); + __raw_writel(mask, pio + PIO_PER); + return 0; +} +EXPORT_SYMBOL(at91_set_gpio_input); + + +/* + * mux the pin to the gpio controller (instead of "A" or "B" peripheral), + * and configure it for an output. + */ +int __init_or_module at91_set_gpio_output(unsigned pin, int value) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + PIO_PUDR); + __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR)); + __raw_writel(mask, pio + PIO_OER); + __raw_writel(mask, pio + PIO_PER); + return 0; +} +EXPORT_SYMBOL(at91_set_gpio_output); + + +/* + * enable/disable the glitch filter; mostly used with IRQ handling. + */ +int __init_or_module at91_set_deglitch(unsigned pin, int is_on) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); + return 0; +} +EXPORT_SYMBOL(at91_set_deglitch); + +/*--------------------------------------------------------------------------*/ + + +/* + * assuming the pin is muxed as a gpio output, set its value. + */ +int at91_set_gpio_value(unsigned pin, int value) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio) + return -EINVAL; + __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR)); + return 0; +} +EXPORT_SYMBOL(at91_set_gpio_value); + + +/* + * read the pin's value (works even if it's not muxed as a gpio). + */ +int at91_get_gpio_value(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + u32 pdsr; + + if (!pio) + return -EINVAL; + pdsr = __raw_readl(pio + PIO_PDSR); + return (pdsr & mask) != 0; +} +EXPORT_SYMBOL(at91_get_gpio_value); + +/*--------------------------------------------------------------------------*/ + + +/* Several AIC controller irqs are dispatched through this GPIO handler. + * To use any AT91_PIN_* as an externally triggered IRQ, first call + * at91_set_gpio_input() then maybe enable its glitch filter. + * Then just request_irq() with the pin ID; it works like any ARM IRQ + * handler, though it always triggers on rising and falling edges. + * + * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after + * configuring them with at91_set_a_periph() or at91_set_b_periph(). + * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering. + */ + +static void gpio_irq_mask(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (pio) + __raw_writel(mask, pio + PIO_IDR); +} + +static void gpio_irq_unmask(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (pio) + __raw_writel(mask, pio + PIO_IER); +} + +static int gpio_irq_type(unsigned pin, unsigned type) +{ + return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL; +} + +static struct irqchip gpio_irqchip = { + .mask = gpio_irq_mask, + .unmask = gpio_irq_unmask, + .set_type = gpio_irq_type, +}; + +static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs) +{ + unsigned pin; + struct irqdesc *gpio; + void __iomem *pio; + u32 isr; + + pio = (void __force __iomem *) desc->chipdata; + + /* temporarily mask (level sensitive) parent IRQ */ + desc->chip->ack(irq); + for (;;) { + isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR); + if (!isr) + break; + + pin = (unsigned) desc->data; + gpio = &irq_desc[pin]; + + while (isr) { + if (isr & 1) + gpio->handle(pin, gpio, regs); + pin++; + gpio++; + isr >>= 1; + } + } + desc->chip->unmask(irq); + /* now it may re-trigger */ +} + +/* call this from board-specific init_irq */ +void __init at91_gpio_irq_setup(unsigned banks) +{ + unsigned pioc, pin, id; + + if (banks > 4) + banks = 4; + for (pioc = 0, pin = PIN_BASE, id = AT91_ID_PIOA; + pioc < banks; + pioc++, id++) { + void __iomem *controller; + unsigned i; + + controller = (void __iomem *) AT91_VA_BASE_SYS + pio_controller_offset[pioc]; + __raw_writel(~0, controller + PIO_IDR); + + set_irq_data(id, (void *) pin); + set_irq_chipdata(id, (void __force *) controller); + + for (i = 0; i < 32; i++, pin++) { + set_irq_chip(pin, &gpio_irqchip); + set_irq_handler(pin, do_simple_IRQ); + set_irq_flags(pin, IRQF_VALID); + } + + set_irq_chained_handler(id, gpio_irq_handler); + + /* enable the PIO peripheral clock */ + at91_sys_write(AT91_PMC_PCER, 1 << id); + } + pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, banks); +} diff --git a/arch/arm/mach-at91rm9200/irq.c b/arch/arm/mach-at91rm9200/irq.c new file mode 100644 index 000000000000..cb62bc83a1dd --- /dev/null +++ b/arch/arm/mach-at91rm9200/irq.c @@ -0,0 +1,170 @@ +/* + * linux/arch/arm/mach-at91rm9200/irq.c + * + * Copyright (C) 2004 SAN People + * Copyright (C) 2004 ATMEL + * Copyright (C) Rick Bronson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "generic.h" + +/* + * The default interrupt priority levels (0 = lowest, 7 = highest). + */ +static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = { + 7, /* Advanced Interrupt Controller */ + 7, /* System Peripheral */ + 0, /* Parallel IO Controller A */ + 0, /* Parallel IO Controller B */ + 0, /* Parallel IO Controller C */ + 0, /* Parallel IO Controller D */ + 6, /* USART 0 */ + 6, /* USART 1 */ + 6, /* USART 2 */ + 6, /* USART 3 */ + 0, /* Multimedia Card Interface */ + 4, /* USB Device Port */ + 0, /* Two-Wire Interface */ + 6, /* Serial Peripheral Interface */ + 5, /* Serial Synchronous Controller */ + 5, /* Serial Synchronous Controller */ + 5, /* Serial Synchronous Controller */ + 0, /* Timer Counter 0 */ + 0, /* Timer Counter 1 */ + 0, /* Timer Counter 2 */ + 0, /* Timer Counter 3 */ + 0, /* Timer Counter 4 */ + 0, /* Timer Counter 5 */ + 3, /* USB Host port */ + 3, /* Ethernet MAC */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0 /* Advanced Interrupt Controller */ +}; + + +static void at91rm9200_mask_irq(unsigned int irq) +{ + /* Disable interrupt on AIC */ + at91_sys_write(AT91_AIC_IDCR, 1 << irq); +} + +static void at91rm9200_unmask_irq(unsigned int irq) +{ + /* Enable interrupt on AIC */ + at91_sys_write(AT91_AIC_IECR, 1 << irq); +} + +static int at91rm9200_irq_type(unsigned irq, unsigned type) +{ + unsigned int smr, srctype; + + /* change triggering only for FIQ and external IRQ0..IRQ6 */ + if ((irq < AT91_ID_IRQ0) && (irq != AT91_ID_FIQ)) + return -EINVAL; + + switch (type) { + case IRQT_HIGH: + srctype = AT91_AIC_SRCTYPE_HIGH; + break; + case IRQT_RISING: + srctype = AT91_AIC_SRCTYPE_RISING; + break; + case IRQT_LOW: + srctype = AT91_AIC_SRCTYPE_LOW; + break; + case IRQT_FALLING: + srctype = AT91_AIC_SRCTYPE_FALLING; + break; + default: + return -EINVAL; + } + + smr = at91_sys_read(AT91_AIC_SMR(irq)) & ~AT91_AIC_SRCTYPE; + at91_sys_write(AT91_AIC_SMR(irq), smr | srctype); + return 0; +} + +static struct irqchip at91rm9200_irq_chip = { + .ack = at91rm9200_mask_irq, + .mask = at91rm9200_mask_irq, + .unmask = at91rm9200_unmask_irq, + .set_type = at91rm9200_irq_type, +}; + +/* + * Initialize the AIC interrupt controller. + */ +void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS]) +{ + unsigned int i; + + /* No priority list specified for this board -> use defaults */ + if (priority == NULL) + priority = at91rm9200_default_irq_priority; + + /* + * The IVR is used by macro get_irqnr_and_base to read and verify. + * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. + */ + for (i = 0; i < NR_AIC_IRQS; i++) { + /* Put irq number in Source Vector Register: */ + at91_sys_write(AT91_AIC_SVR(i), i); + /* Store the Source Mode Register as defined in table above */ + at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); + + set_irq_chip(i, &at91rm9200_irq_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + + /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */ + if (i < 8) + at91_sys_write(AT91_AIC_EOICR, 0); + } + + /* + * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS + * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU + */ + at91_sys_write(AT91_AIC_SPU, NR_AIC_IRQS); + + /* No debugging in AIC: Debug (Protect) Control Register */ + at91_sys_write(AT91_AIC_DCR, 0); + + /* Disable and clear all interrupts initially */ + at91_sys_write(AT91_AIC_IDCR, 0xFFFFFFFF); + at91_sys_write(AT91_AIC_ICCR, 0xFFFFFFFF); +} diff --git a/arch/arm/mach-at91rm9200/time.c b/arch/arm/mach-at91rm9200/time.c new file mode 100644 index 000000000000..1b6dd2deeb22 --- /dev/null +++ b/arch/arm/mach-at91rm9200/time.c @@ -0,0 +1,127 @@ +/* + * linux/arch/arm/mach-at91rm9200/time.c + * + * Copyright (C) 2003 SAN People + * Copyright (C) 2003 ATMEL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * The ST_CRTR is updated asynchronously to the master clock. It is therefore + * necessary to read it twice (with the same value) to ensure accuracy. + */ +static inline unsigned long read_CRTR(void) { + unsigned long x1, x2; + + do { + x1 = at91_sys_read(AT91_ST_CRTR); + x2 = at91_sys_read(AT91_ST_CRTR); + } while (x1 != x2); + + return x1; +} + +/* + * Returns number of microseconds since last timer interrupt. Note that interrupts + * will have been disabled by do_gettimeofday() + * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. + * 'tick' is usecs per jiffy (linux/timex.h). + */ +static unsigned long at91rm9200_gettimeoffset(void) +{ + unsigned long elapsed; + + elapsed = (read_CRTR() - at91_sys_read(AT91_ST_RTAR)) & AT91_ST_ALMV; + + return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH; +} + +/* + * IRQ handler for the timer. + */ +static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long rtar; + + if (at91_sys_read(AT91_ST_SR) & AT91_ST_PITS) { /* This is a shared interrupt */ + write_seqlock(&xtime_lock); + + do { + timer_tick(regs); + rtar = (at91_sys_read(AT91_ST_RTAR) + LATCH) & AT91_ST_ALMV; + at91_sys_write(AT91_ST_RTAR, rtar); + } while (((read_CRTR() - at91_sys_read(AT91_ST_RTAR)) & AT91_ST_ALMV) >= LATCH); + + write_sequnlock(&xtime_lock); + + return IRQ_HANDLED; + } + else + return IRQ_NONE; /* not handled */ +} + +static struct irqaction at91rm9200_timer_irq = { + .name = "at91_tick", + .flags = SA_SHIRQ | SA_INTERRUPT, + .handler = at91rm9200_timer_interrupt +}; + +/* + * Set up timer interrupt. + */ +void __init at91rm9200_timer_init(void) +{ + /* Disable all timer interrupts */ + at91_sys_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS); + (void) at91_sys_read(AT91_ST_SR); /* Clear any pending interrupts */ + + /* + * Make IRQs happen for the system timer. + */ + setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq); + + /* Set initial alarm to 0 */ + at91_sys_write(AT91_ST_RTAR, 0); + + /* Real time counter incremented every 30.51758 microseconds */ + at91_sys_write(AT91_ST_RTMR, 1); + + /* Set Period Interval timer */ + at91_sys_write(AT91_ST_PIMR, LATCH); + + /* Change the kernel's 'tick' value to 10009 usec. (the default is 10000) */ + tick_usec = (LATCH * 1000000) / CLOCK_TICK_RATE; + + /* Enable Period Interval Timer interrupt */ + at91_sys_write(AT91_ST_IER, AT91_ST_PITS); +} + +struct sys_timer at91rm9200_timer = { + .init = at91rm9200_timer_init, + .offset = at91rm9200_gettimeoffset, +}; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 04cf0557e54b..3b79d0e23455 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -62,8 +62,8 @@ config CPU_ARM720T # ARM920T config CPU_ARM920T bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 - default y if ARCH_S3C2410 + depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 + default y if ARCH_S3C2410 || ARCH_AT91RM9200 select CPU_32v4 select CPU_ABRT_EV4T select CPU_CACHE_V4WT diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200.h b/include/asm-arm/arch-at91rm9200/at91rm9200.h new file mode 100644 index 000000000000..58f40931a5c1 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91rm9200.h @@ -0,0 +1,261 @@ +/* + * include/asm-arm/arch-at91rm9200/at91rm9200.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Common definitions. + * Based on AT91RM9200 datasheet revision E. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef AT91RM9200_H +#define AT91RM9200_H + +/* + * Peripheral identifiers/interrupts. + */ +#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */ +#define AT91_ID_SYS 1 /* System Peripheral */ +#define AT91_ID_PIOA 2 /* Parallel IO Controller A */ +#define AT91_ID_PIOB 3 /* Parallel IO Controller B */ +#define AT91_ID_PIOC 4 /* Parallel IO Controller C */ +#define AT91_ID_PIOD 5 /* Parallel IO Controller D */ +#define AT91_ID_US0 6 /* USART 0 */ +#define AT91_ID_US1 7 /* USART 1 */ +#define AT91_ID_US2 8 /* USART 2 */ +#define AT91_ID_US3 9 /* USART 3 */ +#define AT91_ID_MCI 10 /* Multimedia Card Interface */ +#define AT91_ID_UDP 11 /* USB Device Port */ +#define AT91_ID_TWI 12 /* Two-Wire Interface */ +#define AT91_ID_SPI 13 /* Serial Peripheral Interface */ +#define AT91_ID_SSC0 14 /* Serial Synchronous Controller 0 */ +#define AT91_ID_SSC1 15 /* Serial Synchronous Controller 1 */ +#define AT91_ID_SSC2 16 /* Serial Synchronous Controller 2 */ +#define AT91_ID_TC0 17 /* Timer Counter 0 */ +#define AT91_ID_TC1 18 /* Timer Counter 1 */ +#define AT91_ID_TC2 19 /* Timer Counter 2 */ +#define AT91_ID_TC3 20 /* Timer Counter 3 */ +#define AT91_ID_TC4 21 /* Timer Counter 4 */ +#define AT91_ID_TC5 22 /* Timer Counter 5 */ +#define AT91_ID_UHP 23 /* USB Host port */ +#define AT91_ID_EMAC 24 /* Ethernet MAC */ +#define AT91_ID_IRQ0 25 /* Advanced Interrupt Controller (IRQ0) */ +#define AT91_ID_IRQ1 26 /* Advanced Interrupt Controller (IRQ1) */ +#define AT91_ID_IRQ2 27 /* Advanced Interrupt Controller (IRQ2) */ +#define AT91_ID_IRQ3 28 /* Advanced Interrupt Controller (IRQ3) */ +#define AT91_ID_IRQ4 29 /* Advanced Interrupt Controller (IRQ4) */ +#define AT91_ID_IRQ5 30 /* Advanced Interrupt Controller (IRQ5) */ +#define AT91_ID_IRQ6 31 /* Advanced Interrupt Controller (IRQ6) */ + + +/* + * Peripheral physical base addresses. + */ +#define AT91_BASE_TCB0 0xfffa0000 +#define AT91_BASE_TC0 0xfffa0000 +#define AT91_BASE_TC1 0xfffa0040 +#define AT91_BASE_TC2 0xfffa0080 +#define AT91_BASE_TCB1 0xfffa4000 +#define AT91_BASE_TC3 0xfffa4000 +#define AT91_BASE_TC4 0xfffa4040 +#define AT91_BASE_TC5 0xfffa4080 +#define AT91_BASE_UDP 0xfffb0000 +#define AT91_BASE_MCI 0xfffb4000 +#define AT91_BASE_TWI 0xfffb8000 +#define AT91_BASE_EMAC 0xfffbc000 +#define AT91_BASE_US0 0xfffc0000 +#define AT91_BASE_US1 0xfffc4000 +#define AT91_BASE_US2 0xfffc8000 +#define AT91_BASE_US3 0xfffcc000 +#define AT91_BASE_SSC0 0xfffd0000 +#define AT91_BASE_SSC1 0xfffd4000 +#define AT91_BASE_SSC2 0xfffd8000 +#define AT91_BASE_SPI 0xfffe0000 +#define AT91_BASE_SYS 0xfffff000 + + +/* + * PIO pin definitions (peripheral A/B multiplexing). + */ +#define AT91_PA0_MISO (1 << 0) /* A: SPI Master-In Slave-Out */ +#define AT91_PA0_PCK3 (1 << 0) /* B: PMC Programmable Clock Output 3 */ +#define AT91_PA1_MOSI (1 << 1) /* A: SPI Master-Out Slave-In */ +#define AT91_PA1_PCK0 (1 << 1) /* B: PMC Programmable Clock Output 0 */ +#define AT91_PA2_SPCK (1 << 2) /* A: SPI Serial Clock */ +#define AT91_PA2_IRQ4 (1 << 2) /* B: External Interrupt 4 */ +#define AT91_PA3_NPCS0 (1 << 3) /* A: SPI Peripheral Chip Select 0 */ +#define AT91_PA3_IRQ5 (1 << 3) /* B: External Interrupt 5 */ +#define AT91_PA4_NPCS1 (1 << 4) /* A: SPI Peripheral Chip Select 1 */ +#define AT91_PA4_PCK1 (1 << 4) /* B: PMC Programmable Clock Output 1 */ +#define AT91_PA5_NPCS2 (1 << 5) /* A: SPI Peripheral Chip Select 2 */ +#define AT91_PA5_TXD3 (1 << 5) /* B: USART Transmit Data 3 */ +#define AT91_PA6_NPCS3 (1 << 6) /* A: SPI Peripheral Chip Select 3 */ +#define AT91_PA6_RXD3 (1 << 6) /* B: USART Receive Data 3 */ +#define AT91_PA7_ETXCK_EREFCK (1 << 7) /* A: Ethernet Reference Clock / Transmit Clock */ +#define AT91_PA7_PCK2 (1 << 7) /* B: PMC Programmable Clock Output 2 */ +#define AT91_PA8_ETXEN (1 << 8) /* A: Ethernet Transmit Enable */ +#define AT91_PA8_MCCDB (1 << 8) /* B: MMC Multimedia Card B Command */ +#define AT91_PA9_ETX0 (1 << 9) /* A: Ethernet Transmit Data 0 */ +#define AT91_PA9_MCDB0 (1 << 9) /* B: MMC Multimedia Card B Data 0 */ +#define AT91_PA10_ETX1 (1 << 10) /* A: Ethernet Transmit Data 1 */ +#define AT91_PA10_MCDB1 (1 << 10) /* B: MMC Multimedia Card B Data 1 */ +#define AT91_PA11_ECRS_ECRSDV (1 << 11) /* A: Ethernet Carrier Sense / Data Valid */ +#define AT91_PA11_MCDB2 (1 << 11) /* B: MMC Multimedia Card B Data 2 */ +#define AT91_PA12_ERX0 (1 << 12) /* A: Ethernet Receive Data 0 */ +#define AT91_PA12_MCDB3 (1 << 12) /* B: MMC Multimedia Card B Data 3 */ +#define AT91_PA13_ERX1 (1 << 13) /* A: Ethernet Receive Data 1 */ +#define AT91_PA13_TCLK0 (1 << 13) /* B: TC External Clock Input 0 */ +#define AT91_PA14_ERXER (1 << 14) /* A: Ethernet Receive Error */ +#define AT91_PA14_TCLK1 (1 << 14) /* B: TC External Clock Input 1 */ +#define AT91_PA15_EMDC (1 << 15) /* A: Ethernet Management Data Clock */ +#define AT91_PA15_TCLK2 (1 << 15) /* B: TC External Clock Input 2 */ +#define AT91_PA16_EMDIO (1 << 16) /* A: Ethernet Management Data I/O */ +#define AT91_PA16_IRQ6 (1 << 16) /* B: External Interrupt 6 */ +#define AT91_PA17_TXD0 (1 << 17) /* A: USART Transmit Data 0 */ +#define AT91_PA17_TIOA0 (1 << 17) /* B: TC I/O Line A 0 */ +#define AT91_PA18_RXD0 (1 << 18) /* A: USART Receive Data 0 */ +#define AT91_PA18_TIOB0 (1 << 18) /* B: TC I/O Line B 0 */ +#define AT91_PA19_SCK0 (1 << 19) /* A: USART Serial Clock 0 */ +#define AT91_PA19_TIOA1 (1 << 19) /* B: TC I/O Line A 1 */ +#define AT91_PA20_CTS0 (1 << 20) /* A: USART Clear To Send 0 */ +#define AT91_PA20_TIOB1 (1 << 20) /* B: TC I/O Line B 1 */ +#define AT91_PA21_RTS0 (1 << 21) /* A: USART Ready To Send 0 */ +#define AT91_PA21_TIOA2 (1 << 21) /* B: TC I/O Line A 2 */ +#define AT91_PA22_RXD2 (1 << 22) /* A: USART Receive Data 2 */ +#define AT91_PA22_TIOB2 (1 << 22) /* B: TC I/O Line B 2 */ +#define AT91_PA23_TXD2 (1 << 23) /* A: USART Transmit Data 2 */ +#define AT91_PA23_IRQ3 (1 << 23) /* B: External Interrupt 3 */ +#define AT91_PA24_SCK2 (1 << 24) /* A: USART Serial Clock 2 */ +#define AT91_PA24_PCK1 (1 << 24) /* B: PMC Programmable Clock Output 1 */ +#define AT91_PA25_TWD (1 << 25) /* A: TWI Two-wire Serial Data */ +#define AT91_PA25_IRQ2 (1 << 25) /* B: External Interrupt 2 */ +#define AT91_PA26_TWCK (1 << 26) /* A: TWI Two-wire Serial Clock */ +#define AT91_PA26_IRQ1 (1 << 26) /* B: External Interrupt 1 */ +#define AT91_PA27_MCCK (1 << 27) /* A: MMC Multimedia Card Clock */ +#define AT91_PA27_TCLK3 (1 << 27) /* B: TC External Clock Input 3 */ +#define AT91_PA28_MCCDA (1 << 28) /* A: MMC Multimedia Card A Command */ +#define AT91_PA28_TCLK4 (1 << 28) /* B: TC External Clock Input 4 */ +#define AT91_PA29_MCDA0 (1 << 29) /* A: MMC Multimedia Card A Data 0 */ +#define AT91_PA29_TCLK5 (1 << 29) /* B: TC External Clock Input 5 */ +#define AT91_PA30_DRXD (1 << 30) /* A: DBGU Receive Data */ +#define AT91_PA30_CTS2 (1 << 30) /* B: USART Clear To Send 2 */ +#define AT91_PA31_DTXD (1 << 31) /* A: DBGU Transmit Data */ +#define AT91_PA31_RTS2 (1 << 31) /* B: USART Ready To Send 2 */ + +#define AT91_PB0_TF0 (1 << 0) /* A: SSC Transmit Frame Sync 0 */ +#define AT91_PB0_RTS3 (1 << 0) /* B: USART Ready To Send 3 */ +#define AT91_PB1_TK0 (1 << 1) /* A: SSC Transmit Clock 0 */ +#define AT91_PB1_CTS3 (1 << 1) /* B: USART Clear To Send 3 */ +#define AT91_PB2_TD0 (1 << 2) /* A: SSC Transmit Data 0 */ +#define AT91_PB2_SCK3 (1 << 2) /* B: USART Serial Clock 3 */ +#define AT91_PB3_RD0 (1 << 3) /* A: SSC Receive Data 0 */ +#define AT91_PB3_MCDA1 (1 << 3) /* B: MMC Multimedia Card A Data 1 */ +#define AT91_PB4_RK0 (1 << 4) /* A: SSC Receive Clock 0 */ +#define AT91_PB4_MCDA2 (1 << 4) /* B: MMC Multimedia Card A Data 2 */ +#define AT91_PB5_RF0 (1 << 5) /* A: SSC Receive Frame Sync 0 */ +#define AT91_PB5_MCDA3 (1 << 5) /* B: MMC Multimedia Card A Data 3 */ +#define AT91_PB6_TF1 (1 << 6) /* A: SSC Transmit Frame Sync 1 */ +#define AT91_PB6_TIOA3 (1 << 6) /* B: TC I/O Line A 3 */ +#define AT91_PB7_TK1 (1 << 7) /* A: SSC Transmit Clock 1 */ +#define AT91_PB7_TIOB3 (1 << 7) /* B: TC I/O Line B 3 */ +#define AT91_PB8_TD1 (1 << 8) /* A: SSC Transmit Data 1 */ +#define AT91_PB8_TIOA4 (1 << 8) /* B: TC I/O Line A 4 */ +#define AT91_PB9_RD1 (1 << 9) /* A: SSC Receive Data 1 */ +#define AT91_PB9_TIOB4 (1 << 9) /* B: TC I/O Line B 4 */ +#define AT91_PB10_RK1 (1 << 10) /* A: SSC Receive Clock 1 */ +#define AT91_PB10_TIOA5 (1 << 10) /* B: TC I/O Line A 5 */ +#define AT91_PB11_RF1 (1 << 11) /* A: SSC Receive Frame Sync 1 */ +#define AT91_PB11_TIOB5 (1 << 11) /* B: TC I/O Line B 5 */ +#define AT91_PB12_TF2 (1 << 12) /* A: SSC Transmit Frame Sync 2 */ +#define AT91_PB12_ETX2 (1 << 12) /* B: Ethernet Transmit Data 2 */ +#define AT91_PB13_TK2 (1 << 13) /* A: SSC Transmit Clock 3 */ +#define AT91_PB13_ETX3 (1 << 13) /* B: Ethernet Transmit Data 3 */ +#define AT91_PB14_TD2 (1 << 14) /* A: SSC Transmit Data 2 */ +#define AT91_PB14_ETXER (1 << 14) /* B: Ethernet Transmit Coding Error */ +#define AT91_PB15_RD2 (1 << 15) /* A: SSC Receive Data 2 */ +#define AT91_PB15_ERX2 (1 << 15) /* B: Ethernet Receive Data 2 */ +#define AT91_PB16_RK2 (1 << 16) /* A: SSC Receive Clock 2 */ +#define AT91_PB16_ERX3 (1 << 16) /* B: Ethernet Receive Data 3 */ +#define AT91_PB17_RF2 (1 << 17) /* A: SSC Receive Frame Sync 2 */ +#define AT91_PB17_ERXDV (1 << 17) /* B: Ethernet Receive Data Valid */ +#define AT91_PB18_RI1 (1 << 18) /* A: USART Ring Indicator 1 */ +#define AT91_PB18_ECOL (1 << 18) /* B: Ethernet Collision Detected */ +#define AT91_PB19_DTR1 (1 << 19) /* A: USART Data Terminal Ready 1 */ +#define AT91_PB19_ERXCK (1 << 19) /* B: Ethernet Receive Clock */ +#define AT91_PB20_TXD1 (1 << 20) /* A: USART Transmit Data 1 */ +#define AT91_PB21_RXD1 (1 << 21) /* A: USART Receive Data 1 */ +#define AT91_PB22_SCK1 (1 << 22) /* A: USART Serial Clock 1 */ +#define AT91_PB23_DCD1 (1 << 23) /* A: USART Data Carrier Detect 1 */ +#define AT91_PB24_CTS1 (1 << 24) /* A: USART Clear To Send 1 */ +#define AT91_PB25_DSR1 (1 << 25) /* A: USART Data Set Ready 1 */ +#define AT91_PB25_EF100 (1 << 25) /* B: Ethernet Force 100 Mbit */ +#define AT91_PB26_RTS1 (1 << 26) /* A: USART Ready To Send 1 */ +#define AT91_PB27_PCK0 (1 << 27) /* B: PMC Programmable Clock Output 0 */ +#define AT91_PB28_FIQ (1 << 28) /* A: Fast Interrupt */ +#define AT91_PB29_IRQ0 (1 << 29) /* A: External Interrupt 0 */ + +#define AT91_PC0_BFCK (1 << 0) /* A: Burst Flash Clock */ +#define AT91_PC1_BFRDY_SMOE (1 << 1) /* A: Burst Flash Ready / SmartMedia Output Enable */ +#define AT91_PC2_BFAVD (1 << 2) /* A: Burst Flash Address Valid */ +#define AT91_PC3_BFBAA_SMWE (1 << 3) /* A: Burst Flash Address Advance / SmartMedia Write Enable */ +#define AT91_PC4_BFOE (1 << 4) /* A: Burst Flash Output Enable */ +#define AT91_PC5_BFWE (1 << 5) /* A: Burst Flash Write Enable */ +#define AT91_PC6_NWAIT (1 << 6) /* A: SMC Wait Signal */ +#define AT91_PC7_A23 (1 << 7) /* A: Address Bus 23 */ +#define AT91_PC8_A24 (1 << 8) /* A: Address Bus 24 */ +#define AT91_PC9_A25_CFRNW (1 << 9) /* A: Address Bus 25 / Compact Flash Read Not Write */ +#define AT91_PC10_NCS4_CFCS (1 << 10) /* A: SMC Chip Select 4 / Compact Flash Chip Select */ +#define AT91_PC11_NCS5_CFCE1 (1 << 11) /* A: SMC Chip Select 5 / Compact Flash Chip Enable 1 */ +#define AT91_PC12_NCS6_CFCE2 (1 << 12) /* A: SMC Chip Select 6 / Compact Flash Chip Enable 2 */ +#define AT91_PC13_NCS7 (1 << 13) /* A: Chip Select 7 */ + +#define AT91_PD0_ETX0 (1 << 0) /* A: Ethernet Transmit Data 0 */ +#define AT91_PD1_ETX1 (1 << 1) /* A: Ethernet Transmit Data 1 */ +#define AT91_PD2_ETX2 (1 << 2) /* A: Ethernet Transmit Data 2 */ +#define AT91_PD3_ETX3 (1 << 3) /* A: Ethernet Transmit Data 3 */ +#define AT91_PD4_ETXEN (1 << 4) /* A: Ethernet Transmit Enable */ +#define AT91_PD5_ETXER (1 << 5) /* A: Ethernet Transmit Coding Error */ +#define AT91_PD6_DTXD (1 << 6) /* A: DBGU Transmit Data */ +#define AT91_PD7_PCK0 (1 << 7) /* A: PMC Programmable Clock Output 0 */ +#define AT91_PD7_TSYNC (1 << 7) /* B: ETM Trace Synchronization Signal */ +#define AT91_PD8_PCK1 (1 << 8) /* A: PMC Programmable Clock Output 1 */ +#define AT91_PD8_TCLK (1 << 8) /* B: ETM Trace Clock */ +#define AT91_PD9_PCK2 (1 << 9) /* A: PMC Programmable Clock Output 2 */ +#define AT91_PD9_TPS0 (1 << 9) /* B: ETM Trace ARM Pipeline Status 0 */ +#define AT91_PD10_PCK3 (1 << 10) /* A: PMC Programmable Clock Output 3 */ +#define AT91_PD10_TPS1 (1 << 10) /* B: ETM Trace ARM Pipeline Status 1 */ +#define AT91_PD11_TPS2 (1 << 11) /* B: ETM Trace ARM Pipeline Status 2 */ +#define AT91_PD12_TPK0 (1 << 12) /* B: ETM Trace Packet Port 0 */ +#define AT91_PD13_TPK1 (1 << 13) /* B: ETM Trace Packet Port 1 */ +#define AT91_PD14_TPK2 (1 << 14) /* B: ETM Trace Packet Port 2 */ +#define AT91_PD15_TD0 (1 << 15) /* A: SSC Transmit Data 0 */ +#define AT91_PD15_TPK3 (1 << 15) /* B: ETM Trace Packet Port 3 */ +#define AT91_PD16_TD1 (1 << 16) /* A: SSC Transmit Data 1 */ +#define AT91_PD16_TPK4 (1 << 16) /* B: ETM Trace Packet Port 4 */ +#define AT91_PD17_TD2 (1 << 17) /* A: SSC Transmit Data 2 */ +#define AT91_PD17_TPK5 (1 << 17) /* B: ETM Trace Packet Port 5 */ +#define AT91_PD18_NPCS1 (1 << 18) /* A: SPI Peripheral Chip Select 1 */ +#define AT91_PD18_TPK6 (1 << 18) /* B: ETM Trace Packet Port 6 */ +#define AT91_PD19_NPCS2 (1 << 19) /* A: SPI Peripheral Chip Select 2 */ +#define AT91_PD19_TPK7 (1 << 19) /* B: ETM Trace Packet Port 7 */ +#define AT91_PD20_NPCS3 (1 << 20) /* A: SPI Peripheral Chip Select 3 */ +#define AT91_PD20_TPK8 (1 << 20) /* B: ETM Trace Packet Port 8 */ +#define AT91_PD21_RTS0 (1 << 21) /* A: USART Ready To Send 0 */ +#define AT91_PD21_TPK9 (1 << 21) /* B: ETM Trace Packet Port 9 */ +#define AT91_PD22_RTS1 (1 << 22) /* A: USART Ready To Send 1 */ +#define AT91_PD22_TPK10 (1 << 22) /* B: ETM Trace Packet Port 10 */ +#define AT91_PD23_RTS2 (1 << 23) /* A: USART Ready To Send 2 */ +#define AT91_PD23_TPK11 (1 << 23) /* B: ETM Trace Packet Port 11 */ +#define AT91_PD24_RTS3 (1 << 24) /* A: USART Ready To Send 3 */ +#define AT91_PD24_TPK12 (1 << 24) /* B: ETM Trace Packet Port 12 */ +#define AT91_PD25_DTR1 (1 << 25) /* A: USART Data Terminal Ready 1 */ +#define AT91_PD25_TPK13 (1 << 25) /* B: ETM Trace Packet Port 13 */ +#define AT91_PD26_TPK14 (1 << 26) /* B: ETM Trace Packet Port 14 */ +#define AT91_PD27_TPK15 (1 << 27) /* B: ETM Trace Packet Port 15 */ + +#endif diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h new file mode 100644 index 000000000000..9bfffdbf1e0b --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h @@ -0,0 +1,328 @@ +/* + * include/asm-arm/arch-at91rm9200/at91rm9200_sys.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * System peripherals registers. + * Based on AT91RM9200 datasheet revision E. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef AT91RM9200_SYS_H +#define AT91RM9200_SYS_H + +/* + * Advanced Interrupt Controller. + */ +#define AT91_AIC 0x000 + +#define AT91_AIC_SMR(n) (AT91_AIC + ((n) * 4)) /* Source Mode Registers 0-31 */ +#define AT91_AIC_PRIOR (7 << 0) /* Priority Level */ +#define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */ +#define AT91_AIC_SRCTYPE_LOW (0 << 5) +#define AT91_AIC_SRCTYPE_FALLING (1 << 5) +#define AT91_AIC_SRCTYPE_HIGH (2 << 5) +#define AT91_AIC_SRCTYPE_RISING (3 << 5) + +#define AT91_AIC_SVR(n) (AT91_AIC + 0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */ +#define AT91_AIC_IVR (AT91_AIC + 0x100) /* Interrupt Vector Register */ +#define AT91_AIC_FVR (AT91_AIC + 0x104) /* Fast Interrupt Vector Register */ +#define AT91_AIC_ISR (AT91_AIC + 0x108) /* Interrupt Status Register */ +#define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */ + +#define AT91_AIC_IPR (AT91_AIC + 0x10c) /* Interrupt Pending Register */ +#define AT91_AIC_IMR (AT91_AIC + 0x110) /* Interrupt Mask Register */ +#define AT91_AIC_CISR (AT91_AIC + 0x114) /* Core Interrupt Status Register */ +#define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */ +#define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */ + +#define AT91_AIC_IECR (AT91_AIC + 0x120) /* Interrupt Enable Command Register */ +#define AT91_AIC_IDCR (AT91_AIC + 0x124) /* Interrupt Disable Command Register */ +#define AT91_AIC_ICCR (AT91_AIC + 0x128) /* Interrupt Clear Command Register */ +#define AT91_AIC_ISCR (AT91_AIC + 0x12c) /* Interrupt Set Command Register */ +#define AT91_AIC_EOICR (AT91_AIC + 0x130) /* End of Interrupt Command Register */ +#define AT91_AIC_SPU (AT91_AIC + 0x134) /* Spurious Interrupt Vector Register */ +#define AT91_AIC_DCR (AT91_AIC + 0x138) /* Debug Control Register */ +#define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */ +#define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */ + + +/* + * Debug Unit. + */ +#define AT91_DBGU 0x200 + +#define AT91_DBGU_CR (AT91_DBGU + 0x00) /* Control Register */ +#define AT91_DBGU_MR (AT91_DBGU + 0x04) /* Mode Register */ +#define AT91_DBGU_IER (AT91_DBGU + 0x08) /* Interrupt Enable Register */ +#define AT91_DBGU_TXRDY (1 << 1) /* Transmitter Ready */ +#define AT91_DBGU_TXEMPTY (1 << 9) /* Transmitter Empty */ +#define AT91_DBGU_IDR (AT91_DBGU + 0x0c) /* Interrupt Disable Register */ +#define AT91_DBGU_IMR (AT91_DBGU + 0x10) /* Interrupt Mask Register */ +#define AT91_DBGU_SR (AT91_DBGU + 0x14) /* Status Register */ +#define AT91_DBGU_RHR (AT91_DBGU + 0x18) /* Receiver Holding Register */ +#define AT91_DBGU_THR (AT91_DBGU + 0x1c) /* Transmitter Holding Register */ +#define AT91_DBGU_BRGR (AT91_DBGU + 0x20) /* Baud Rate Generator Register */ +#define AT91_DBGU_CIDR (AT91_DBGU + 0x40) /* Chip ID Register */ +#define AT91_DBGU_EXID (AT91_DBGU + 0x44) /* Chip ID Extension Register */ + + +/* + * PIO Controllers. + */ +#define AT91_PIOA 0x400 +#define AT91_PIOB 0x600 +#define AT91_PIOC 0x800 +#define AT91_PIOD 0xa00 + +#define PIO_PER 0x00 /* Enable Register */ +#define PIO_PDR 0x04 /* Disable Register */ +#define PIO_PSR 0x08 /* Status Register */ +#define PIO_OER 0x10 /* Output Enable Register */ +#define PIO_ODR 0x14 /* Output Disable Register */ +#define PIO_OSR 0x18 /* Output Status Register */ +#define PIO_IFER 0x20 /* Glitch Input Filter Enable */ +#define PIO_IFDR 0x24 /* Glitch Input Filter Disable */ +#define PIO_IFSR 0x28 /* Glitch Input Filter Status */ +#define PIO_SODR 0x30 /* Set Output Data Register */ +#define PIO_CODR 0x34 /* Clear Output Data Register */ +#define PIO_ODSR 0x38 /* Output Data Status Register */ +#define PIO_PDSR 0x3c /* Pin Data Status Register */ +#define PIO_IER 0x40 /* Interrupt Enable Register */ +#define PIO_IDR 0x44 /* Interrupt Disable Register */ +#define PIO_IMR 0x48 /* Interrupt Mask Register */ +#define PIO_ISR 0x4c /* Interrupt Status Register */ +#define PIO_MDER 0x50 /* Multi-driver Enable Register */ +#define PIO_MDDR 0x54 /* Multi-driver Disable Register */ +#define PIO_MDSR 0x58 /* Multi-driver Status Register */ +#define PIO_PUDR 0x60 /* Pull-up Disable Register */ +#define PIO_PUER 0x64 /* Pull-up Enable Register */ +#define PIO_PUSR 0x68 /* Pull-up Status Register */ +#define PIO_ASR 0x70 /* Peripheral A Select Register */ +#define PIO_BSR 0x74 /* Peripheral B Select Register */ +#define PIO_ABSR 0x78 /* AB Status Register */ +#define PIO_OWER 0xa0 /* Output Write Enable Register */ +#define PIO_OWDR 0xa4 /* Output Write Disable Register */ +#define PIO_OWSR 0xa8 /* Output Write Status Register */ + +#define AT91_PIO_P(n) (1 << (n)) + + +/* + * Power Management Controller. + */ +#define AT91_PMC 0xc00 + +#define AT91_PMC_SCER (AT91_PMC + 0x00) /* System Clock Enable Register */ +#define AT91_PMC_SCDR (AT91_PMC + 0x04) /* System Clock Disable Register */ + +#define AT91_PMC_SCSR (AT91_PMC + 0x08) /* System Clock Status Register */ +#define AT91_PMC_PCK (1 << 0) /* Processor Clock */ +#define AT91_PMC_UDP (1 << 1) /* USB Devcice Port Clock */ +#define AT91_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend */ +#define AT91_PMC_UHP (1 << 4) /* USB Host Port Clock */ +#define AT91_PMC_PCK0 (1 << 8) /* Programmable Clock 0 */ +#define AT91_PMC_PCK1 (1 << 9) /* Programmable Clock 1 */ +#define AT91_PMC_PCK2 (1 << 10) /* Programmable Clock 2 */ +#define AT91_PMC_PCK3 (1 << 11) /* Programmable Clock 3 */ + +#define AT91_PMC_PCER (AT91_PMC + 0x10) /* Peripheral Clock Enable Register */ +#define AT91_PMC_PCDR (AT91_PMC + 0x14) /* Peripheral Clock Disable Register */ +#define AT91_PMC_PCSR (AT91_PMC + 0x18) /* Peripheral Clock Status Register */ + +#define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register */ +#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ +#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ + +#define AT91_CKGR_MCFR (AT91_PMC + 0x24) /* Main Clock Frequency Register */ +#define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */ +#define AT91_PMC_MAINRDY (1 << 16) /* Main Clock Ready */ + +#define AT91_CKGR_PLLAR (AT91_PMC + 0x28) /* PLL A Register */ +#define AT91_CKGR_PLLBR (AT91_PMC + 0x2c) /* PLL B Register */ +#define AT91_PMC_DIV (0xff << 0) /* Divider */ +#define AT91_PMC_PLLCOUNT (0x3f << 8) /* PLL Counter */ +#define AT91_PMC_OUT (3 << 14) /* PLL Clock Frequency Range */ +#define AT91_PMC_MUL (0x7ff << 16) /* PLL Multiplier */ +#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ + +#define AT91_PMC_MCKR (AT91_PMC + 0x30) /* Master Clock Register */ +#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ +#define AT91_PMC_CSS_SLOW (0 << 0) +#define AT91_PMC_CSS_MAIN (1 << 0) +#define AT91_PMC_CSS_PLLA (2 << 0) +#define AT91_PMC_CSS_PLLB (3 << 0) +#define AT91_PMC_PRES (7 << 2) /* Master Clock Prescaler */ +#define AT91_PMC_PRES_1 (0 << 2) +#define AT91_PMC_PRES_2 (1 << 2) +#define AT91_PMC_PRES_4 (2 << 2) +#define AT91_PMC_PRES_8 (3 << 2) +#define AT91_PMC_PRES_16 (4 << 2) +#define AT91_PMC_PRES_32 (5 << 2) +#define AT91_PMC_PRES_64 (6 << 2) +#define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */ +#define AT91_PMC_MDIV_1 (0 << 8) +#define AT91_PMC_MDIV_2 (1 << 8) +#define AT91_PMC_MDIV_3 (2 << 8) +#define AT91_PMC_MDIV_4 (3 << 8) + +#define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-3 Registers */ +#define AT91_PMC_IER (AT91_PMC + 0x60) /* Interrupt Enable Register */ +#define AT91_PMC_IDR (AT91_PMC + 0x64) /* Interrupt Disable Register */ +#define AT91_PMC_SR (AT91_PMC + 0x68) /* Status Register */ +#define AT91_PMC_MOSCS (1 << 0) /* MOSCS Flag */ +#define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ +#define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ +#define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ +#define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ +#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ +#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ +#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */ +#define AT91_PMC_IMR (AT91_PMC + 0x6c) /* Interrupt Mask Register */ + + +/* + * System Timer. + */ +#define AT91_ST 0xd00 + +#define AT91_ST_CR (AT91_ST + 0x00) /* Control Register */ +#define AT91_ST_WDRST (1 << 0) /* Watchdog Timer Restart */ +#define AT91_ST_PIMR (AT91_ST + 0x04) /* Period Interval Mode Register */ +#define AT91_ST_PIV (0xffff << 0) /* Period Interval Value */ +#define AT91_ST_WDMR (AT91_ST + 0x08) /* Watchdog Mode Register */ +#define AT91_ST_WDV (0xffff << 0) /* Watchdog Counter Value */ +#define AT91_ST_RSTEN (1 << 16) /* Reset Enable */ +#define AT91_ST_EXTEN (1 << 17) /* External Signal Assertion Enable */ +#define AT91_ST_RTMR (AT91_ST + 0x0c) /* Real-time Mode Register */ +#define AT91_ST_RTPRES (0xffff << 0) /* Real-time Prescalar Value */ +#define AT91_ST_SR (AT91_ST + 0x10) /* Status Register */ +#define AT91_ST_PITS (1 << 0) /* Period Interval Timer Status */ +#define AT91_ST_WDOVF (1 << 1) /* Watchdog Overflow */ +#define AT91_ST_RTTINC (1 << 2) /* Real-time Timer Increment */ +#define AT91_ST_ALMS (1 << 3) /* Alarm Status */ +#define AT91_ST_IER (AT91_ST + 0x14) /* Interrupt Enable Register */ +#define AT91_ST_IDR (AT91_ST + 0x18) /* Interrupt Disable Register */ +#define AT91_ST_IMR (AT91_ST + 0x1c) /* Interrupt Mask Register */ +#define AT91_ST_RTAR (AT91_ST + 0x20) /* Real-time Alarm Register */ +#define AT91_ST_ALMV (0xfffff << 0) /* Alarm Value */ +#define AT91_ST_CRTR (AT91_ST + 0x24) /* Current Real-time Register */ +#define AT91_ST_CRTV (0xfffff << 0) /* Current Real-Time Value */ + + +/* + * Real-time Clock. + */ +#define AT91_RTC 0xe00 + +#define AT91_RTC_CR (AT91_RTC + 0x00) /* Control Register */ +#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */ +#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */ +#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */ +#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8) +#define AT91_RTC_TIMEVSEL_HOUR (1 << 8) +#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8) +#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8) +#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */ +#define AT91_RTC_CALEVSEL_WEEK (0 << 16) +#define AT91_RTC_CALEVSEL_MONTH (1 << 16) +#define AT91_RTC_CALEVSEL_YEAR (2 << 16) + +#define AT91_RTC_MR (AT91_RTC + 0x04) /* Mode Register */ +#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */ + +#define AT91_RTC_TIMR (AT91_RTC + 0x08) /* Time Register */ +#define AT91_RTC_SEC (0x7f << 0) /* Current Second */ +#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */ +#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */ +#define At91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */ + +#define AT91_RTC_CALR (AT91_RTC + 0x0c) /* Calendar Register */ +#define AT91_RTC_CENT (0x7f << 0) /* Current Century */ +#define AT91_RTC_YEAR (0xff << 8) /* Current Year */ +#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */ +#define AT91_RTC_DAY (7 << 21) /* Current Day */ +#define AT91_RTC_DATE (0x3f << 24) /* Current Date */ + +#define AT91_RTC_TIMALR (AT91_RTC + 0x10) /* Time Alarm Register */ +#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */ +#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */ +#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */ + +#define AT91_RTC_CALALR (AT91_RTC + 0x14) /* Calendar Alarm Register */ +#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */ +#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */ + +#define AT91_RTC_SR (AT91_RTC + 0x18) /* Status Register */ +#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */ +#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */ +#define AT91_RTC_SECEV (1 << 2) /* Second Event */ +#define AT91_RTC_TIMEV (1 << 3) /* Time Event */ +#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */ + +#define AT91_RTC_SCCR (AT91_RTC + 0x1c) /* Status Clear Command Register */ +#define AT91_RTC_IER (AT91_RTC + 0x20) /* Interrupt Enable Register */ +#define AT91_RTC_IDR (AT91_RTC + 0x24) /* Interrupt Disable Register */ +#define AT91_RTC_IMR (AT91_RTC + 0x28) /* Interrupt Mask Register */ + +#define AT91_RTC_VER (AT91_RTC + 0x2c) /* Valid Entry Register */ +#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */ +#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */ +#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */ +#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */ + + +/* + * Memory Controller. + */ +#define AT91_MC 0xf00 + +#define AT91_MC_RCR (AT91_MC + 0x00) /* MC Remap Control Register */ +#define AT91_MC_RCB (1 << 0) /* Remap Command Bit */ + +#define AT91_MC_ASR (AT91_MC + 0x04) /* MC Abort Status Register */ +#define AT91_MC_AASR (AT91_MC + 0x08) /* MC Abort Address Status Register */ +#define AT91_MC_MPR (AT91_MC + 0x0c) /* MC Master Priority Register */ + +/* External Bus Interface (EBI) registers */ +#define AT91_EBI_CSA (AT91_MC + 0x60) /* Chip Select Assignment Register */ +#define AT91_EBI_CS0A (1 << 0) /* Chip Select 0 Assignment */ +#define AT91_EBI_CS0A_SMC (0 << 0) +#define AT91_EBI_CS0A_BFC (1 << 0) +#define AT91_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */ +#define AT91_EBI_CS1A_SMC (0 << 1) +#define AT91_EBI_CS1A_SDRAMC (1 << 1) +#define AT91_EBI_CS3A (1 << 3) /* Chip Select 2 Assignment */ +#define AT91_EBI_CS3A_SMC (0 << 3) +#define AT91_EBI_CS3A_SMC_SMARTMEDIA (1 << 3) +#define AT91_EBI_CS4A (1 << 4) /* Chip Select 3 Assignment */ +#define AT91_EBI_CS4A_SMC (0 << 4) +#define AT91_EBI_CS4A_SMC_COMPACTFLASH (1 << 4) +#define AT91_EBI_CFGR (AT91_MC + 0x64) /* Configuration Register */ +#define AT91_EBI_DBPUC (1 << 0) /* Data Bus Pull-Up Configuration */ + +/* Static Memory Controller (SMC) registers */ +#define AT91_SMC_CSR(n) (AT91_MC + 0x70 + ((n) * 4))/* SMC Chip Select Register */ +#define AT91_SMC_NWS (0x7f << 0) /* Number of Wait States */ +#define AT91_SMC_WSEN (1 << 7) /* Wait State Enable */ +#define AT91_SMC_TDF (0xf << 8) /* Data Float Time */ +#define AT91_SMC_BAT (1 << 12) /* Byte Access Type */ +#define AT91_SMC_DBW (3 << 13) /* Data Bus Width */ +#define AT91_SMC_DBW_16 (1 << 13) +#define AT91_SMC_DBW_8 (2 << 13) +#define AT91_SMC_DPR (1 << 15) /* Data Read Protocol */ +#define AT91_SMC_ACSS (3 << 16) /* Address to Chip Select Setup */ +#define AT91_SMC_ACSS_STD (0 << 16) +#define AT91_SMC_ACSS_1 (1 << 16) +#define AT91_SMC_ACSS_2 (2 << 16) +#define AT91_SMC_ACSS_3 (3 << 16) +#define AT91_SMC_RWSETUP (7 << 24) /* Read & Write Signal Time Setup */ +#define AT91_SMC_RWHOLD (7 << 28) /* Read & Write Signal Hold Time */ + + +#endif diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h new file mode 100644 index 000000000000..2e7d1139a799 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/board.h @@ -0,0 +1,80 @@ +/* + * include/asm-arm/arch-at91rm9200/board.h + * + * Copyright (C) 2005 HP Labs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * These are data structures found in platform_device.dev.platform_data, + * and describing board-specfic data needed by drivers. For example, + * which pin is used for a given GPIO role. + * + * In 2.6, drivers should strongly avoid board-specific knowledge so + * that supporting new boards normally won't require driver patches. + * Most board-specific knowledge should be in arch/.../board-*.c files. + */ + +#ifndef __ASM_ARCH_BOARD_H +#define __ASM_ARCH_BOARD_H + + /* Clocks */ +extern unsigned long at91_master_clock; + + /* Serial Port */ +extern int at91_serial_map[AT91_NR_UART]; +extern int at91_console_port; + + /* USB Device */ +struct at91_udc_data { + u8 vbus_pin; /* high == host powering us */ + u8 pullup_pin; /* high == D+ pulled up */ +}; +extern void __init at91_add_device_udc(struct at91_udc_data *data); + + /* Compact Flash */ +struct at91_cf_data { + u8 irq_pin; /* I/O IRQ */ + u8 det_pin; /* Card detect */ + u8 vcc_pin; /* power switching */ + u8 rst_pin; /* card reset */ +}; +extern void __init at91_add_device_cf(struct at91_cf_data *data); + + /* MMC / SD */ +struct at91_mmc_data { + u8 det_pin; /* card detect IRQ */ + unsigned is_b:1; /* uses B side (vs A) */ + unsigned wire4:1; /* (SD) supports DAT0..DAT3 */ + u8 wp_pin; /* (SD) writeprotect detect */ + u8 vcc_pin; /* power switching (high == on) */ +}; +extern void __init at91_add_device_mmc(struct at91_mmc_data *data); + + /* Ethernet */ +struct at91_eth_data { + u8 phy_irq_pin; /* PHY IRQ */ + u8 is_rmii; /* using RMII interface? */ +}; +extern void __init at91_add_device_eth(struct at91_eth_data *data); + + /* USB Host */ +struct at91_usbh_data { + u8 ports; /* number of ports on root hub */ +}; +extern void __init at91_add_device_usbh(struct at91_usbh_data *data); + +#endif diff --git a/include/asm-arm/arch-at91rm9200/debug-macro.S b/include/asm-arm/arch-at91rm9200/debug-macro.S new file mode 100644 index 000000000000..f496b54c4c3e --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/debug-macro.S @@ -0,0 +1,38 @@ +/* + * include/asm-arm/arch-at91rm9200/debug-macro.S + * + * Copyright (C) 2003-2005 SAN People + * + * Debugging macro include header + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#include + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldreq \rx, =AT91_BASE_SYS @ System peripherals (phys address) + ldrne \rx, =AT91_VA_BASE_SYS @ System peripherals (virt address) + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #AT91_DBGU_THR] @ Write to Transmitter Holding Register + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #AT91_DBGU_SR] @ Read Status Register + tst \rd, #AT91_DBGU_TXRDY @ DBGU_TXRDY = 1 when ready to transmit + beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #AT91_DBGU_SR] @ Read Status Register + tst \rd, #AT91_DBGU_TXEMPTY @ DBGU_TXEMPTY = 1 when transmission complete + beq 1001b + .endm + diff --git a/include/asm-arm/arch-at91rm9200/dma.h b/include/asm-arm/arch-at91rm9200/dma.h new file mode 100644 index 000000000000..6738bdd74b22 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/dma.h @@ -0,0 +1,27 @@ +/* + * include/asm-arm/arch-at91rm9200/dma.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ diff --git a/include/asm-arm/arch-at91rm9200/entry-macro.S b/include/asm-arm/arch-at91rm9200/entry-macro.S new file mode 100644 index 000000000000..61a326e94909 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/entry-macro.S @@ -0,0 +1,25 @@ +/* + * include/asm-arm/arch-at91rm9200/entry-macro.S + * + * Copyright (C) 2003-2005 SAN People + * + * Low-level IRQ helper macros for AT91RM9200 platforms + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \base, =(AT91_VA_BASE_SYS) @ base virtual address of SYS peripherals + ldr \irqnr, [\base, #AT91_AIC_IVR] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt) + ldr \irqstat, [\base, #AT91_AIC_ISR] @ read interrupt source number + teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt + streq \tmp, [\base, #AT91_AIC_EOICR] @ not going to be handled further, then ACK it now. + .endm + diff --git a/include/asm-arm/arch-at91rm9200/gpio.h b/include/asm-arm/arch-at91rm9200/gpio.h new file mode 100644 index 000000000000..0f0a61e2f129 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/gpio.h @@ -0,0 +1,193 @@ +/* + * include/asm-arm/arch-at91rm9200/gpio.h + * + * Copyright (C) 2005 HP Labs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_AT91RM9200_GPIO_H +#define __ASM_ARCH_AT91RM9200_GPIO_H + +#define PIN_BASE NR_AIC_IRQS + +#define PQFP_GPIO_BANKS 3 /* PQFP package has 3 banks */ +#define BGA_GPIO_BANKS 4 /* BGA package has 4 banks */ + +/* these pin numbers double as IRQ numbers, like AT91_ID_* values */ + +#define AT91_PIN_PA0 (PIN_BASE + 0x00 + 0) +#define AT91_PIN_PA1 (PIN_BASE + 0x00 + 1) +#define AT91_PIN_PA2 (PIN_BASE + 0x00 + 2) +#define AT91_PIN_PA3 (PIN_BASE + 0x00 + 3) +#define AT91_PIN_PA4 (PIN_BASE + 0x00 + 4) + +#define AT91_PIN_PA5 (PIN_BASE + 0x00 + 5) +#define AT91_PIN_PA6 (PIN_BASE + 0x00 + 6) +#define AT91_PIN_PA7 (PIN_BASE + 0x00 + 7) +#define AT91_PIN_PA8 (PIN_BASE + 0x00 + 8) +#define AT91_PIN_PA9 (PIN_BASE + 0x00 + 9) + +#define AT91_PIN_PA10 (PIN_BASE + 0x00 + 10) +#define AT91_PIN_PA11 (PIN_BASE + 0x00 + 11) +#define AT91_PIN_PA12 (PIN_BASE + 0x00 + 12) +#define AT91_PIN_PA13 (PIN_BASE + 0x00 + 13) +#define AT91_PIN_PA14 (PIN_BASE + 0x00 + 14) + +#define AT91_PIN_PA15 (PIN_BASE + 0x00 + 15) +#define AT91_PIN_PA16 (PIN_BASE + 0x00 + 16) +#define AT91_PIN_PA17 (PIN_BASE + 0x00 + 17) +#define AT91_PIN_PA18 (PIN_BASE + 0x00 + 18) +#define AT91_PIN_PA19 (PIN_BASE + 0x00 + 19) + +#define AT91_PIN_PA20 (PIN_BASE + 0x00 + 20) +#define AT91_PIN_PA21 (PIN_BASE + 0x00 + 21) +#define AT91_PIN_PA22 (PIN_BASE + 0x00 + 22) +#define AT91_PIN_PA23 (PIN_BASE + 0x00 + 23) +#define AT91_PIN_PA24 (PIN_BASE + 0x00 + 24) + +#define AT91_PIN_PA25 (PIN_BASE + 0x00 + 25) +#define AT91_PIN_PA26 (PIN_BASE + 0x00 + 26) +#define AT91_PIN_PA27 (PIN_BASE + 0x00 + 27) +#define AT91_PIN_PA28 (PIN_BASE + 0x00 + 28) +#define AT91_PIN_PA29 (PIN_BASE + 0x00 + 29) + +#define AT91_PIN_PA30 (PIN_BASE + 0x00 + 30) +#define AT91_PIN_PA31 (PIN_BASE + 0x00 + 31) + +#define AT91_PIN_PB0 (PIN_BASE + 0x20 + 0) +#define AT91_PIN_PB1 (PIN_BASE + 0x20 + 1) +#define AT91_PIN_PB2 (PIN_BASE + 0x20 + 2) +#define AT91_PIN_PB3 (PIN_BASE + 0x20 + 3) +#define AT91_PIN_PB4 (PIN_BASE + 0x20 + 4) + +#define AT91_PIN_PB5 (PIN_BASE + 0x20 + 5) +#define AT91_PIN_PB6 (PIN_BASE + 0x20 + 6) +#define AT91_PIN_PB7 (PIN_BASE + 0x20 + 7) +#define AT91_PIN_PB8 (PIN_BASE + 0x20 + 8) +#define AT91_PIN_PB9 (PIN_BASE + 0x20 + 9) + +#define AT91_PIN_PB10 (PIN_BASE + 0x20 + 10) +#define AT91_PIN_PB11 (PIN_BASE + 0x20 + 11) +#define AT91_PIN_PB12 (PIN_BASE + 0x20 + 12) +#define AT91_PIN_PB13 (PIN_BASE + 0x20 + 13) +#define AT91_PIN_PB14 (PIN_BASE + 0x20 + 14) + +#define AT91_PIN_PB15 (PIN_BASE + 0x20 + 15) +#define AT91_PIN_PB16 (PIN_BASE + 0x20 + 16) +#define AT91_PIN_PB17 (PIN_BASE + 0x20 + 17) +#define AT91_PIN_PB18 (PIN_BASE + 0x20 + 18) +#define AT91_PIN_PB19 (PIN_BASE + 0x20 + 19) + +#define AT91_PIN_PB20 (PIN_BASE + 0x20 + 20) +#define AT91_PIN_PB21 (PIN_BASE + 0x20 + 21) +#define AT91_PIN_PB22 (PIN_BASE + 0x20 + 22) +#define AT91_PIN_PB23 (PIN_BASE + 0x20 + 23) +#define AT91_PIN_PB24 (PIN_BASE + 0x20 + 24) + +#define AT91_PIN_PB25 (PIN_BASE + 0x20 + 25) +#define AT91_PIN_PB26 (PIN_BASE + 0x20 + 26) +#define AT91_PIN_PB27 (PIN_BASE + 0x20 + 27) +#define AT91_PIN_PB28 (PIN_BASE + 0x20 + 28) +#define AT91_PIN_PB29 (PIN_BASE + 0x20 + 29) + +#define AT91_PIN_PB30 (PIN_BASE + 0x20 + 30) +#define AT91_PIN_PB31 (PIN_BASE + 0x20 + 31) + +#define AT91_PIN_PC0 (PIN_BASE + 0x40 + 0) +#define AT91_PIN_PC1 (PIN_BASE + 0x40 + 1) +#define AT91_PIN_PC2 (PIN_BASE + 0x40 + 2) +#define AT91_PIN_PC3 (PIN_BASE + 0x40 + 3) +#define AT91_PIN_PC4 (PIN_BASE + 0x40 + 4) + +#define AT91_PIN_PC5 (PIN_BASE + 0x40 + 5) +#define AT91_PIN_PC6 (PIN_BASE + 0x40 + 6) +#define AT91_PIN_PC7 (PIN_BASE + 0x40 + 7) +#define AT91_PIN_PC8 (PIN_BASE + 0x40 + 8) +#define AT91_PIN_PC9 (PIN_BASE + 0x40 + 9) + +#define AT91_PIN_PC10 (PIN_BASE + 0x40 + 10) +#define AT91_PIN_PC11 (PIN_BASE + 0x40 + 11) +#define AT91_PIN_PC12 (PIN_BASE + 0x40 + 12) +#define AT91_PIN_PC13 (PIN_BASE + 0x40 + 13) +#define AT91_PIN_PC14 (PIN_BASE + 0x40 + 14) + +#define AT91_PIN_PC15 (PIN_BASE + 0x40 + 15) +#define AT91_PIN_PC16 (PIN_BASE + 0x40 + 16) +#define AT91_PIN_PC17 (PIN_BASE + 0x40 + 17) +#define AT91_PIN_PC18 (PIN_BASE + 0x40 + 18) +#define AT91_PIN_PC19 (PIN_BASE + 0x40 + 19) + +#define AT91_PIN_PC20 (PIN_BASE + 0x40 + 20) +#define AT91_PIN_PC21 (PIN_BASE + 0x40 + 21) +#define AT91_PIN_PC22 (PIN_BASE + 0x40 + 22) +#define AT91_PIN_PC23 (PIN_BASE + 0x40 + 23) +#define AT91_PIN_PC24 (PIN_BASE + 0x40 + 24) + +#define AT91_PIN_PC25 (PIN_BASE + 0x40 + 25) +#define AT91_PIN_PC26 (PIN_BASE + 0x40 + 26) +#define AT91_PIN_PC27 (PIN_BASE + 0x40 + 27) +#define AT91_PIN_PC28 (PIN_BASE + 0x40 + 28) +#define AT91_PIN_PC29 (PIN_BASE + 0x40 + 29) + +#define AT91_PIN_PC30 (PIN_BASE + 0x40 + 30) +#define AT91_PIN_PC31 (PIN_BASE + 0x40 + 31) + +#define AT91_PIN_PD0 (PIN_BASE + 0x60 + 0) +#define AT91_PIN_PD1 (PIN_BASE + 0x60 + 1) +#define AT91_PIN_PD2 (PIN_BASE + 0x60 + 2) +#define AT91_PIN_PD3 (PIN_BASE + 0x60 + 3) +#define AT91_PIN_PD4 (PIN_BASE + 0x60 + 4) + +#define AT91_PIN_PD5 (PIN_BASE + 0x60 + 5) +#define AT91_PIN_PD6 (PIN_BASE + 0x60 + 6) +#define AT91_PIN_PD7 (PIN_BASE + 0x60 + 7) +#define AT91_PIN_PD8 (PIN_BASE + 0x60 + 8) +#define AT91_PIN_PD9 (PIN_BASE + 0x60 + 9) + +#define AT91_PIN_PD10 (PIN_BASE + 0x60 + 10) +#define AT91_PIN_PD11 (PIN_BASE + 0x60 + 11) +#define AT91_PIN_PD12 (PIN_BASE + 0x60 + 12) +#define AT91_PIN_PD13 (PIN_BASE + 0x60 + 13) +#define AT91_PIN_PD14 (PIN_BASE + 0x60 + 14) + +#define AT91_PIN_PD15 (PIN_BASE + 0x60 + 15) +#define AT91_PIN_PD16 (PIN_BASE + 0x60 + 16) +#define AT91_PIN_PD17 (PIN_BASE + 0x60 + 17) +#define AT91_PIN_PD18 (PIN_BASE + 0x60 + 18) +#define AT91_PIN_PD19 (PIN_BASE + 0x60 + 19) + +#define AT91_PIN_PD20 (PIN_BASE + 0x60 + 20) +#define AT91_PIN_PD21 (PIN_BASE + 0x60 + 21) +#define AT91_PIN_PD22 (PIN_BASE + 0x60 + 22) +#define AT91_PIN_PD23 (PIN_BASE + 0x60 + 23) +#define AT91_PIN_PD24 (PIN_BASE + 0x60 + 24) + +#define AT91_PIN_PD25 (PIN_BASE + 0x60 + 25) +#define AT91_PIN_PD26 (PIN_BASE + 0x60 + 26) +#define AT91_PIN_PD27 (PIN_BASE + 0x60 + 27) +#define AT91_PIN_PD28 (PIN_BASE + 0x60 + 28) +#define AT91_PIN_PD29 (PIN_BASE + 0x60 + 29) + +#define AT91_PIN_PD30 (PIN_BASE + 0x60 + 30) +#define AT91_PIN_PD31 (PIN_BASE + 0x60 + 31) + +#ifndef __ASSEMBLY__ +/* setup setup routines, called from board init or driver probe() */ +extern int at91_set_A_periph(unsigned pin, int use_pullup); +extern int at91_set_B_periph(unsigned pin, int use_pullup); +extern int at91_set_gpio_input(unsigned pin, int use_pullup); +extern int at91_set_gpio_output(unsigned pin, int value); +extern int at91_set_deglitch(unsigned pin, int is_on); + +/* callable at any time */ +extern int at91_set_gpio_value(unsigned pin, int value); +extern int at91_get_gpio_value(unsigned pin); +#endif + +#endif + diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h new file mode 100644 index 000000000000..2646c01f8e97 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/hardware.h @@ -0,0 +1,92 @@ +/* + * include/asm-arm/arch-at91rm9200/hardware.h + * + * Copyright (C) 2003 SAN People + * Copyright (C) 2003 ATMEL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include + +#include +#include + +/* + * Remap the peripherals from address 0xFFFA0000 .. 0xFFFFFFFF + * to 0xFEFA0000 .. 0xFF000000. (384Kb) + */ +#define AT91_IO_PHYS_BASE 0xFFFA0000 +#define AT91_IO_SIZE (0xFFFFFFFF - AT91_IO_PHYS_BASE + 1) +#define AT91_IO_VIRT_BASE (0xFF000000 - AT91_IO_SIZE) + + /* Convert a physical IO address to virtual IO address */ +#define AT91_IO_P2V(x) ((x) - AT91_IO_PHYS_BASE + AT91_IO_VIRT_BASE) + +/* + * Virtual to Physical Address mapping for IO devices. + */ +#define AT91_VA_BASE_SYS AT91_IO_P2V(AT91_BASE_SYS) +#define AT91_VA_BASE_SPI AT91_IO_P2V(AT91_BASE_SPI) +#define AT91_VA_BASE_SSC2 AT91_IO_P2V(AT91_BASE_SSC2) +#define AT91_VA_BASE_SSC1 AT91_IO_P2V(AT91_BASE_SSC1) +#define AT91_VA_BASE_SSC0 AT91_IO_P2V(AT91_BASE_SSC0) +#define AT91_VA_BASE_US3 AT91_IO_P2V(AT91_BASE_US3) +#define AT91_VA_BASE_US2 AT91_IO_P2V(AT91_BASE_US2) +#define AT91_VA_BASE_US1 AT91_IO_P2V(AT91_BASE_US1) +#define AT91_VA_BASE_US0 AT91_IO_P2V(AT91_BASE_US0) +#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91_BASE_EMAC) +#define AT91_VA_BASE_TWI AT91_IO_P2V(AT91_BASE_TWI) +#define AT91_VA_BASE_MCI AT91_IO_P2V(AT91_BASE_MCI) +#define AT91_VA_BASE_UDP AT91_IO_P2V(AT91_BASE_UDP) +#define AT91_VA_BASE_TCB1 AT91_IO_P2V(AT91_BASE_TCB1) +#define AT91_VA_BASE_TCB0 AT91_IO_P2V(AT91_BASE_TCB0) + +/* Internal SRAM */ +#define AT91_BASE_SRAM 0x00200000 /* Internal SRAM base address */ +#define AT91_SRAM_SIZE 0x00004000 /* Internal SRAM SIZE (16Kb) */ + +/* Serial ports */ +#define AT91_NR_UART 5 /* 4 USART3's and one DBGU port */ + +/* FLASH */ +#define AT91_FLASH_BASE 0x10000000 /* NCS0: Flash physical base address */ + +/* SDRAM */ +#define AT91_SDRAM_BASE 0x20000000 /* NCS1: SDRAM physical base address */ + +/* SmartMedia */ +#define AT91_SMARTMEDIA_BASE 0x40000000 /* NCS3: Smartmedia physical base address */ + +/* Multi-Master Memory controller */ +#define AT91_UHP_BASE 0x00300000 /* USB Host controller */ + +/* Clocks */ +#define AT91_SLOW_CLOCK 32768 /* slow clock */ + +#ifndef __ASSEMBLY__ +#include + +static inline unsigned int at91_sys_read(unsigned int reg_offset) +{ + void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS; + + return readl(addr + reg_offset); +} + +static inline void at91_sys_write(unsigned int reg_offset, unsigned long value) +{ + void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS; + + writel(value, addr + reg_offset); +} +#endif + +#endif diff --git a/include/asm-arm/arch-at91rm9200/io.h b/include/asm-arm/arch-at91rm9200/io.h new file mode 100644 index 000000000000..23e670d85c9d --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/io.h @@ -0,0 +1,33 @@ +/* + * include/asm-arm/arch-at91rm9200/io.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#include +#include + +#define IO_SPACE_LIMIT 0xFFFFFFFF + +#define __io(a) ((void __iomem *)(a)) +#define __mem_pci(a) (a) + + +#endif diff --git a/include/asm-arm/arch-at91rm9200/irqs.h b/include/asm-arm/arch-at91rm9200/irqs.h new file mode 100644 index 000000000000..27b0497f1b36 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/irqs.h @@ -0,0 +1,52 @@ +/* + * include/asm-arm/arch-at91rm9200/irqs.h + * + * Copyright (C) 2004 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H + +#define NR_AIC_IRQS 32 + + +/* + * Acknowledge interrupt with AIC after interrupt has been handled. + * (by kernel/irq.c) + */ +#define irq_finish(irq) do { at91_sys_write(AT91_AIC_EOICR, 0); } while (0) + + +/* + * IRQ interrupt symbols are the AT91_ID_* symbols in at91rm9200.h + * for IRQs handled directly through the AIC, or else the AT91_PIN_* + * symbols in gpio.h for ones handled indirectly as GPIOs. + * We make provision for 4 banks of GPIO. + */ +#include + +#define NR_IRQS (NR_AIC_IRQS + (4 * 32)) + + +#ifndef __ASSEMBLY__ +/* + * Initialize the IRQ controller. + */ +extern void at91rm9200_init_irq(unsigned int priority[]); +#endif + +#endif diff --git a/include/asm-arm/arch-at91rm9200/memory.h b/include/asm-arm/arch-at91rm9200/memory.h new file mode 100644 index 000000000000..462f1f0ad67c --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/memory.h @@ -0,0 +1,41 @@ +/* + * include/asm-arm/arch-at91rm9200/memory.h + * + * Copyright (C) 2004 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +#include + +#define PHYS_OFFSET (AT91_SDRAM_BASE) + + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif diff --git a/include/asm-arm/arch-at91rm9200/param.h b/include/asm-arm/arch-at91rm9200/param.h new file mode 100644 index 000000000000..9480f8446852 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/param.h @@ -0,0 +1,28 @@ +/* + * include/asm-arm/arch-at91rm9200/param.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_PARAM_H +#define __ASM_ARCH_PARAM_H + +/* + * We use default params + */ + +#endif diff --git a/include/asm-arm/arch-at91rm9200/pio.h b/include/asm-arm/arch-at91rm9200/pio.h new file mode 100644 index 000000000000..a89501b4a703 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/pio.h @@ -0,0 +1,115 @@ +/* + * include/asm-arm/arch-at91rm9200/pio.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_PIO_H +#define __ASM_ARCH_PIO_H + +#include + +static inline void AT91_CfgPIO_USART0(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA17_TXD0 | AT91_PA18_RXD0 | AT91_PA20_CTS0); + + /* + * Errata #39 - RTS0 is not internally connected to PA21. We need to drive + * the pin manually. Default is off (RTS is active low). + */ + at91_sys_write(AT91_PIOA + PIO_PER, AT91_PA21_RTS0); + at91_sys_write(AT91_PIOA + PIO_OER, AT91_PA21_RTS0); + at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0); +} + +static inline void AT91_CfgPIO_USART1(void) { + at91_sys_write(AT91_PIOB + PIO_PDR, AT91_PB18_RI1 | AT91_PB19_DTR1 + | AT91_PB20_TXD1 | AT91_PB21_RXD1 | AT91_PB23_DCD1 + | AT91_PB24_CTS1 | AT91_PB25_DSR1 | AT91_PB26_RTS1); +} + +static inline void AT91_CfgPIO_USART2(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA22_RXD2 | AT91_PA23_TXD2); +} + +static inline void AT91_CfgPIO_USART3(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA5_TXD3 | AT91_PA6_RXD3); + at91_sys_write(AT91_PIOA + PIO_BSR, AT91_PA5_TXD3 | AT91_PA6_RXD3); +} + +static inline void AT91_CfgPIO_DBGU(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA31_DTXD | AT91_PA30_DRXD); +} + +/* + * Enable the Two-Wire interface. + */ +static inline void AT91_CfgPIO_TWI(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA25_TWD | AT91_PA26_TWCK); + at91_sys_write(AT91_PIOA + PIO_ASR, AT91_PA25_TWD | AT91_PA26_TWCK); + at91_sys_write(AT91_PIOA + PIO_MDER, AT91_PA25_TWD | AT91_PA26_TWCK); /* open drain */ +} + +/* + * Enable the Serial Peripheral Interface. + */ +static inline void AT91_CfgPIO_SPI(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA0_MISO | AT91_PA1_MOSI | AT91_PA2_SPCK); +} + +static inline void AT91_CfgPIO_SPI_CS0(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA3_NPCS0); +} + +static inline void AT91_CfgPIO_SPI_CS1(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA4_NPCS1); +} + +static inline void AT91_CfgPIO_SPI_CS2(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA5_NPCS2); +} + +static inline void AT91_CfgPIO_SPI_CS3(void) { + at91_sys_write(AT91_PIOA + PIO_PDR, AT91_PA6_NPCS3); +} + +/* + * Select the DataFlash card. + */ +static inline void AT91_CfgPIO_DataFlashCard(void) { + at91_sys_write(AT91_PIOB + PIO_PER, AT91_PIO_P(7)); + at91_sys_write(AT91_PIOB + PIO_OER, AT91_PIO_P(7)); + at91_sys_write(AT91_PIOB + PIO_CODR, AT91_PIO_P(7)); +} + +/* + * Enable NAND Flash (SmartMedia) interface. + */ +static inline void AT91_CfgPIO_SmartMedia(void) { + /* enable PC0=SMCE, PC1=SMOE, PC3=SMWE, A21=CLE, A22=ALE */ + at91_sys_write(AT91_PIOC + PIO_ASR, AT91_PC0_BFCK | AT91_PC1_BFRDY_SMOE | AT91_PC3_BFBAA_SMWE); + at91_sys_write(AT91_PIOC + PIO_PDR, AT91_PC0_BFCK | AT91_PC1_BFRDY_SMOE | AT91_PC3_BFBAA_SMWE); + + /* Configure PC2 as input (signal READY of the SmartMedia) */ + at91_sys_write(AT91_PIOC + PIO_PER, AT91_PC2_BFAVD); /* enable direct output enable */ + at91_sys_write(AT91_PIOC + PIO_ODR, AT91_PC2_BFAVD); /* disable output */ + + /* Configure PB1 as input (signal Card Detect of the SmartMedia) */ + at91_sys_write(AT91_PIOB + PIO_PER, AT91_PIO_P(1)); /* enable direct output enable */ + at91_sys_write(AT91_PIOB + PIO_ODR, AT91_PIO_P(1)); /* disable output */ +} + +static inline int AT91_PIO_SmartMedia_RDY(void) { + return (at91_sys_read(AT91_PIOC + PIO_PDSR) & AT91_PIO_P(2)) ? 1 : 0; +} + +static inline int AT91_PIO_SmartMedia_CardDetect(void) { + return (at91_sys_read(AT91_PIOB + PIO_PDSR) & AT91_PIO_P(1)) ? 1 : 0; +} + +#endif diff --git a/include/asm-arm/arch-at91rm9200/system.h b/include/asm-arm/arch-at91rm9200/system.h new file mode 100644 index 000000000000..29c42655f05c --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/system.h @@ -0,0 +1,51 @@ +/* + * include/asm-arm/arch-at91rm9200/system.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include + +static inline void arch_idle(void) +{ + /* + * Disable the processor clock. The processor will be automatically + * re-enabled by an interrupt or by a reset. + */ +// at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK); + + /* + * Set the processor (CP15) into 'Wait for Interrupt' mode. + * Unlike disabling the processor clock via the PMC (above) + * this allows the processor to be woken via JTAG. + */ + cpu_do_idle(); +} + +static inline void arch_reset(char mode) +{ + /* + * Perform a hardware reset with the use of the Watchdog timer. + */ + at91_sys_write(AT91_ST_WDMR, AT91_ST_RSTEN | AT91_ST_EXTEN | 1); + at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); +} + +#endif diff --git a/include/asm-arm/arch-at91rm9200/timex.h b/include/asm-arm/arch-at91rm9200/timex.h new file mode 100644 index 000000000000..3f112dd12587 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/timex.h @@ -0,0 +1,28 @@ +/* + * include/asm-arm/arch-at91rm9200/timex.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_TIMEX_H +#define __ASM_ARCH_TIMEX_H + +#include + +#define CLOCK_TICK_RATE (AT91_SLOW_CLOCK) + +#endif diff --git a/include/asm-arm/arch-at91rm9200/uncompress.h b/include/asm-arm/arch-at91rm9200/uncompress.h new file mode 100644 index 000000000000..b30dd5520713 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/uncompress.h @@ -0,0 +1,55 @@ +/* + * include/asm-arm/arch-at91rm9200/uncompress.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_UNCOMPRESS_H +#define __ASM_ARCH_UNCOMPRESS_H + +#include + +/* + * The following code assumes the serial port has already been + * initialized by the bootloader. We search for the first enabled + * port in the most probable order. If you didn't setup a port in + * your bootloader then nothing will appear (which might be desired). + * + * This does not append a newline + */ +static void putstr(const char *s) +{ + void __iomem *sys = (void __iomem *) AT91_BASE_SYS; /* physical address */ + + while (*s) { + while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXRDY)) { barrier(); } + __raw_writel(*s, sys + AT91_DBGU_THR); + if (*s == '\n') { + while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXRDY)) { barrier(); } + __raw_writel('\r', sys + AT91_DBGU_THR); + } + s++; + } + /* wait for transmission to complete */ + while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXEMPTY)) { barrier(); } +} + +#define arch_decomp_setup() + +#define arch_decomp_wdog() + +#endif diff --git a/include/asm-arm/arch-at91rm9200/vmalloc.h b/include/asm-arm/arch-at91rm9200/vmalloc.h new file mode 100644 index 000000000000..34d9718feb90 --- /dev/null +++ b/include/asm-arm/arch-at91rm9200/vmalloc.h @@ -0,0 +1,26 @@ +/* + * include/asm-arm/arch-at91rm9200/vmalloc.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_VMALLOC_H +#define __ASM_ARCH_VMALLOC_H + +#define VMALLOC_END (AT91_IO_VIRT_BASE & PGDIR_MASK) + +#endif -- cgit v1.2.3 From 8ef12c9f01afba47c2d33bb939085111ca0d0f7d Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 9 Jan 2006 17:08:11 +0000 Subject: [ARM] AT91RM9200 doesn't need anything in dma.h Signed-off-by: Russell King --- include/asm-arm/arch-at91rm9200/dma.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/asm-arm/arch-at91rm9200/dma.h b/include/asm-arm/arch-at91rm9200/dma.h index 6738bdd74b22..22c1dfdd8da3 100644 --- a/include/asm-arm/arch-at91rm9200/dma.h +++ b/include/asm-arm/arch-at91rm9200/dma.h @@ -17,11 +17,3 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H - -#define MAX_DMA_ADDRESS 0xffffffff -#define MAX_DMA_CHANNELS 0 - -#endif /* _ASM_ARCH_DMA_H */ -- cgit v1.2.3 From 0d0fbf8152fb3bb4393be11e8df7f70e1fbbd738 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Jan 2006 15:24:57 -0200 Subject: V4L (926_2): Moves compat32 functions from fs to v4l subsystem This moves the 32 bit ioctl compatibility handlers for Video4Linux into a new file and adds explicit calls to them to each v4l device driver. Unfortunately, there does not seem to be any code handling the v4l2 ioctls, so quite often the code goes through two separate conversions, first from 32 bit v4l to 64 bit v4l, and from there to 64 bit v4l2. My patch does not change that, so there is still much room for improvement. Also, some drivers have additional ioctl numbers, for which the conversion should be handled internally to that driver. Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/miropcm20-radio.c | 1 + drivers/media/radio/radio-aimslab.c | 1 + drivers/media/radio/radio-aztech.c | 1 + drivers/media/radio/radio-cadet.c | 1 + drivers/media/radio/radio-gemtek-pci.c | 1 + drivers/media/radio/radio-gemtek.c | 1 + drivers/media/radio/radio-maestro.c | 1 + drivers/media/radio/radio-maxiradio.c | 1 + drivers/media/radio/radio-rtrack2.c | 1 + drivers/media/radio/radio-sf16fmi.c | 1 + drivers/media/radio/radio-sf16fmr2.c | 1 + drivers/media/radio/radio-terratec.c | 1 + drivers/media/radio/radio-trust.c | 1 + drivers/media/radio/radio-typhoon.c | 1 + drivers/media/radio/radio-zoltrix.c | 1 + drivers/media/video/Makefile | 3 +- drivers/media/video/arv.c | 1 + drivers/media/video/bttv-driver.c | 1 + drivers/media/video/bw-qcam.c | 1 + drivers/media/video/c-qcam.c | 1 + drivers/media/video/compat_ioctl32.c | 318 ++++++++++++++++++++++++++++ drivers/media/video/cpia.c | 1 + drivers/media/video/cx88/cx88-video.c | 2 + drivers/media/video/meye.c | 1 + drivers/media/video/pms.c | 1 + drivers/media/video/saa5249.c | 1 + drivers/media/video/saa7134/saa7134-video.c | 2 + drivers/media/video/stradis.c | 1 + drivers/media/video/w9966.c | 1 + drivers/media/video/zoran_driver.c | 1 + drivers/media/video/zr36120.c | 1 + drivers/usb/media/dsbr100.c | 1 + drivers/usb/media/ov511.c | 1 + drivers/usb/media/pwc/pwc-if.c | 1 + drivers/usb/media/se401.c | 1 + drivers/usb/media/stv680.c | 1 + drivers/usb/media/usbvideo.c | 1 + drivers/usb/media/vicam.c | 1 + drivers/usb/media/w9968cf.c | 1 + fs/compat_ioctl.c | 246 --------------------- include/linux/compat_ioctl.h | 26 --- include/linux/videodev2.h | 3 + 42 files changed, 362 insertions(+), 273 deletions(-) create mode 100644 drivers/media/video/compat_ioctl32.c diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c index c2ebe8754a95..dc292da2605f 100644 --- a/drivers/media/radio/miropcm20-radio.c +++ b/drivers/media/radio/miropcm20-radio.c @@ -220,6 +220,7 @@ static struct file_operations pcm20_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = pcm20_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 877c770558e9..914deab4e044 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -299,6 +299,7 @@ static struct file_operations rtrack_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = rt_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 5319a9c9a979..523be820f9c6 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -256,6 +256,7 @@ static struct file_operations aztech_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = az_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 9b0406318f2d..f1b5ac81e9d2 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -490,6 +490,7 @@ static struct file_operations cadet_fops = { .release = cadet_release, .read = cadet_read, .ioctl = cadet_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 630cc786d0a4..42c8fce04aa2 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -301,6 +301,7 @@ static struct file_operations gemtek_pci_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = gemtek_pci_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 6418f03b9ce4..47173be97b9f 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -233,6 +233,7 @@ static struct file_operations gemtek_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = gemtek_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index e5e2021a7312..c30effdf711f 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -72,6 +72,7 @@ static struct file_operations maestro_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = radio_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 02d39a50d5ed..30869308332a 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -80,6 +80,7 @@ static struct file_operations maxiradio_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = radio_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static struct video_device maxiradio_radio = diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index b2256d675b44..28a47c9e7a81 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -199,6 +199,7 @@ static struct file_operations rtrack2_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = rt_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 6f03ce4dd7b0..0229f792a059 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -225,6 +225,7 @@ static struct file_operations fmi_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = fmi_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 71971e9bb342..26632cead09a 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -356,6 +356,7 @@ static struct file_operations fmr2_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = fmr2_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index b03573c6840e..fcfde2e4f195 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -276,6 +276,7 @@ static struct file_operations terratec_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = tt_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index b300bedf7c74..5a099a50d4d0 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -255,6 +255,7 @@ static struct file_operations trust_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = tr_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index f304f3c14763..8ac9a8ef9094 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -261,6 +261,7 @@ static struct file_operations typhoon_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = typhoon_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 4c6d6fb49034..d590e80c922e 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -313,6 +313,7 @@ static struct file_operations zoltrix_fops = .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = zol_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 82060f9909d8..618a08ab940a 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -8,7 +8,8 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o + +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 881cdcb1875d..7d5a068353f2 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -749,6 +749,7 @@ static struct file_operations ar_fops = { .release = video_exclusive_release, .read = ar_read, .ioctl = ar_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 1ddf9ba613ef..03f925724ce9 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3120,6 +3120,7 @@ static struct file_operations bttv_fops = .open = bttv_open, .release = bttv_release, .ioctl = bttv_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, .read = bttv_read, .mmap = bttv_mmap, diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 0065d0c240d1..6bad93ef969f 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -875,6 +875,7 @@ static struct file_operations qcam_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = qcam_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .read = qcam_read, .llseek = no_llseek, }; diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 75442ec49f35..9976db4f6da8 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -687,6 +687,7 @@ static struct file_operations qcam_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = qcam_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .read = qcam_read, .llseek = no_llseek, }; diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c new file mode 100644 index 000000000000..42dc11c63c0d --- /dev/null +++ b/drivers/media/video/compat_ioctl32.c @@ -0,0 +1,318 @@ +#include +#include +#include + +#ifdef CONFIG_COMPAT +struct video_tuner32 { + compat_int_t tuner; + char name[32]; + compat_ulong_t rangelow, rangehigh; + u32 flags; /* It is really u32 in videodev.h */ + u16 mode, signal; +}; + +static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) +{ + int i; + + if(get_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __get_user(kp->name[i], &up->name[i]); + __get_user(kp->rangelow, &up->rangelow); + __get_user(kp->rangehigh, &up->rangehigh); + __get_user(kp->flags, &up->flags); + __get_user(kp->mode, &up->mode); + __get_user(kp->signal, &up->signal); + return 0; +} + +static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) +{ + int i; + + if(put_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __put_user(kp->name[i], &up->name[i]); + __put_user(kp->rangelow, &up->rangelow); + __put_user(kp->rangehigh, &up->rangehigh); + __put_user(kp->flags, &up->flags); + __put_user(kp->mode, &up->mode); + __put_user(kp->signal, &up->signal); + return 0; +} + +struct video_buffer32 { + compat_caddr_t base; + compat_int_t height, width, depth, bytesperline; +}; + +static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up) +{ + u32 tmp; + + if (get_user(tmp, &up->base)) + return -EFAULT; + + /* This is actually a physical address stored + * as a void pointer. + */ + kp->base = (void *)(unsigned long) tmp; + + __get_user(kp->height, &up->height); + __get_user(kp->width, &up->width); + __get_user(kp->depth, &up->depth); + __get_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up) +{ + u32 tmp = (u32)((unsigned long)kp->base); + + if(put_user(tmp, &up->base)) + return -EFAULT; + __put_user(kp->height, &up->height); + __put_user(kp->width, &up->width); + __put_user(kp->depth, &up->depth); + __put_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +struct video_clip32 { + s32 x, y, width, height; /* Its really s32 in videodev.h */ + compat_caddr_t next; +}; + +struct video_window32 { + u32 x, y, width, height, chromakey, flags; + compat_caddr_t clips; + compat_int_t clipcount; +}; + +static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = -ENOIOCTLCMD; + + if (file->f_ops->unlocked_ioctl) + ret = file->f_ops->unlocked_ioctl(file, cmd, arg); + else if (file->f_ops->ioctl) { + lock_kernel(); + ret = file->f_ops->ioctl(file->f_dentry->d_inode, file, cmd, arg); + unlock_kernel(); + } + + return ret; +} + + +/* You get back everything except the clips... */ +static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) +{ + if(put_user(kp->x, &up->x)) + return -EFAULT; + __put_user(kp->y, &up->y); + __put_user(kp->width, &up->width); + __put_user(kp->height, &up->height); + __put_user(kp->chromakey, &up->chromakey); + __put_user(kp->flags, &up->flags); + __put_user(kp->clipcount, &up->clipcount); + return 0; +} + +#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) +#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) +#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) +#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) +#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) +#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) +#define VIDIOCGFREQ32 _IOR('v',14, u32) +#define VIDIOCSFREQ32 _IOW('v',15, u32) + +enum { + MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) +}; + +static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct video_window32 __user *up = compat_ptr(arg); + struct video_window __user *vw; + struct video_clip __user *p; + int nclips; + u32 n; + + if (get_user(nclips, &up->clipcount)) + return -EFAULT; + + /* Peculiar interface... */ + if (nclips < 0) + nclips = VIDEO_CLIPMAP_SIZE; + + if (nclips > MaxClips) + return -ENOMEM; + + vw = compat_alloc_user_space(sizeof(struct video_window) + + nclips * sizeof(struct video_clip)); + + p = nclips ? (struct video_clip __user *)(vw + 1) : NULL; + + if (get_user(n, &up->x) || put_user(n, &vw->x) || + get_user(n, &up->y) || put_user(n, &vw->y) || + get_user(n, &up->width) || put_user(n, &vw->width) || + get_user(n, &up->height) || put_user(n, &vw->height) || + get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) || + get_user(n, &up->flags) || put_user(n, &vw->flags) || + get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) || + get_user(n, &up->clips) || put_user(p, &vw->clips)) + return -EFAULT; + + if (nclips) { + struct video_clip32 __user *u = compat_ptr(n); + int i; + if (!u) + return -EINVAL; + for (i = 0; i < nclips; i++, u++, p++) { + s32 v; + if (get_user(v, &u->x) || + put_user(v, &p->x) || + get_user(v, &u->y) || + put_user(v, &p->y) || + get_user(v, &u->width) || + put_user(v, &p->width) || + get_user(v, &u->height) || + put_user(v, &p->height) || + put_user(NULL, &p->next)) + return -EFAULT; + } + } + + return native_ioctl(file, VIDIOCSWIN, (unsigned long)p); +} + +static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + union { + struct video_tuner vt; + struct video_buffer vb; + struct video_window vw; + unsigned long vx; + } karg; + mm_segment_t old_fs = get_fs(); + void __user *up = compat_ptr(arg); + int err = 0; + + /* First, convert the command. */ + switch(cmd) { + case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; + case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; + case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; + case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; + case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; + case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; + case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; + }; + + switch(cmd) { + case VIDIOCSTUNER: + case VIDIOCGTUNER: + err = get_video_tuner32(&karg.vt, up); + break; + + case VIDIOCSFBUF: + err = get_video_buffer32(&karg.vb, up); + break; + + case VIDIOCSFREQ: + err = get_user(karg.vx, (u32 __user *)up); + break; + }; + if(err) + goto out; + + set_fs(KERNEL_DS); + err = native_ioctl(file, cmd, (unsigned long)&karg); + set_fs(old_fs); + + if(err == 0) { + switch(cmd) { + case VIDIOCGTUNER: + err = put_video_tuner32(&karg.vt, up); + break; + + case VIDIOCGWIN: + err = put_video_window32(&karg.vw, up); + break; + + case VIDIOCGFBUF: + err = put_video_buffer32(&karg.vb, up); + break; + + case VIDIOCGFREQ: + err = put_user(((u32)karg.vx), (u32 __user *)up); + break; + }; + } +out: + return err; +} + +long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = -ENOIOCTLCMD; + + if (!file->f_ops->ioctl) + return ret; + + switch (cmd) { + case VIDIOCSWIN32: + ret = do_set_window(file, cmd, arg); + break; + case VIDIOCGTUNER32: + case VIDIOCSTUNER32: + case VIDIOCGWIN32: + case VIDIOCGFBUF32: + case VIDIOCSFBUF32: + case VIDIOCGFREQ32: + case VIDIOCSFREQ32 + ret = do_video_ioctl(file, cmd, arg); + break; + + /* Little v, the video4linux ioctls (conflict?) */ + case VIDIOCGCAP: + case VIDIOCGCHAN: + case VIDIOCSCHAN: + case VIDIOCGPICT: + case VIDIOCSPICT: + case VIDIOCCAPTURE: + case VIDIOCKEY: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + case VIDIOCSYNC: + case VIDIOCMCAPTURE: + case VIDIOCGMBUF: + case VIDIOCGUNIT: + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + + /* BTTV specific... */ + case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]): + case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]): + case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int): + case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */ + case _IOR('v' , BASE_VIDIOCPRIVATE+4, int): + case _IOR('v' , BASE_VIDIOCPRIVATE+5, int): + case _IOR('v' , BASE_VIDIOCPRIVATE+6, int): + case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): + ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); + break; + + return ret; +} +#else +long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} +#endif +EXPORT_SYMBOL_GPL(v4l_compat_ioctl32); diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index b7ec9bf45085..9f59541155d9 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -3807,6 +3807,7 @@ static struct file_operations cpia_fops = { .read = cpia_read, .mmap = cpia_mmap, .ioctl = cpia_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 24a48f8a48c1..bc025c46aedf 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1740,6 +1740,7 @@ static struct file_operations video_fops = .poll = video_poll, .mmap = video_mmap, .ioctl = video_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -1767,6 +1768,7 @@ static struct file_operations radio_fops = .open = video_open, .release = video_release, .ioctl = radio_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 3f2a882bc20a..2869464aee0d 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1754,6 +1754,7 @@ static struct file_operations meye_fops = { .release = meye_release, .mmap = meye_mmap, .ioctl = meye_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .poll = meye_poll, .llseek = no_llseek, }; diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 2504207b2e3d..9e6448639480 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -883,6 +883,7 @@ static struct file_operations pms_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = pms_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .read = pms_read, .llseek = no_llseek, }; diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index a51c7bd96618..73b4f0e2abf0 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -702,6 +702,7 @@ static struct file_operations saa_fops = { .open = saa5249_open, .release = saa5249_release, .ioctl = saa5249_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 45c852df13ed..9b9e1e7f05ef 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2262,6 +2262,7 @@ static struct file_operations video_fops = .poll = video_poll, .mmap = video_mmap, .ioctl = video_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2271,6 +2272,7 @@ static struct file_operations radio_fops = .open = video_open, .release = video_release, .ioctl = radio_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index d4497dbae05c..6ee54a45411f 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -1974,6 +1974,7 @@ static struct file_operations saa_fops = .open = saa_open, .release = saa_release, .ioctl = saa_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .read = saa_read, .llseek = no_llseek, .write = saa_write, diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index c318ba32fbaf..b7b0afffd214 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -187,6 +187,7 @@ static struct file_operations w9966_fops = { .open = video_exclusive_open, .release = video_exclusive_release, .ioctl = w9966_v4l_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .read = w9966_v4l_read, .llseek = no_llseek, }; diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 4034f1b45366..15283f44e79f 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -4678,6 +4678,7 @@ static struct file_operations zoran_fops = { .open = zoran_open, .release = zoran_close, .ioctl = zoran_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, .read = zoran_read, .write = zoran_write, diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c index 07286816d7df..d4c633b8a7f5 100644 --- a/drivers/media/video/zr36120.c +++ b/drivers/media/video/zr36120.c @@ -1490,6 +1490,7 @@ static struct video_device zr36120_template= .write = zoran_write, .poll = zoran_poll, .ioctl = zoran_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .mmap = zoran_mmap, .minor = -1, }; diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c index 6a5700e9d428..25646804d5be 100644 --- a/drivers/usb/media/dsbr100.c +++ b/drivers/usb/media/dsbr100.c @@ -127,6 +127,7 @@ static struct file_operations usb_dsbr100_fops = { .open = usb_dsbr100_open, .release = usb_dsbr100_close, .ioctl = usb_dsbr100_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index 3a0e8ce67ebe..8af665bbe330 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -4774,6 +4774,7 @@ static struct file_operations ov511_fops = { .read = ov51x_v4l1_read, .mmap = ov51x_v4l1_mmap, .ioctl = ov51x_v4l1_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c index 09ca6128ac20..4f9b0dc6fd7b 100644 --- a/drivers/usb/media/pwc/pwc-if.c +++ b/drivers/usb/media/pwc/pwc-if.c @@ -154,6 +154,7 @@ static struct file_operations pwc_fops = { .poll = pwc_video_poll, .mmap = pwc_video_mmap, .ioctl = pwc_video_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static struct video_device pwc_template = { diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c index b2ae29af5940..2ba562285fda 100644 --- a/drivers/usb/media/se401.c +++ b/drivers/usb/media/se401.c @@ -1193,6 +1193,7 @@ static struct file_operations se401_fops = { .read = se401_read, .mmap = se401_mmap, .ioctl = se401_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static struct video_device se401_template = { diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index 774038b352cd..b497a6a0a206 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -1343,6 +1343,7 @@ static struct file_operations stv680_fops = { .read = stv680_read, .mmap = stv680_mmap, .ioctl = stv680_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static struct video_device stv680_template = { diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c index 4bd113325ef9..63a72e550a1b 100644 --- a/drivers/usb/media/usbvideo.c +++ b/drivers/usb/media/usbvideo.c @@ -953,6 +953,7 @@ static struct file_operations usbvideo_fops = { .read = usbvideo_v4l_read, .mmap = usbvideo_v4l_mmap, .ioctl = usbvideo_v4l_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static const struct video_device usbvideo_template = { diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 1c73155c8d77..5df144073871 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -1236,6 +1236,7 @@ static struct file_operations vicam_fops = { .read = vicam_read, .mmap = vicam_mmap, .ioctl = vicam_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c index 3605a6f3067b..bff9434c8e55 100644 --- a/drivers/usb/media/w9968cf.c +++ b/drivers/usb/media/w9968cf.c @@ -3490,6 +3490,7 @@ static struct file_operations w9968cf_fops = { .release = w9968cf_release, .read = w9968cf_read, .ioctl = w9968cf_ioctl, + .compat_ioctl = v4l_compat_ioctl32, .mmap = w9968cf_mmap, .llseek = no_llseek, }; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 43a2508ac696..55d9a3a954cf 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -207,244 +207,6 @@ static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg)); } -struct video_tuner32 { - compat_int_t tuner; - char name[32]; - compat_ulong_t rangelow, rangehigh; - u32 flags; /* It is really u32 in videodev.h */ - u16 mode, signal; -}; - -static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) -{ - int i; - - if(get_user(kp->tuner, &up->tuner)) - return -EFAULT; - for(i = 0; i < 32; i++) - __get_user(kp->name[i], &up->name[i]); - __get_user(kp->rangelow, &up->rangelow); - __get_user(kp->rangehigh, &up->rangehigh); - __get_user(kp->flags, &up->flags); - __get_user(kp->mode, &up->mode); - __get_user(kp->signal, &up->signal); - return 0; -} - -static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) -{ - int i; - - if(put_user(kp->tuner, &up->tuner)) - return -EFAULT; - for(i = 0; i < 32; i++) - __put_user(kp->name[i], &up->name[i]); - __put_user(kp->rangelow, &up->rangelow); - __put_user(kp->rangehigh, &up->rangehigh); - __put_user(kp->flags, &up->flags); - __put_user(kp->mode, &up->mode); - __put_user(kp->signal, &up->signal); - return 0; -} - -struct video_buffer32 { - compat_caddr_t base; - compat_int_t height, width, depth, bytesperline; -}; - -static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up) -{ - u32 tmp; - - if (get_user(tmp, &up->base)) - return -EFAULT; - - /* This is actually a physical address stored - * as a void pointer. - */ - kp->base = (void *)(unsigned long) tmp; - - __get_user(kp->height, &up->height); - __get_user(kp->width, &up->width); - __get_user(kp->depth, &up->depth); - __get_user(kp->bytesperline, &up->bytesperline); - return 0; -} - -static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up) -{ - u32 tmp = (u32)((unsigned long)kp->base); - - if(put_user(tmp, &up->base)) - return -EFAULT; - __put_user(kp->height, &up->height); - __put_user(kp->width, &up->width); - __put_user(kp->depth, &up->depth); - __put_user(kp->bytesperline, &up->bytesperline); - return 0; -} - -struct video_clip32 { - s32 x, y, width, height; /* Its really s32 in videodev.h */ - compat_caddr_t next; -}; - -struct video_window32 { - u32 x, y, width, height, chromakey, flags; - compat_caddr_t clips; - compat_int_t clipcount; -}; - -/* You get back everything except the clips... */ -static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) -{ - if(put_user(kp->x, &up->x)) - return -EFAULT; - __put_user(kp->y, &up->y); - __put_user(kp->width, &up->width); - __put_user(kp->height, &up->height); - __put_user(kp->chromakey, &up->chromakey); - __put_user(kp->flags, &up->flags); - __put_user(kp->clipcount, &up->clipcount); - return 0; -} - -#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) -#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) -#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) -#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) -#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) -#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) -#define VIDIOCGFREQ32 _IOR('v',14, u32) -#define VIDIOCSFREQ32 _IOW('v',15, u32) - -enum { - MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) -}; - -static int do_set_window(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct video_window32 __user *up = compat_ptr(arg); - struct video_window __user *vw; - struct video_clip __user *p; - int nclips; - u32 n; - - if (get_user(nclips, &up->clipcount)) - return -EFAULT; - - /* Peculiar interface... */ - if (nclips < 0) - nclips = VIDEO_CLIPMAP_SIZE; - - if (nclips > MaxClips) - return -ENOMEM; - - vw = compat_alloc_user_space(sizeof(struct video_window) + - nclips * sizeof(struct video_clip)); - - p = nclips ? (struct video_clip __user *)(vw + 1) : NULL; - - if (get_user(n, &up->x) || put_user(n, &vw->x) || - get_user(n, &up->y) || put_user(n, &vw->y) || - get_user(n, &up->width) || put_user(n, &vw->width) || - get_user(n, &up->height) || put_user(n, &vw->height) || - get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) || - get_user(n, &up->flags) || put_user(n, &vw->flags) || - get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) || - get_user(n, &up->clips) || put_user(p, &vw->clips)) - return -EFAULT; - - if (nclips) { - struct video_clip32 __user *u = compat_ptr(n); - int i; - if (!u) - return -EINVAL; - for (i = 0; i < nclips; i++, u++, p++) { - s32 v; - if (get_user(v, &u->x) || - put_user(v, &p->x) || - get_user(v, &u->y) || - put_user(v, &p->y) || - get_user(v, &u->width) || - put_user(v, &p->width) || - get_user(v, &u->height) || - put_user(v, &p->height) || - put_user(NULL, &p->next)) - return -EFAULT; - } - } - - return sys_ioctl(fd, VIDIOCSWIN, (unsigned long)p); -} - -static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - union { - struct video_tuner vt; - struct video_buffer vb; - struct video_window vw; - unsigned long vx; - } karg; - mm_segment_t old_fs = get_fs(); - void __user *up = compat_ptr(arg); - int err = 0; - - /* First, convert the command. */ - switch(cmd) { - case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; - case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; - case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; - case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; - case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; - case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; - case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; - }; - - switch(cmd) { - case VIDIOCSTUNER: - case VIDIOCGTUNER: - err = get_video_tuner32(&karg.vt, up); - break; - - case VIDIOCSFBUF: - err = get_video_buffer32(&karg.vb, up); - break; - - case VIDIOCSFREQ: - err = get_user(karg.vx, (u32 __user *)up); - break; - }; - if(err) - goto out; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&karg); - set_fs(old_fs); - - if(err == 0) { - switch(cmd) { - case VIDIOCGTUNER: - err = put_video_tuner32(&karg.vt, up); - break; - - case VIDIOCGWIN: - err = put_video_window32(&karg.vw, up); - break; - - case VIDIOCGFBUF: - err = put_video_buffer32(&karg.vb, up); - break; - - case VIDIOCGFREQ: - err = put_user(((u32)karg.vx), (u32 __user *)up); - break; - }; - } -out: - return err; -} - struct compat_dmx_event { dmx_event_t event; compat_time_t timeStamp; @@ -3015,14 +2777,6 @@ COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD) #ifdef CONFIG_JBD_DEBUG HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl) #endif -HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSWIN32, do_set_window) -HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) /* One SMB ioctl needs translations. */ #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 119f9d064cc6..339878952f12 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -218,32 +218,6 @@ COMPATIBLE_IOCTL(VT_RESIZE) COMPATIBLE_IOCTL(VT_RESIZEX) COMPATIBLE_IOCTL(VT_LOCKSWITCH) COMPATIBLE_IOCTL(VT_UNLOCKSWITCH) -/* Little v */ -/* Little v, the video4linux ioctls (conflict?) */ -COMPATIBLE_IOCTL(VIDIOCGCAP) -COMPATIBLE_IOCTL(VIDIOCGCHAN) -COMPATIBLE_IOCTL(VIDIOCSCHAN) -COMPATIBLE_IOCTL(VIDIOCGPICT) -COMPATIBLE_IOCTL(VIDIOCSPICT) -COMPATIBLE_IOCTL(VIDIOCCAPTURE) -COMPATIBLE_IOCTL(VIDIOCKEY) -COMPATIBLE_IOCTL(VIDIOCGAUDIO) -COMPATIBLE_IOCTL(VIDIOCSAUDIO) -COMPATIBLE_IOCTL(VIDIOCSYNC) -COMPATIBLE_IOCTL(VIDIOCMCAPTURE) -COMPATIBLE_IOCTL(VIDIOCGMBUF) -COMPATIBLE_IOCTL(VIDIOCGUNIT) -COMPATIBLE_IOCTL(VIDIOCGCAPTURE) -COMPATIBLE_IOCTL(VIDIOCSCAPTURE) -/* BTTV specific... */ -COMPATIBLE_IOCTL(_IOW('v', BASE_VIDIOCPRIVATE+0, char [256])) -COMPATIBLE_IOCTL(_IOR('v', BASE_VIDIOCPRIVATE+1, char [256])) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)) -COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */ -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int)) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int)) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)) /* Little p (/dev/rtc, /dev/envctrl, etc.) */ COMPATIBLE_IOCTL(RTC_AIE_ON) COMPATIBLE_IOCTL(RTC_AIE_OFF) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 1cded681eb6d..13f78ec4bf76 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1117,6 +1117,9 @@ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, unsigned int cmd, void *arg); int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, int cmd, void *arg, v4l2_kioctl driver_ioctl); +/* 32 Bits compatibility layer for 64 bits processors */ +extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd, + unsigned long arg); #endif /* __KERNEL__ */ #endif /* __LINUX_VIDEODEV2_H */ -- cgit v1.2.3 From 925e699f26d2162553f7453dcacbac32f063a4c7 Mon Sep 17 00:00:00 2001 From: Ricardo Cerqueira Date: Mon, 9 Jan 2006 15:24:57 -0200 Subject: V4L (957): Compat ioctl32 license fix - Compat_ioctl32 license fix Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 42dc11c63c0d..55c2fd3527fd 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -316,3 +316,5 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) } #endif EXPORT_SYMBOL_GPL(v4l_compat_ioctl32); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 17cbe2e5831c3df114c8d7b7d8bf07f2c35a6030 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:24:58 -0200 Subject: V4L (963): Explicit compat_ioctl32 handler to em28xx - Included explicit compat_ioctl32 handler. - removed extra line on cardlist. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 - drivers/media/video/em28xx/em28xx-video.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index efb708ec116a..53cd3e7e9e14 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -81,4 +81,3 @@ 80 -> ASUS Digimatrix TV [1043:0210] 81 -> Philips Tiger reference design [1131:2018] 82 -> MSI TV@Anywhere plus [1462:6231] - diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 3a56120397ae..8516ec12836e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1564,6 +1564,8 @@ static struct file_operations em28xx_v4l_fops = { .poll = em28xx_v4l2_poll, .mmap = em28xx_v4l2_mmap, .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, + }; /******************************** usb interface *****************************************/ -- cgit v1.2.3 From 133b735416fcd0f32a429e3f55072afe84c1f005 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Mon, 9 Jan 2006 15:24:58 -0200 Subject: V4L (0972): More build fixes for compat_ioctl32.c - More build fixes for compat_ioctl32.c Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 55c2fd3527fd..83cba5651f71 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -1,6 +1,7 @@ #include #include #include +#include #ifdef CONFIG_COMPAT struct video_tuner32 { @@ -274,7 +275,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOCGFBUF32: case VIDIOCSFBUF32: case VIDIOCGFREQ32: - case VIDIOCSFREQ32 + case VIDIOCSFREQ32: ret = do_video_ioctl(file, cmd, arg); break; -- cgit v1.2.3 From 97e2a01b6bd995bc3438b361e58b126a2c3cc0ca Mon Sep 17 00:00:00 2001 From: MishalÅ Pytasz Date: Mon, 9 Jan 2006 15:24:59 -0200 Subject: V4L (0973): Another build fix for compat_ioctl32.c - Another build fix for compat_ioctl32.c Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 83cba5651f71..99774c420689 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -309,6 +309,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) break; return ret; + } } #else long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) -- cgit v1.2.3 From e8efb71d02d008a665ba88e6f75af691d9425e49 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:24:59 -0200 Subject: V4L (0978): 64-bit fixes for removing warnings on compat_ioctl32 - 64-bit fixes for removing warnings on compat_ioctl32. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 4 ++-- drivers/media/video/em28xx/em28xx-core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 99774c420689..5472d36d73ff 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef CONFIG_COMPAT struct video_tuner32 { @@ -307,9 +308,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); break; - - return ret; } + return ret; } #else long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 0cfe75416ec6..6d32bd64ce55 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -126,7 +126,7 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count) const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */ void *buff = NULL; u32 i; - em28xx_coredbg("requested %i buffers with size %zd", count, imagesize); + em28xx_coredbg("requested %i buffers with size %zi", count, imagesize); if (count > EM28XX_NUM_FRAMES) count = EM28XX_NUM_FRAMES; -- cgit v1.2.3 From cf664a6458b254ce665d129c0960cff4f32b91f3 Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Mon, 9 Jan 2006 15:24:59 -0200 Subject: V4L/DVB (3120): Adds 32-bit compatibility for v4l2 framegrabber ioctls. - Adds 32-bit compatibility for v4l2 framegrabber ioctls. Signed-off-by: Philippe De Muyter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 388 +++++++++++++++++++++++++++++++++-- 1 file changed, 376 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 5472d36d73ff..4b14942dd91c 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -1,6 +1,21 @@ +/* + * ioctl32.c: Conversion between 32bit and 64bit native ioctls. + * Separated from fs stuff by Arnd Bergmann + * + * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs + * Copyright (C) 2003 Pavel Machek (pavel@suse.cz) + * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be) + * + * These routines maintain argument size conversion between 32bit and 64bit + * ioctls. + */ + #include #include #include +#include #include #include @@ -15,12 +30,9 @@ struct video_tuner32 { static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) { - int i; - if(get_user(kp->tuner, &up->tuner)) return -EFAULT; - for(i = 0; i < 32; i++) - __get_user(kp->name[i], &up->name[i]); + __copy_from_user(kp->name, up->name, 32); __get_user(kp->rangelow, &up->rangelow); __get_user(kp->rangehigh, &up->rangehigh); __get_user(kp->flags, &up->flags); @@ -31,12 +43,9 @@ static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up) { - int i; - if(put_user(kp->tuner, &up->tuner)) return -EFAULT; - for(i = 0; i < 32; i++) - __put_user(kp->name[i], &up->name[i]); + __copy_to_user(up->name, kp->name, 32); __put_user(kp->rangelow, &up->rangelow); __put_user(kp->rangehigh, &up->rangehigh); __put_user(kp->flags, &up->flags); @@ -123,6 +132,265 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u return 0; } +struct v4l2_clip32 +{ + struct v4l2_rect c; + compat_caddr_t next; +}; + +struct v4l2_window32 +{ + struct v4l2_rect w; + enum v4l2_field field; + __u32 chromakey; + compat_caddr_t clips; /* actually struct v4l2_clip32 * */ + __u32 clipcount; + compat_caddr_t bitmap; +}; + +static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +{ + if (copy_from_user(&kp->w, &up->w, sizeof(up->w))) + return -EFAULT; + __get_user(kp->field, &up->field); + __get_user(kp->chromakey, &up->chromakey); + __get_user(kp->clipcount, &up->clipcount); + if (kp->clipcount > 2048) + return -EINVAL; + if (kp->clipcount) { + struct v4l2_clip32 *uclips = compat_ptr(up->clips); + struct v4l2_clip *kclips; + int n = kp->clipcount; + + kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip)); + kp->clips = kclips; + while (--n >= 0) { + copy_from_user(&kclips->c, &uclips->c, sizeof(uclips->c)); + kclips->next = n ? kclips + 1 : 0; + uclips += 1; + kclips += 1; + } + } else + kp->clips = 0; + return 0; +} + +static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) +{ + if (copy_to_user(&up->w, &kp->w, sizeof(up->w))) + return -EFAULT; + __put_user(kp->field, &up->field); + __put_user(kp->chromakey, &up->chromakey); + __put_user(kp->clipcount, &up->clipcount); + return 0; +} + +static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +{ + return copy_from_user(kp, up, sizeof(struct v4l2_pix_format)); +} + +static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) +{ + return copy_to_user(up, kp, sizeof(struct v4l2_pix_format)); +} + +static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +{ + return copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)); +} + +static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) +{ + return copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)); +} + +struct v4l2_format32 +{ + enum v4l2_buf_type type; + union + { + struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE + struct v4l2_window32 win; // V4L2_BUF_TYPE_VIDEO_OVERLAY + struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE + __u8 raw_data[200]; // user-defined + } fmt; +}; + +static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +{ + if(get_user(kp->type, &up->type)) + return -EFAULT; + switch (kp->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); + case V4L2_BUF_TYPE_VBI_CAPTURE: + return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + default: + printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n", + kp->type); + return -ENXIO; + } +} + +static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) +{ + if(put_user(kp->type, &up->type)) + return -EFAULT; + switch (kp->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); + case V4L2_BUF_TYPE_VBI_CAPTURE: + return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi); + default: + return -ENXIO; + } +} + +struct v4l2_standard32 +{ + __u32 index; + __u32 id[2]; /* __u64 would get the alignment wrong */ + __u8 name[24]; + struct v4l2_fract frameperiod; /* Frames, not fields */ + __u32 framelines; + __u32 reserved[4]; +}; + +static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +{ + /* other fields are not set by the user, nor used by the driver */ + return get_user(kp->index, &up->index); +} + +static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up) +{ + if(put_user(kp->index, &up->index)) + return -EFAULT; + __copy_to_user(up->id, &kp->id, sizeof(__u64)); + __copy_to_user(up->name, kp->name, 24); + __put_user(kp->frameperiod, &up->frameperiod); + __put_user(kp->framelines, &up->framelines); + __copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)); + return 0; +} + +struct v4l2_buffer32 +{ + __u32 index; + enum v4l2_buf_type type; + __u32 bytesused; + __u32 flags; + enum v4l2_field field; + struct compat_timeval timestamp; + struct v4l2_timecode timecode; + __u32 sequence; + + /* memory location */ + enum v4l2_memory memory; + union { + __u32 offset; + compat_long_t userptr; + } m; + __u32 length; + __u32 input; + __u32 reserved; +}; + +static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +{ + + if (get_user(kp->index, &up->index)) + return -EFAULT; + __get_user(kp->type, &up->type); + __get_user(kp->flags, &up->flags); + __get_user(kp->memory, &up->memory); + __get_user(kp->input, &up->input); + switch(kp->memory) { + case V4L2_MEMORY_MMAP: + break; + case V4L2_MEMORY_USERPTR: + { + unsigned long tmp = (unsigned long)compat_ptr(up->m.userptr); + + __get_user(kp->length, &up->length); + __get_user(kp->m.userptr, &tmp); + } + break; + case V4L2_MEMORY_OVERLAY: + __get_user(kp->m.offset, &up->m.offset); + break; + } + return 0; +} + +static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) +{ + if (put_user(kp->index, &up->index)) + return -EFAULT; + __put_user(kp->type, &up->type); + __put_user(kp->flags, &up->flags); + __put_user(kp->memory, &up->memory); + __put_user(kp->input, &up->input); + switch(kp->memory) { + case V4L2_MEMORY_MMAP: + __put_user(kp->length, &up->length); + __put_user(kp->m.offset, &up->m.offset); + break; + case V4L2_MEMORY_USERPTR: + __put_user(kp->length, &up->length); + __put_user(kp->m.userptr, &up->m.userptr); + break; + case V4L2_MEMORY_OVERLAY: + __put_user(kp->m.offset, &up->m.offset); + break; + } + __put_user(kp->bytesused, &up->bytesused); + __put_user(kp->field, &up->field); + __put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec); + __put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec); + __copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)); + __put_user(kp->sequence, &up->sequence); + __put_user(kp->reserved, &up->reserved); + return 0; +} + +struct v4l2_framebuffer32 +{ + __u32 capability; + __u32 flags; + compat_caddr_t base; + struct v4l2_pix_format fmt; +}; + +static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +{ + u32 tmp = (u32)((unsigned long)kp->base); + + if(put_user(tmp, &up->base)) + return -EFAULT; + __put_user(kp->capability, &up->capability); + __put_user(kp->flags, &up->flags); + put_v4l2_pix_format(&kp->fmt, &up->fmt); + return 0; +} + +struct v4l2_input32 /* identical layout, but different size */ +{ + __u32 index; /* Which input */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of input */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 tuner; /* Associated tuner */ + __u32 std[2]; /* __u64 would get the padding wrong */ + __u32 status; + __u32 reserved[4]; +}; + #define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) #define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) #define VIDIOCGWIN32 _IOR('v',9, struct video_window32) @@ -132,6 +400,24 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u #define VIDIOCGFREQ32 _IOR('v',14, u32) #define VIDIOCSFREQ32 _IOW('v',15, u32) +#define VIDIOC_G_FMT32 _IOWR ('V', 4, struct v4l2_format32) +#define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32) +#define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32) +#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32) +/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */ +#define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t) +#define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32) +#define VIDIOC_DQBUF32 _IOWR ('V', 17, struct v4l2_buffer32) +#define VIDIOC_STREAMON32 _IOW ('V', 18, compat_int_t) +#define VIDIOC_STREAMOFF32 _IOW ('V', 19, compat_int_t) +#define VIDIOC_ENUMSTD32 _IOWR ('V', 25, struct v4l2_standard32) +#define VIDIOC_ENUMINPUT32 _IOWR ('V', 26, struct v4l2_input32) +/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */ +#define VIDIOC_S_CTRL32 _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_G_INPUT32 _IOR ('V', 38, compat_int_t) +#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t) +#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32) + enum { MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) }; @@ -198,10 +484,14 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg struct video_tuner vt; struct video_buffer vb; struct video_window vw; + struct v4l2_format v2f; + struct v4l2_buffer v2b; + struct v4l2_framebuffer v2fb; + struct v4l2_standard v2s; unsigned long vx; } karg; - mm_segment_t old_fs = get_fs(); void __user *up = compat_ptr(arg); + int compatible_arg = 1; int err = 0; /* First, convert the command. */ @@ -213,29 +503,82 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; + case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break; + case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break; + case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break; + case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break; + case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break; + case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break; + case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break; + case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break; + case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; + case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break; + case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break; + case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break; + case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; + case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; + case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break; }; switch(cmd) { case VIDIOCSTUNER: case VIDIOCGTUNER: err = get_video_tuner32(&karg.vt, up); + compatible_arg = 0; + break; case VIDIOCSFBUF: err = get_video_buffer32(&karg.vb, up); + compatible_arg = 0; break; case VIDIOCSFREQ: + case VIDIOC_S_INPUT: + case VIDIOC_OVERLAY: err = get_user(karg.vx, (u32 __user *)up); + compatible_arg = 0; break; }; + + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + err = get_v4l2_format32(&karg.v2f, up); + compatible_arg = 0; + break; + + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: + err = get_v4l2_buffer32(&karg.v2b, up); + compatible_arg = 0; + break; + + case VIDIOC_ENUMSTD: + err = get_v4l2_standard32(&karg.v2s, up); + compatible_arg = 0; + break; + + case VIDIOCGWIN: + case VIDIOCGFBUF: + case VIDIOCGFREQ: + case VIDIOC_G_FBUF: + case VIDIOC_G_INPUT: + compatible_arg = 0; + if(err) goto out; - set_fs(KERNEL_DS); - err = native_ioctl(file, cmd, (unsigned long)&karg); - set_fs(old_fs); + if(compatible_arg) + err = sys_ioctl(fd, cmd, (unsigned long)up); + else { + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&karg); + set_fs(old_fs); + } if(err == 0) { switch(cmd) { case VIDIOCGTUNER: @@ -250,7 +593,28 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg err = put_video_buffer32(&karg.vb, up); break; + case VIDIOC_G_FBUF: + err = put_v4l2_framebuffer32(&karg.v2fb, up); + break; + + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + err = put_v4l2_format32(&karg.v2f, up); + break; + + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: + err = put_v4l2_buffer32(&karg.v2b, up); + break; + + case VIDIOC_ENUMSTD: + err = put_v4l2_standard32(&karg.v2s, up); + break; + case VIDIOCGFREQ: + case VIDIOC_G_INPUT: err = put_user(((u32)karg.vx), (u32 __user *)up); break; }; -- cgit v1.2.3 From 13d133bc66ea78cf2d60c78a41082c87432e0e94 Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Mon, 9 Jan 2006 15:25:00 -0200 Subject: V4L/DVB (3152): Fixes some troubles at v4l2 compat stuff - This patch fixes merge and typo problems in v4l2/compat, and fixes VIDIOC_STREAMON, VIDIOC_STREAMOFF & VIDIOC_S_FBUF. Signed-off-by: Philippe De Muyter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 62 +++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 4b14942dd91c..27945e082195 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -106,11 +106,11 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; - if (file->f_ops->unlocked_ioctl) - ret = file->f_ops->unlocked_ioctl(file, cmd, arg); - else if (file->f_ops->ioctl) { + if (file->f_op->unlocked_ioctl) + ret = file->f_op->unlocked_ioctl(file, cmd, arg); + else if (file->f_op->ioctl) { lock_kernel(); - ret = file->f_ops->ioctl(file->f_dentry->d_inode, file, cmd, arg); + ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg); unlock_kernel(); } @@ -367,6 +367,19 @@ struct v4l2_framebuffer32 struct v4l2_pix_format fmt; }; +static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) +{ + u32 tmp; + + if (get_user(tmp, &up->base)) + return -EFAULT; + kp->base = compat_ptr(tmp); + __get_user(kp->capability, &up->capability); + __get_user(kp->flags, &up->flags); + get_v4l2_pix_format(&kp->fmt, &up->fmt); + return 0; +} + static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up) { u32 tmp = (u32)((unsigned long)kp->base); @@ -404,6 +417,7 @@ struct v4l2_input32 /* identical layout, but different size */ #define VIDIOC_S_FMT32 _IOWR ('V', 5, struct v4l2_format32) #define VIDIOC_QUERYBUF32 _IOWR ('V', 9, struct v4l2_buffer32) #define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32) +#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32) /* VIDIOC_OVERLAY is now _IOW, but was _IOWR */ #define VIDIOC_OVERLAY32 _IOWR ('V', 14, compat_int_t) #define VIDIOC_QBUF32 _IOWR ('V', 15, struct v4l2_buffer32) @@ -511,6 +525,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break; case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break; case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break; + case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break; case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break; case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break; @@ -536,10 +551,16 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOCSFREQ: case VIDIOC_S_INPUT: case VIDIOC_OVERLAY: + case VIDIOC_STREAMON: + case VIDIOC_STREAMOFF: err = get_user(karg.vx, (u32 __user *)up); compatible_arg = 0; break; - }; + + case VIDIOC_S_FBUF: + err = get_v4l2_framebuffer32(&karg.v2fb, up); + compatible_arg = 0; + break; case VIDIOC_G_FMT: case VIDIOC_S_FMT: @@ -566,17 +587,18 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg case VIDIOC_G_FBUF: case VIDIOC_G_INPUT: compatible_arg = 0; + }; if(err) goto out; if(compatible_arg) - err = sys_ioctl(fd, cmd, (unsigned long)up); + err = native_ioctl(file, cmd, (unsigned long)up); else { mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&karg); + err = native_ioctl(file, cmd, (unsigned long)&karg); set_fs(old_fs); } if(err == 0) { @@ -627,7 +649,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOIOCTLCMD; - if (!file->f_ops->ioctl) + if (!file->f_op->ioctl) return ret; switch (cmd) { @@ -641,6 +663,30 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOCSFBUF32: case VIDIOCGFREQ32: case VIDIOCSFREQ32: + case VIDIOC_QUERYCAP: + case VIDIOC_ENUM_FMT: + case VIDIOC_G_FMT32: + case VIDIOC_S_FMT32: + case VIDIOC_REQBUFS: + case VIDIOC_QUERYBUF32: + case VIDIOC_G_FBUF32: + case VIDIOC_S_FBUF32: + case VIDIOC_OVERLAY32: + case VIDIOC_QBUF32: + case VIDIOC_DQBUF32: + case VIDIOC_STREAMON32: + case VIDIOC_STREAMOFF32: + case VIDIOC_G_PARM: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_ENUMSTD32: + case VIDIOC_ENUMINPUT32: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL32: + case VIDIOC_QUERYCTRL: + case VIDIOC_G_INPUT32: + case VIDIOC_S_INPUT32: + case VIDIOC_TRY_FMT32: ret = do_video_ioctl(file, cmd, arg); break; -- cgit v1.2.3 From f3c5987a386300abea9854b32814d0eab7af7841 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:00 -0200 Subject: V4L (0987): Added Secam L' std on tda9887 and common macros moved to videodev2.h - Added SECAM L' video standard - Common std macros moved to videodev2.h Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda8290.c | 6 ------ drivers/media/video/tda9887.c | 9 +++++++++ include/linux/videodev2.h | 11 ++++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 61d94ddaff41..2498b76df429 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -398,14 +398,8 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) return 0; } - /*---------------------------------------------------------------------*/ -#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC) -#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B) -#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H) -#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK) - static void set_audio(struct tuner *t) { char* mode; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 7165a1b9625a..93bf10436b82 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -189,6 +189,15 @@ static struct tvnorm tvnorms[] = { .e = ( cGating_36 | cAudioIF_6_5 | cVideoIF_38_90 ), + },{ + .std = V4L2_STD_SECAM_LC, + .name = "SECAM-L'", + .b = ( cOutputPort2Inactive | + cPositiveAmTV | + cQSS ), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_33_90 ), },{ .std = V4L2_STD_SECAM_DK, .name = "SECAM-DK", diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 13f78ec4bf76..b2f5e864b397 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -642,6 +642,12 @@ typedef __u64 v4l2_std_id; #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) +/* some merged standards */ +#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC) +#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B) +#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H) +#define V4L2_STD_DK (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK) + /* some common needed stuff */ #define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ V4L2_STD_PAL_B1 |\ @@ -662,7 +668,8 @@ typedef __u64 v4l2_std_id; V4L2_STD_SECAM_G |\ V4L2_STD_SECAM_H |\ V4L2_STD_SECAM_DK |\ - V4L2_STD_SECAM_L) + V4L2_STD_SECAM_L |\ + V4L2_STD_SECAM_LC) #define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ V4L2_STD_PAL_60 |\ @@ -1117,10 +1124,12 @@ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, unsigned int cmd, void *arg); int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, int cmd, void *arg, v4l2_kioctl driver_ioctl); + /* 32 Bits compatibility layer for 64 bits processors */ extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg); + #endif /* __KERNEL__ */ #endif /* __LINUX_VIDEODEV2_H */ -- cgit v1.2.3 From f639c9b21b763441bd6bd76185be6d2504d83d54 Mon Sep 17 00:00:00 2001 From: Jörg Schummer Date: Mon, 9 Jan 2006 15:25:01 -0200 Subject: V4L (1019): Added basic support (tv + radio) for TerraTec Cinergy 250 PCI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added "TerraTec Cinergy 250 PCI" board (tv and radio). - svideo not tested - IR yet not working Signed-off-by: Jörg Schummer Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 34 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 36 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 53cd3e7e9e14..0fb6c4a29f5b 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -81,3 +81,4 @@ 80 -> ASUS Digimatrix TV [1043:0210] 81 -> Philips Tiger reference design [1131:2018] 82 -> MSI TV@Anywhere plus [1462:6231] + 83 -> Terratec Cinergy 250 PCI TV [153b:1160] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 672fb205959f..66ff6862468e 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2555,6 +2555,34 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_CINERGY250PCI] = { + /* remote-control does not work. The signal about a + key press comes in via gpio, but the key code + doesn't. Neither does it have an i2c remote control + interface. */ + .name = "Terratec Cinergy 250 PCI TV", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x80200000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_svideo, /* NOT tested */ + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x0200000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3001,6 +3029,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1462, .subdevice = 0x6231, .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x153b, + .subdevice = 0x1160, + .driver_data = SAA7134_BOARD_CINERGY250PCI, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index add49db1ad41..185115226b4b 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -209,6 +209,7 @@ struct saa7134_format { #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80 #define SAA7134_BOARD_PHILIPS_TIGER 81 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82 +#define SAA7134_BOARD_CINERGY250PCI 83 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From cd1257d860f6ee09b589723a5d3888b1fed46487 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:01 -0200 Subject: V4L (1023): Added Hauppauge ImpactVCB board - Modifications to bttv to support the Hauppauge ImpactVCB product (Model #64900). Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.bttv | 1 + drivers/media/video/bttv-cards.c | 34 +++++++++++++++++++++++++++++++++ drivers/media/video/bttv.h | 1 + 3 files changed, 36 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 330246ac80f8..74fb085e178b 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -141,3 +141,4 @@ 140 -> Osprey 440 [0070:ff07] 141 -> Asound Skyeye PCTV 142 -> Sabrent TV-FM (bttv version) +143 -> Hauppauge ImpactVCB (bt878) [0070:13eb] diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 012be639aa18..80bcbc4ea3a4 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -292,6 +292,9 @@ static struct CARD { /* likely broken, vendor id doesn't match the other magic views ... * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ + /* Duplicate PCI ID, reconfigure for this board during the eeprom read. + * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */ + /* DVB cards (using pci function .1 for mpeg data xfer) */ { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, @@ -2817,6 +2820,22 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .has_radio = 1, }, + /* ---- card 0x8f ---------------------------------- */ + [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = { + .name = "Hauppauge ImpactVCB (bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0x0f, /* old: 7 */ + .muxsel = { 0, 1, 3, 2}, /* Composite 0-3 */ + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -3471,6 +3490,21 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); btv->tuner_type = tv.tuner_type; btv->has_radio = tv.has_radio; + + printk("bttv%d: Hauppauge eeprom indicates model#%d\n", + btv->c.nr, tv.model); + + /* + * Some of the 878 boards have duplicate PCI IDs. Switch the board + * type based on model #. + */ + if(tv.model == 64900) { + printk("bttv%d: Switching board type from %s to %s\n", + btv->c.nr, + bttv_tvcards[btv->c.type].name, + bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); + btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB; + } } static int terratec_active_radio_upgrade(struct bttv *btv) diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index 93298f06e019..a5f172fe9f98 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -163,6 +163,7 @@ #define BTTV_BOARD_OSPREY440 0x8c #define BTTV_BOARD_ASOUND_SKYEYE 0x8d #define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f /* i2c address list */ #define I2C_TSA5522 0xc2 -- cgit v1.2.3 From 0fa14aa6214823bb013b598add866e277a7efe28 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:02 -0200 Subject: V4L (0979): Added V4L support for the Nova-S-Plus and Nova-SE2 DVB-S products - Added V4L support for the Nova-S-Plus and Nova-SE2 DVB-S products. - Basic DVB-S support is working, analog video inputs work. - It has one or two fixme comments, primarily analog GPIOs (audio) and eeprom parsing. - CX24123 code (in cx88-dvb.c) disabled until the - cx24123 module is added to dvb-kernel cvs. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 2 ++ drivers/media/video/cx88/Kconfig | 10 ++++++++ drivers/media/video/cx88/Makefile | 1 + drivers/media/video/cx88/cx88-cards.c | 41 +++++++++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-dvb.c | 25 ++++++++++++++++++++ drivers/media/video/cx88/cx88-mpeg.c | 5 ++++ drivers/media/video/cx88/cx88.h | 2 ++ 7 files changed, 86 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index a1017d1a85d4..ba269e6f3410 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -35,3 +35,5 @@ 34 -> ATI HDTV Wonder [1002:a101] 35 -> WinFast DTV1000-T [107d:665f] 36 -> AVerTV 303 (M126) [1461:000a] + 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9200] + 38 -> Hauppauge Nova-SE2 DVB-S [0070:9202] diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 85ba4106dc79..ec6201a32aca 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -38,6 +38,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS select DVB_CX22702 select DVB_LGDT330X select DVB_NXT200X + select DVB_CX24123 ---help--- This builds cx88-dvb with all currently supported frontend demodulators. If you wish to tweak your configuration, and @@ -89,3 +90,12 @@ config VIDEO_CX88_DVB_NXT200X ---help--- This adds ATSC 8VSB and QAM64/256 support for cards based on the Connexant 2388x chip and the NXT2002/NXT2004 demodulator. + +config VIDEO_CX88_DVB_CX24123 + bool "Conexant CX24123 DVB-S Support" + default y + depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS + select DVB_CX24123 + ---help--- + This adds DVB-S support for cards based on the + Connexant 2388x chip and the CX24123 demodulator. diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 54401b02b7ce..90a7ace55f64 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -16,5 +16,6 @@ extra-cflags-$(CONFIG_DVB_OR51132) += -DHAVE_OR51132=1 extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1 extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1 extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1 +extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1 EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 951709aa88ba..d738ea8c6f5e 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -897,6 +897,37 @@ struct cx88_board cx88_boards[] = { .gpio3 = 0x0000, }}, }, + [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = { + .name = "Hauppauge Nova-S-Plus DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + /* fixme: add the analog gpio stuff here */ + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + .dvb = 1, + }, + [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = { + .name = "Hauppauge Nova-SE2 DVB-S", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + }}, + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1044,6 +1075,14 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x1461, .subdevice = 0x000a, .card = CX88_BOARD_AVERTV_303, + },{ + .subvendor = 0x0070, + .subdevice = 0x9200, + .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, + },{ + .subvendor = 0x0070, + .subdevice = 0x9202, + .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1211,6 +1250,8 @@ void cx88_card_setup(struct cx88_core *core) if (0 == core->i2c_rc) leadtek_eeprom(core,eeprom); break; + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: case CX88_BOARD_HAUPPAUGE_DVB_T1: if (0 == core->i2c_rc) hauppauge_eeprom(core,eeprom); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 99ea955f5987..21972572a943 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -48,6 +48,9 @@ #ifdef HAVE_NXT200X # include "nxt200x.h" #endif +#ifdef HAVE_CX24123 +# include "cx24123.h" +#endif MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe "); @@ -314,6 +317,21 @@ static struct nxt200x_config ati_hdtvwonder = { }; #endif +#ifdef HAVE_CX24123 +static int cx24123_set_ts_param(struct dvb_frontend* fe, + int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + dev->ts_gen_cntrl = 0x2; + return 0; +} + +static struct cx24123_config hauppauge_novas_config = { + .demod_address = 0x55, + .set_ts_params = cx24123_set_ts_param, +}; +#endif + static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ @@ -420,6 +438,13 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder, &dev->core->i2c_adap); break; +#endif +#ifdef HAVE_CX24123 + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config, + &dev->core->i2c_adap); + break; #endif default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 35e6d0c2b872..c79cc1d2bf8b 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -78,6 +78,11 @@ static int cx8802_start_dma(struct cx8802_dev *dev, case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: cx_write(TS_SOP_STAT, 1<<13); break; + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ + udelay(100); + break; default: cx_write(TS_SOP_STAT, 0x00); break; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 77beafc5c327..2cf40afc0ace 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -179,6 +179,8 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_ATI_HDTVWONDER 34 #define CX88_BOARD_WINFAST_DTV1000 35 #define CX88_BOARD_AVERTV_303 36 +#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 +#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From fb56cb65e4b737c93727ea296050e8d24eb7cb42 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:02 -0200 Subject: V4L (0990): Enable IR support for the Nova-S-Plus - Enable IR support for the Nova-S-Plus. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 4 ++-- drivers/media/video/cx88/cx88-cards.c | 6 +++++- drivers/media/video/cx88/cx88-input.c | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index ba269e6f3410..739a343e5275 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -35,5 +35,5 @@ 34 -> ATI HDTV Wonder [1002:a101] 35 -> WinFast DTV1000-T [107d:665f] 36 -> AVerTV 303 (M126) [1461:000a] - 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9200] - 38 -> Hauppauge Nova-SE2 DVB-S [0070:9202] + 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202] + 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index d738ea8c6f5e..1976e04d8ace 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1078,11 +1078,15 @@ struct cx88_subid cx88_subids[] = { },{ .subvendor = 0x0070, .subdevice = 0x9200, + .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, + },{ + .subvendor = 0x0070, + .subdevice = 0x9201, .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, },{ .subvendor = 0x0070, .subdevice = 0x9202, - .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, + .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 461019dca901..d7e9813384d8 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -388,6 +388,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; @@ -567,6 +569,8 @@ void cx88_ir_irq(struct cx88_core *core) break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: + case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: + case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) -- cgit v1.2.3 From 0e0351e3709023dbd015d09880b04f0aa8818fcb Mon Sep 17 00:00:00 2001 From: Vadim Catana Date: Mon, 9 Jan 2006 15:25:02 -0200 Subject: V4L (1007): Add support for KWorld DVB-S 100 - Add support for KWorld DVB-S 100, based on the same chips as Hauppauge Nova-S Plus (CX23883/CX24123/CX24109), without the Intersil ISL6421, which is used for LNB control. - LNB voltage and tone are controled by LNBDC and LNBTone bits from register 0x29 of the CX24123 demodulator. - The MO_GP0_IO register from CX23883 is used to turn LNB power on and off. Signed-off-by: Vadim Catana Acked-by: Johannes Stezenbach Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 1 + drivers/media/video/cx88/cx88-cards.c | 26 ++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-dvb.c | 27 +++++++++++++++++++++++++-- drivers/media/video/cx88/cx88.h | 1 + 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 739a343e5275..13ec5e965f41 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -37,3 +37,4 @@ 36 -> AVerTV 303 (M126) [1461:000a] 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202] 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200] + 39 -> KWorld DVB-S 100 [17de:08b2] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 1976e04d8ace..fd173e6ac605 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -928,6 +928,24 @@ struct cx88_board cx88_boards[] = { }}, .dvb = 1, }, + [CX88_BOARD_KWORLD_DVBS_100] = { + .name = "KWorld DVB-S 100", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1087,6 +1105,10 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x9202, .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, + },{ + .subvendor = 0x17de, + .subdevice = 0x08b2, + .card = CX88_BOARD_KWORLD_DVBS_100, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1260,6 +1282,10 @@ void cx88_card_setup(struct cx88_core *core) if (0 == core->i2c_rc) hauppauge_eeprom(core,eeprom); break; + case CX88_BOARD_KWORLD_DVBS_100: + cx_write(MO_GP0_IO, 0x000007f8); + cx_write(MO_GP1_IO, 0x00000001); + break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: /* GPIO0:0 is hooked to mt352 reset pin */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 21972572a943..054094e48fc3 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -326,9 +326,28 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe, return 0; } +static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; + + if (on) + cx_write(MO_GP0_IO, 0x000006f9); + else + cx_write(MO_GP0_IO, 0x000006fB); +} + static struct cx24123_config hauppauge_novas_config = { - .demod_address = 0x55, - .set_ts_params = cx24123_set_ts_param, + .demod_address = 0x55, + .use_isl6421 = 1, + .set_ts_params = cx24123_set_ts_param, +}; + +static struct cx24123_config kworld_dvbs_100_config = { + .demod_address = 0x15, + .use_isl6421 = 0, + .set_ts_params = cx24123_set_ts_param, + .enable_lnb_voltage = cx24123_enable_lnb_voltage, }; #endif @@ -445,6 +464,10 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config, &dev->core->i2c_adap); break; + case CX88_BOARD_KWORLD_DVBS_100: + dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config, + &dev->core->i2c_adap); + break; #endif default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 2cf40afc0ace..11dc0335151c 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -181,6 +181,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_AVERTV_303 36 #define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 #define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 +#define CX88_BOARD_KWORLD_DVBS_100 39 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From 1faf11a3ed19d7d404fa867f572a1f23def9882e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:03 -0200 Subject: V4L (0988): Tuner cleanups by removing Video IF from tuners struct - Video IF was removed from tuners struct. - Each Video standard have its own Video IF frequency, so it is related to video standard. Of course tuner also needs saw filters for IF, but this way, similar tuners can be grouped into just one entry, if they have the same cut-off freqs and the same switch config and global config. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 306 +++++++++++++++++++------------------ 1 file changed, 161 insertions(+), 145 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index e0c9fdb9914a..feaed92e2a69 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -80,8 +80,6 @@ struct tunertype { char *name; - unsigned char Vendor; - unsigned char Type; unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ unsigned short thresh2; /* band switch VHF_HI <=> UHF */ @@ -89,10 +87,6 @@ struct tunertype unsigned char VHF_H; unsigned char UHF; unsigned char config; - unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, - 732 =16*45.75 NTSCi, - 940 =16*58.75 NTSC-Japan - 704 =16*44 ATSC */ }; /* @@ -102,158 +96,158 @@ struct tunertype */ static struct tunertype tuners[] = { /* 0-9 */ - { "Temic PAL (4002 FH5)", TEMIC, PAL, - 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, - { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, - 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, - { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, - 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, - { "NoTuner", NoTuner, NOTUNER, - 0,0,0x00,0x00,0x00,0x00,0x00}, - { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, - { "Temic NTSC (4032 FY5)", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, - { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, - 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, - { "Temic NTSC (4036 FY5)", TEMIC, NTSC, - 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, - { "Alps HSBH1", TEMIC, NTSC, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Temic PAL (4002 FH5)", /* TEMIC PAL */ + 16*140.25, 16*463.25, 0x02, 0x04, 0x01, 0x8e}, + { "Philips PAL_I (FI1246 and compatibles)", /* Philips PAL_I */ + 16*140.25, 16*463.25, 0xa0, 0x90, 0x30, 0x8e}, + { "Philips NTSC (FI1236,FM1236 and compatibles)", /* Philips NTSC */ + 16*157.25, 16*451.25, 0xA0, 0x90, 0x30, 0x8e}, + { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",/* Philips SECAM */ + 16*168.25, 16*447.25, 0xA7, 0x97, 0x37, 0x8e}, + { "NoTuner", /* NoTuner NOTUNER */ + 0, 0, 0x00, 0x00, 0x00, 0x00}, + { "Philips PAL_BG (FI1216 and compatibles)", /* Philips PAL */ + 16*168.25, 16*447.25, 0xA0, 0x90, 0x30, 0x8e}, + { "Temic NTSC (4032 FY5)", /* TEMIC NTSC */ + 16*157.25, 16*463.25, 0x02, 0x04, 0x01, 0x8e}, + { "Temic PAL_I (4062 FY5)", /* TEMIC PAL_I */ + 16*170.00, 16*450.00, 0x02, 0x04, 0x01, 0x8e}, + { "Temic NTSC (4036 FY5)", /* TEMIC NTSC */ + 16*157.25, 16*463.25, 0xa0, 0x90, 0x30, 0x8e}, + { "Alps HSBH1", /* TEMIC NTSC */ + 16*137.25, 16*385.25, 0x01, 0x02, 0x08, 0x8e}, /* 10-19 */ - { "Alps TSBE1", TEMIC, PAL, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, - { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, - { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, - { "Temic PAL_BG (4006FH5)", TEMIC, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Alps TSCH6", Alps, NTSC, - 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, - { "Temic PAL_DK (4016 FY5)", TEMIC, PAL, - 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC_M (MK2)", Philips, NTSC, - 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, - { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, - 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, - 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, + { "Alps TSBE1", /* TEMIC PAL */ + 16*137.25, 16*385.25, 0x01, 0x02, 0x08, 0x8e}, + { "Alps TSBB5", /* Alps PAL_I */ + 16*133.25, 16*351.25, 0x01, 0x02, 0x08, 0x8e}, + { "Alps TSBE5", /* Alps PAL */ + 16*133.25, 16*351.25, 0x01, 0x02, 0x08, 0x8e}, + { "Alps TSBC5", /* Alps PAL */ + 16*133.25, 16*351.25, 0x01, 0x02, 0x08, 0x8e}, + { "Temic PAL_BG (4006FH5)", /* TEMIC PAL */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Alps TSCH6", /* Alps NTSC */ + 16*137.25, 16*385.25, 0x14, 0x12, 0x11, 0x8e}, + { "Temic PAL_DK (4016 FY5)", /* TEMIC PAL */ + 16*168.25, 16*456.25, 0xa0, 0x90, 0x30, 0x8e}, + { "Philips NTSC_M (MK2)", /* Philips NTSC */ + 16*160.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Temic PAL_I (4066 FY5)", /* TEMIC PAL_I */ + 16*169.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Temic PAL* auto (4006 FN5)", /* TEMIC PAL */ + 16*169.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, /* 20-29 */ - { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, - 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic NTSC (4039 FR5)", TEMIC, NTSC, - 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, - { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL, - 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, - 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, - { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, - 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", /* TEMIC PAL */ + 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Temic NTSC (4039 FR5)", /* TEMIC NTSC */ + 16*158.00, 16*453.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Temic PAL/SECAM multi (4046 FM5)", /* TEMIC PAL */ + 16*169.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Philips PAL_DK (FI1256 and compatibles)", /* Philips PAL */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Philips PAL/SECAM multi (FQ1216ME)", /* Philips PAL */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + { "LG PAL_I+FM (TAPC-I001D)", /* LGINNOTEK PAL_I */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + { "LG PAL_I (TAPC-I701D)", /* LGINNOTEK PAL_I */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + { "LG NTSC+FM (TPI8NSR01F)", /* LGINNOTEK NTSC */ + 16*210.00, 16*497.00, 0xa0, 0x90, 0x30, 0x8e}, + { "LG PAL_BG+FM (TPI8PSB01D)", /* LGINNOTEK PAL */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + { "LG PAL_BG (TPI8PSB11D)", /* LGINNOTEK PAL */ + 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, /* 30-39 */ - { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, - 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, - { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ - 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, - { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ - 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, - { "MT20xx universal", Microtune, PAL|NTSC, + { "Temic PAL* auto + FM (4009 FN5)", /* TEMIC PAL */ + 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, + { "SHARP NTSC_JP (2U5JF5540)", /* SHARP NTSC */ + 16*137.25, 16*317.25, 0x01, 0x02, 0x08, 0x8e}, + { "Samsung PAL TCPM9091PD27", /* Samsung PAL */ + 16*169, 16*464, 0xA0, 0x90, 0x30, 0x8e}, + { "MT20xx universal", /* Microtune PAL|NTSC */ /* see mt20xx.c for details */ }, - { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, - 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, - { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, - 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, - { "Temic NTSC (4136 FY5)", TEMIC, NTSC, - 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, - { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623}, - { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL, - 16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, - { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, + { "Temic PAL_BG (4106 FH5)", /* TEMIC PAL */ + 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Temic PAL_DK/SECAM_L (4012 FY5)", /* TEMIC PAL */ + 16*140.25, 16*463.25, 0x02, 0x04, 0x01, 0x8e}, + { "Temic NTSC (4136 FY5)", /* TEMIC NTSC */ + 16*158.00, 16*453.00, 0xa0, 0x90, 0x30, 0x8e}, + { "LG PAL (newer TAPC series)", /* LGINNOTEK PAL */ + 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0x8e}, + { "Philips PAL/SECAM multi (FM1216ME MK3)", /* Philips PAL */ + 16*158.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, + { "LG NTSC (newer TAPC series)", /* LGINNOTEK NTSC */ + 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0x8e}, /* 40-49 */ - { "HITACHI V7-J180AT", HITACHI, NTSC, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, - { "Philips PAL_MK (FI1216 MK)", Philips, PAL, - 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, - { "Philips 1236D ATSC/NTSC daul in", Philips, ATSC, - 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, - { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Microtune 4049 FM5", Microtune, PAL, - 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, - { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, - 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, - { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - { "Tenna TNF 8831 BGFF)", Philips, PAL, - 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, - { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC, - 16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732}, + { "HITACHI V7-J180AT", /* HITACHI NTSC */ + 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0x8e}, + { "Philips PAL_MK (FI1216 MK)", /* Philips PAL */ + 16*140.25, 16*463.25, 0x01, 0xc2, 0xcf, 0x8e}, + { "Philips 1236D ATSC/NTSC daul in", /* Philips ATSC */ + 16*157.25, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", /* Philips NTSC */ + 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, + { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", /* Philips NTSC */ + 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, + { "Microtune 4049 FM5", /* Microtune PAL */ + 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Panasonic VP27s/ENGE4324D", /* Panasonic NTSC */ + 16*160.00, 16*454.00, 0x01, 0x02, 0x08, 0xce}, + { "LG NTSC (TAPE series)", /* LGINNOTEK NTSC */ + 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, + { "Tenna TNF 8831 BGFF)", /* Philips PAL */ + 16*161.25, 16*463.25, 0xa0, 0x90, 0x30, 0x8e}, + { "Microtune 4042 FI5 ATSC/NTSC dual in", /* Microtune NTSC */ + 16*162.00, 16*457.00, 0xa2, 0x94, 0x31, 0x8e}, /* 50-59 */ - { "TCL 2002N", TCL, NTSC, - 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732}, - { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, - { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC, - 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - { "Philips FQ1286", Philips, NTSC, - 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */ - { "tda8290+75", Philips, PAL|NTSC, + { "TCL 2002N", /* TCL NTSC */ + 16*172.00, 16*448.00, 0x01, 0x02, 0x08, 0x8e}, + { "Philips PAL/SECAM_D (FM 1256 I-H3)", /* Philips PAL */ + 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, + { "Thomson DDT 7610 (ATSC/NTSC)", /* THOMSON ATSC */ + 16*157.25, 16*454.00, 0x39, 0x3a, 0x3c, 0x8e}, + { "Philips FQ1286", /* Philips NTSC */ + 16*160.00, 16*454.00, 0x41, 0x42, 0x04, 0x8e}, + { "tda8290+75", /* Philips PAL|NTSC */ /* see tda8290.c for details */ }, - { "TCL 2002MB", TCL, PAL, - 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623}, - { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, - 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, - { "Philips FQ1236A MK4", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - { "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC, - 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, - { "Ymec TVision TVF-5533MF", Philips, NTSC, - 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, + { "TCL 2002MB", /* TCL PAL */ + 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0xce}, + { "Philips PAL/SECAM multi (FQ1216AME MK4)", /* Philips PAL */ + 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0xce}, + { "Philips FQ1236A MK4", /* Philips NTSC */ + 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, + { "Ymec TVision TVF-8531MF/8831MF/8731MF", /* Philips NTSC */ + 16*160.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, + { "Ymec TVision TVF-5533MF", /* Philips NTSC */ + 16*160.00, 16*454.00, 0x01, 0x02, 0x04, 0x8e}, /* 60-69 */ - { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, - 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, - 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623}, - { "Philips TEA5767HN FM Radio", Philips, RADIO, + { "Thomson DDT 7611 (ATSC/NTSC)", /* THOMSON ATSC */ + 16*157.25, 16*454.00, 0x39, 0x3a, 0x3c, 0x8e}, + { "Tena TNF9533-D/IF/TNF9533-B/DF", /* Philips PAL */ + 16*160.25, 16*464.25, 0x01, 0x02, 0x04, 0x8e}, + { "Philips TEA5767HN FM Radio", /* Philips RADIO */ /* see tea5767.c for details */}, - { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, - 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, - { "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC, - 16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732}, - { "Ymec TVF66T5-B/DFF", Philips, PAL, - 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623}, - { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC, - 16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 }, - { "Philips TD1316 Hybrid Tuner", Philips, PAL, - 16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 }, - { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC, - 16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 }, - { "Tena TNF 5335 MF", Philips, NTSC, - 16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 }, + { "Philips FMD1216ME MK3 Hybrid Tuner", /* Philips PAL */ + 16*160.00, 16*442.00, 0x51, 0x52, 0x54, 0x86}, + { "LG TDVS-H062F/TUA6034", /* LGINNOTEK ATSC */ + 16*160.00, 16*455.00, 0x01, 0x02, 0x04, 0x8e}, + { "Ymec TVF66T5-B/DFF", /* Philips PAL */ + 16*160.25, 16*464.25, 0x01, 0x02, 0x08, 0x8e}, + { "LG NTSC (TALN mini series)", /* LGINNOTEK NTSC */ + 16*137.25, 16*373.25, 0x01, 0x02, 0x08, 0x8e}, + { "Philips TD1316 Hybrid Tuner", /* Philips PAL */ + 16*160.00, 16*442.00, 0xa1, 0xa2, 0xa4, 0xc8}, + { "Philips TUV1236D ATSC/NTSC dual in", /* Philips ATSC */ + 16*157.25, 16*454.00, 0x01, 0x02, 0x04, 0xce}, + { "Tena TNF 5335 MF", /* Philips NTSC */ + 16*157.25, 16*454.00, 0x01, 0x02, 0x04, 0x8e}, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); @@ -305,7 +299,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) u16 div; struct tunertype *tun; unsigned char buffer[4]; - int rc; + int rc, IFPCoff; tun = &tuners[t->type]; if (freq < tun->thresh1) { @@ -420,7 +414,29 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) * frequency in case (wanted frequency < current frequency). */ - div=freq + tun->IFPCoff; + /* IFPCoff = Video Intermediate Frequency - Vif: + 940 =16*58.75 NTSC/J (Japan) + 732 =16*45.75 M/N STD + 704 =16*44 ATSC (at DVB code) + 632 =16*39.50 I U.K. + 622.4=16*38.90 B/G D/K I, L STD + 592 =16*37.00 D China + 590 =16.36.875 B Australia + 543.2=16*33.95 L' STD + 171.2=16*10.70 FM Radio (at set_radio_freq) + */ + + if (t->std & V4L2_STD_NTSC_M_JP) { + IFPCoff = 940; + } else if (t->std & V4L2_STD_MN) { + IFPCoff = 732; + } else if (t->std & V4L2_STD_SECAM_LC) { + IFPCoff = 543; + } else { + IFPCoff = 623; + } + + div=freq + IFPCoff; if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { buffer[0] = tun->config; buffer[1] = config; -- cgit v1.2.3 From e142e5107f1e4103dad16e391a41166e15b66a9c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:03 -0200 Subject: V4L (1021): Tuner description now follows the same CodingStyle as the others - Tuner description now follows the same CodingStyle as the others Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 746 ++++++++++++++++++++++++++++++------- include/media/tuner.h | 22 -- 2 files changed, 609 insertions(+), 159 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index feaed92e2a69..cf241ab1e1b0 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -96,158 +96,630 @@ struct tunertype */ static struct tunertype tuners[] = { /* 0-9 */ - { "Temic PAL (4002 FH5)", /* TEMIC PAL */ - 16*140.25, 16*463.25, 0x02, 0x04, 0x01, 0x8e}, - { "Philips PAL_I (FI1246 and compatibles)", /* Philips PAL_I */ - 16*140.25, 16*463.25, 0xa0, 0x90, 0x30, 0x8e}, - { "Philips NTSC (FI1236,FM1236 and compatibles)", /* Philips NTSC */ - 16*157.25, 16*451.25, 0xA0, 0x90, 0x30, 0x8e}, - { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",/* Philips SECAM */ - 16*168.25, 16*447.25, 0xA7, 0x97, 0x37, 0x8e}, - { "NoTuner", /* NoTuner NOTUNER */ - 0, 0, 0x00, 0x00, 0x00, 0x00}, - { "Philips PAL_BG (FI1216 and compatibles)", /* Philips PAL */ - 16*168.25, 16*447.25, 0xA0, 0x90, 0x30, 0x8e}, - { "Temic NTSC (4032 FY5)", /* TEMIC NTSC */ - 16*157.25, 16*463.25, 0x02, 0x04, 0x01, 0x8e}, - { "Temic PAL_I (4062 FY5)", /* TEMIC PAL_I */ - 16*170.00, 16*450.00, 0x02, 0x04, 0x01, 0x8e}, - { "Temic NTSC (4036 FY5)", /* TEMIC NTSC */ - 16*157.25, 16*463.25, 0xa0, 0x90, 0x30, 0x8e}, - { "Alps HSBH1", /* TEMIC NTSC */ - 16*137.25, 16*385.25, 0x01, 0x02, 0x08, 0x8e}, + [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL (4002 FH5)", + .thresh1= 16 * 140.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0x02, + .VHF_H = 0x04, + .UHF = 0x01, + .config = 0x8e, + }, + [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ + .name = "Philips PAL_I (FI1246 and compatibles)", + .thresh1= 16 * 140.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ + .name = "Philips NTSC (FI1236,FM1236 and compatibles)", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 451.25 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ + .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", + .thresh1= 16 * 168.25 /*MHz*/, + .thresh2= 16 * 447.25 /*MHz*/, + .VHF_L = 0xa7, + .VHF_H = 0x97, + .UHF = 0x37, + .config = 0x8e, + }, + [TUNER_ABSENT] = { /* Tuner Absent */ + .name = "NoTuner", + .thresh1= 0 /*MHz*/, + .thresh2= 0 /*MHz*/, + .VHF_L = 0x00, + .VHF_H = 0x00, + .UHF = 0x00, + .config = 0x00, + }, + [TUNER_PHILIPS_PAL] = { /* Philips PAL */ + .name = "Philips PAL_BG (FI1216 and compatibles)", + .thresh1= 16 * 168.25 /*MHz*/, + .thresh2= 16 * 447.25 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4032 FY5)", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0x02, + .VHF_H = 0x04, + .UHF = 0x01, + .config = 0x8e, + }, + [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ + .name = "Temic PAL_I (4062 FY5)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0x02, + .VHF_H = 0x04, + .UHF = 0x01, + .config = 0x8e, + }, + [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4036 FY5)", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ + .name = "Alps HSBH1", + .thresh1= 16 * 137.25 /*MHz*/, + .thresh2= 16 * 385.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, /* 10-19 */ - { "Alps TSBE1", /* TEMIC PAL */ - 16*137.25, 16*385.25, 0x01, 0x02, 0x08, 0x8e}, - { "Alps TSBB5", /* Alps PAL_I */ - 16*133.25, 16*351.25, 0x01, 0x02, 0x08, 0x8e}, - { "Alps TSBE5", /* Alps PAL */ - 16*133.25, 16*351.25, 0x01, 0x02, 0x08, 0x8e}, - { "Alps TSBC5", /* Alps PAL */ - 16*133.25, 16*351.25, 0x01, 0x02, 0x08, 0x8e}, - { "Temic PAL_BG (4006FH5)", /* TEMIC PAL */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Alps TSCH6", /* Alps NTSC */ - 16*137.25, 16*385.25, 0x14, 0x12, 0x11, 0x8e}, - { "Temic PAL_DK (4016 FY5)", /* TEMIC PAL */ - 16*168.25, 16*456.25, 0xa0, 0x90, 0x30, 0x8e}, - { "Philips NTSC_M (MK2)", /* Philips NTSC */ - 16*160.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Temic PAL_I (4066 FY5)", /* TEMIC PAL_I */ - 16*169.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Temic PAL* auto (4006 FN5)", /* TEMIC PAL */ - 16*169.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, + [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ + .name = "Alps TSBE1", + .thresh1= 16 * 137.25 /*MHz*/, + .thresh2= 16 * 385.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ + .name = "Alps TSBB5", + .thresh1= 16 * 133.25 /*MHz*/, + .thresh2= 16 * 351.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ + .name = "Alps TSBE5", + .thresh1= 16 * 133.25 /*MHz*/, + .thresh2= 16 * 351.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ + .name = "Alps TSBC5", + .thresh1= 16 * 133.25 /*MHz*/, + .thresh2= 16 * 351.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4006FH5)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ + .name = "Alps TSCH6", + .thresh1= 16 * 137.25 /*MHz*/, + .thresh2= 16 * 385.25 /*MHz*/, + .VHF_L = 0x14, + .VHF_H = 0x12, + .UHF = 0x11, + .config = 0x8e, + }, + [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ + .name = "Temic PAL_DK (4016 FY5)", + .thresh1= 16 * 168.25 /*MHz*/, + .thresh2= 16 * 456.25 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ + .name = "Philips NTSC_M (MK2)", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ + .name = "Temic PAL_I (4066 FY5)", + .thresh1= 16 * 169.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL* auto (4006 FN5)", + .thresh1= 16 * 169.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, /* 20-29 */ - { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", /* TEMIC PAL */ - 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Temic NTSC (4039 FR5)", /* TEMIC NTSC */ - 16*158.00, 16*453.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Temic PAL/SECAM multi (4046 FM5)", /* TEMIC PAL */ - 16*169.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Philips PAL_DK (FI1256 and compatibles)", /* Philips PAL */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Philips PAL/SECAM multi (FQ1216ME)", /* Philips PAL */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, - { "LG PAL_I+FM (TAPC-I001D)", /* LGINNOTEK PAL_I */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, - { "LG PAL_I (TAPC-I701D)", /* LGINNOTEK PAL_I */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, - { "LG NTSC+FM (TPI8NSR01F)", /* LGINNOTEK NTSC */ - 16*210.00, 16*497.00, 0xa0, 0x90, 0x30, 0x8e}, - { "LG PAL_BG+FM (TPI8PSB01D)", /* LGINNOTEK PAL */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, - { "LG PAL_BG (TPI8PSB11D)", /* LGINNOTEK PAL */ - 16*170.00, 16*450.00, 0xa0, 0x90, 0x30, 0x8e}, + [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", + .thresh1= 16 * 141.00 /*MHz*/, + .thresh2= 16 * 464.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4039 FR5)", + .thresh1= 16 * 158.00 /*MHz*/, + .thresh2= 16 * 453.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ + .name = "Temic PAL/SECAM multi (4046 FM5)", + .thresh1= 16 * 169.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ + .name = "Philips PAL_DK (FI1256 and compatibles)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FQ1216ME)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ + .name = "LG PAL_I+FM (TAPC-I001D)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ + .name = "LG PAL_I (TAPC-I701D)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC+FM (TPI8NSR01F)", + .thresh1= 16 * 210.00 /*MHz*/, + .thresh2= 16 * 497.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ + .name = "LG PAL_BG+FM (TPI8PSB01D)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ + .name = "LG PAL_BG (TPI8PSB11D)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, /* 30-39 */ - { "Temic PAL* auto + FM (4009 FN5)", /* TEMIC PAL */ - 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, - { "SHARP NTSC_JP (2U5JF5540)", /* SHARP NTSC */ - 16*137.25, 16*317.25, 0x01, 0x02, 0x08, 0x8e}, - { "Samsung PAL TCPM9091PD27", /* Samsung PAL */ - 16*169, 16*464, 0xA0, 0x90, 0x30, 0x8e}, - { "MT20xx universal", /* Microtune PAL|NTSC */ + [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ + .name = "Temic PAL* auto + FM (4009 FN5)", + .thresh1= 16 * 141.00 /*MHz*/, + .thresh2= 16 * 464.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ + .name = "SHARP NTSC_JP (2U5JF5540)", + .thresh1= 16 * 137.25 /*MHz*/, + .thresh2= 16 * 317.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ + .name = "Samsung PAL TCPM9091PD27", + .thresh1= 16 * 169 /*MHz*/, + .thresh2= 16 * 464 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_MT2032] = { /* Microtune PAL|NTSC */ + .name = "MT20xx universal", /* see mt20xx.c for details */ }, - { "Temic PAL_BG (4106 FH5)", /* TEMIC PAL */ - 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Temic PAL_DK/SECAM_L (4012 FY5)", /* TEMIC PAL */ - 16*140.25, 16*463.25, 0x02, 0x04, 0x01, 0x8e}, - { "Temic NTSC (4136 FY5)", /* TEMIC NTSC */ - 16*158.00, 16*453.00, 0xa0, 0x90, 0x30, 0x8e}, - { "LG PAL (newer TAPC series)", /* LGINNOTEK PAL */ - 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0x8e}, - { "Philips PAL/SECAM multi (FM1216ME MK3)", /* Philips PAL */ - 16*158.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, - { "LG NTSC (newer TAPC series)", /* LGINNOTEK NTSC */ - 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0x8e}, + [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ + .name = "Temic PAL_BG (4106 FH5)", + .thresh1= 16 * 141.00 /*MHz*/, + .thresh2= 16 * 464.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ + .name = "Temic PAL_DK/SECAM_L (4012 FY5)", + .thresh1= 16 * 140.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0x02, + .VHF_H = 0x04, + .UHF = 0x01, + .config = 0x8e, + }, + [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ + .name = "Temic NTSC (4136 FY5)", + .thresh1= 16 * 158.00 /*MHz*/, + .thresh2= 16 * 453.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ + .name = "LG PAL (newer TAPC series)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216ME MK3)", + .thresh1= 16 * 158.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (newer TAPC series)", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, /* 40-49 */ - { "HITACHI V7-J180AT", /* HITACHI NTSC */ - 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0x8e}, - { "Philips PAL_MK (FI1216 MK)", /* Philips PAL */ - 16*140.25, 16*463.25, 0x01, 0xc2, 0xcf, 0x8e}, - { "Philips 1236D ATSC/NTSC daul in", /* Philips ATSC */ - 16*157.25, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", /* Philips NTSC */ - 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, - { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", /* Philips NTSC */ - 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, - { "Microtune 4049 FM5", /* Microtune PAL */ - 16*141.00, 16*464.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Panasonic VP27s/ENGE4324D", /* Panasonic NTSC */ - 16*160.00, 16*454.00, 0x01, 0x02, 0x08, 0xce}, - { "LG NTSC (TAPE series)", /* LGINNOTEK NTSC */ - 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, - { "Tenna TNF 8831 BGFF)", /* Philips PAL */ - 16*161.25, 16*463.25, 0xa0, 0x90, 0x30, 0x8e}, - { "Microtune 4042 FI5 ATSC/NTSC dual in", /* Microtune NTSC */ - 16*162.00, 16*457.00, 0xa2, 0x94, 0x31, 0x8e}, + [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ + .name = "HITACHI V7-J180AT", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ + .name = "Philips PAL_MK (FI1216 MK)", + .thresh1= 16 * 140.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0xc2, + .UHF = 0xcf, + .config = 0x8e, + }, + [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */ + .name = "Philips 1236D ATSC/NTSC daul in", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ + .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ + .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ + .name = "Microtune 4049 FM5", + .thresh1= 16 * 141.00 /*MHz*/, + .thresh2= 16 * 464.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_MICROTUNE_4042_FI5] = { /* Panasonic NTSC */ + .name = "Panasonic VP27s/ENGE4324D", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0xce, + }, + [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (TAPE series)", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_TNF_8831BGFF] = { /* Philips PAL */ + .name = "Tenna TNF 8831 BGFF)", + .thresh1= 16 * 161.25 /*MHz*/, + .thresh2= 16 * 463.25 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ + .name = "Microtune 4042 FI5 ATSC/NTSC dual in", + .thresh1= 16 * 162.00 /*MHz*/, + .thresh2= 16 * 457.00 /*MHz*/, + .VHF_L = 0xa2, + .VHF_H = 0x94, + .UHF = 0x31, + .config = 0x8e, + }, /* 50-59 */ - { "TCL 2002N", /* TCL NTSC */ - 16*172.00, 16*448.00, 0x01, 0x02, 0x08, 0x8e}, - { "Philips PAL/SECAM_D (FM 1256 I-H3)", /* Philips PAL */ - 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, - { "Thomson DDT 7610 (ATSC/NTSC)", /* THOMSON ATSC */ - 16*157.25, 16*454.00, 0x39, 0x3a, 0x3c, 0x8e}, - { "Philips FQ1286", /* Philips NTSC */ - 16*160.00, 16*454.00, 0x41, 0x42, 0x04, 0x8e}, - { "tda8290+75", /* Philips PAL|NTSC */ + [TUNER_TCL_2002N] = { /* TCL NTSC */ + .name = "TCL 2002N", + .thresh1= 16 * 172.00 /*MHz*/, + .thresh2= 16 * 448.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ + .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ + .name = "Thomson DDT 7610 (ATSC/NTSC)", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x39, + .VHF_H = 0x3a, + .UHF = 0x3c, + .config = 0x8e, + }, + [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ + .name = "Philips FQ1286", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x41, + .VHF_H = 0x42, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ + .name = "tda8290+75", /* see tda8290.c for details */ }, - { "TCL 2002MB", /* TCL PAL */ - 16*170.00, 16*450.00, 0x01, 0x02, 0x08, 0xce}, - { "Philips PAL/SECAM multi (FQ1216AME MK4)", /* Philips PAL */ - 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0xce}, - { "Philips FQ1236A MK4", /* Philips NTSC */ - 16*160.00, 16*442.00, 0x01, 0x02, 0x04, 0x8e}, - { "Ymec TVision TVF-8531MF/8831MF/8731MF", /* Philips NTSC */ - 16*160.00, 16*454.00, 0xa0, 0x90, 0x30, 0x8e}, - { "Ymec TVision TVF-5533MF", /* Philips NTSC */ - 16*160.00, 16*454.00, 0x01, 0x02, 0x04, 0x8e}, + [TUNER_TCL_2002MB] = { /* TCL PAL */ + .name = "TCL 2002MB", + .thresh1= 16 * 170.00 /*MHz*/, + .thresh2= 16 * 450.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0xce, + }, + [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0xce, + }, + [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ + .name = "Philips FQ1236A MK4", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ + .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0xa0, + .VHF_H = 0x90, + .UHF = 0x30, + .config = 0x8e, + }, + [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ + .name = "Ymec TVision TVF-5533MF", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, /* 60-69 */ - { "Thomson DDT 7611 (ATSC/NTSC)", /* THOMSON ATSC */ - 16*157.25, 16*454.00, 0x39, 0x3a, 0x3c, 0x8e}, - { "Tena TNF9533-D/IF/TNF9533-B/DF", /* Philips PAL */ - 16*160.25, 16*464.25, 0x01, 0x02, 0x04, 0x8e}, - { "Philips TEA5767HN FM Radio", /* Philips RADIO */ + [TUNER_THOMSON_DTT7611] = { /* THOMSON ATSC */ + .name = "Thomson DDT 7611 (ATSC/NTSC)", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x39, + .VHF_H = 0x3a, + .UHF = 0x3c, + .config = 0x8e, + }, + [TUNER_TENA_9533_DI] = { /* Philips PAL */ + .name = "Tena TNF9533-D/IF/TNF9533-B/DF", + .thresh1= 16 * 160.25 /*MHz*/, + .thresh2= 16 * 464.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_TEA5767] = { /* Philips RADIO */ + .name = "Philips TEA5767HN FM Radio", /* see tea5767.c for details */}, - { "Philips FMD1216ME MK3 Hybrid Tuner", /* Philips PAL */ - 16*160.00, 16*442.00, 0x51, 0x52, 0x54, 0x86}, - { "LG TDVS-H062F/TUA6034", /* LGINNOTEK ATSC */ - 16*160.00, 16*455.00, 0x01, 0x02, 0x04, 0x8e}, - { "Ymec TVF66T5-B/DFF", /* Philips PAL */ - 16*160.25, 16*464.25, 0x01, 0x02, 0x08, 0x8e}, - { "LG NTSC (TALN mini series)", /* LGINNOTEK NTSC */ - 16*137.25, 16*373.25, 0x01, 0x02, 0x08, 0x8e}, - { "Philips TD1316 Hybrid Tuner", /* Philips PAL */ - 16*160.00, 16*442.00, 0xa1, 0xa2, 0xa4, 0xc8}, - { "Philips TUV1236D ATSC/NTSC dual in", /* Philips ATSC */ - 16*157.25, 16*454.00, 0x01, 0x02, 0x04, 0xce}, - { "Tena TNF 5335 MF", /* Philips NTSC */ - 16*157.25, 16*454.00, 0x01, 0x02, 0x04, 0x8e}, + [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ + .name = "Philips FMD1216ME MK3 Hybrid Tuner", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0x51, + .VHF_H = 0x52, + .UHF = 0x54, + .config = 0x86, + }, + [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */ + .name = "LG TDVS-H062F/TUA6034", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 455.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, + [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ + .name = "Ymec TVF66T5-B/DFF", + .thresh1= 16 * 160.25 /*MHz*/, + .thresh2= 16 * 464.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */ + .name = "LG NTSC (TALN mini series)", + .thresh1= 16 * 137.25 /*MHz*/, + .thresh2= 16 * 373.25 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x08, + .config = 0x8e, + }, + [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ + .name = "Philips TD1316 Hybrid Tuner", + .thresh1= 16 * 160.00 /*MHz*/, + .thresh2= 16 * 442.00 /*MHz*/, + .VHF_L = 0xa1, + .VHF_H = 0xa2, + .UHF = 0xa4, + .config = 0xc8, + }, + [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ + .name = "Philips TUV1236D ATSC/NTSC dual in", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0xce, + }, + [TUNER_TNF_5335MF] = { /* Philips NTSC */ + .name = "Tena TNF 5335 MF", + .thresh1= 16 * 157.25 /*MHz*/, + .thresh2= 16 * 454.00 /*MHz*/, + .VHF_L = 0x01, + .VHF_H = 0x02, + .UHF = 0x04, + .config = 0x8e, + }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/include/media/tuner.h b/include/media/tuner.h index b37cde606692..b28aa17213f5 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -115,28 +115,6 @@ #define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ #define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */ -#define NOTUNER 0 -#define PAL 1 /* PAL_BG */ -#define PAL_I 2 -#define NTSC 3 -#define SECAM 4 -#define ATSC 5 -#define RADIO 6 - -#define NoTuner 0 -#define Philips 1 -#define TEMIC 2 -#define Sony 3 -#define Alps 4 -#define LGINNOTEK 5 -#define SHARP 6 -#define Samsung 7 -#define Microtune 8 -#define HITACHI 9 -#define Panasonic 10 -#define TCL 11 -#define THOMSON 12 - #define TUNER_SET_TYPE_ADDR _IOW('T',3,int) #define TUNER_SET_STANDBY _IOW('T',4,int) #define TDA9887_SET_CONFIG _IOW('t',5,int) -- cgit v1.2.3 From d3707add6158803b6463292178cd1a041857b91b Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 9 Jan 2006 15:25:04 -0200 Subject: DVB (2420): Makes integration of future devices easier - To make the integration of future devices easier - modified the dvb-usb-part to allow a device-specific firmware download - added an option to specify whether a device reconnects after a firmware download or not. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-common.h | 2 +- drivers/media/dvb/dvb-usb/dvb-usb-firmware.c | 151 +++++++++++++++++---------- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 56 +++++----- drivers/media/dvb/dvb-usb/dvb-usb.h | 27 ++++- 4 files changed, 150 insertions(+), 86 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index 7300489d3e24..a3460bf2d9fa 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -24,7 +24,7 @@ extern int dvb_usb_disable_rc_polling; #define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args) /* commonly used methods */ -extern int usb_cypress_load_firmware(struct usb_device *, const char *, int); +extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *); extern int dvb_usb_urb_submit(struct dvb_usb_device *); extern int dvb_usb_urb_kill(struct dvb_usb_device *); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c index 5244e39770a0..ab87af99d36f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c @@ -9,7 +9,6 @@ */ #include "dvb-usb-common.h" -#include #include struct usb_cypress_controller { @@ -19,9 +18,10 @@ struct usb_cypress_controller { }; static struct usb_cypress_controller cypress[] = { - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, + { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, }; /* @@ -33,68 +33,113 @@ static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 le 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ); } -int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type) +static int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) { - const struct firmware *fw = NULL; - u16 addr; - u8 *b,*p; - int ret = 0,i; + struct hexline hx; + u8 reset; + int ret,pos=0; - if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", - filename); + /* stop the CPU */ + reset = 1; + if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + err("could not stop the USB controller CPU."); + + while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); + ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + + if (ret != hx.len) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", + ret,hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); return ret; } - info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name); - - p = kmalloc(fw->size,GFP_KERNEL); - if (p != NULL) { - u8 reset; - /* - * you cannot use the fw->data as buffer for - * usb_control_msg, a new buffer has to be - * created - */ - memcpy(p,fw->data,fw->size); - - /* stop the CPU */ - reset = 1; - if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) - err("could not stop the USB controller CPU."); - for(i = 0; p[i+3] == 0 && i < fw->size; ) { - b = (u8 *) &p[i]; - addr = cpu_to_le16( *((u16 *) &b[1]) ); - - deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]); - - ret = usb_cypress_writemem(udev,addr,&b[4],b[0]); - - if (ret != b[0]) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", - ret,b[0]); - ret = -EINVAL; - break; - } - i += 5 + b[0]; - } - /* length in ret */ - if (ret > 0) - ret = 0; + if (ret == 0) { /* restart the CPU */ reset = 0; if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } + } else + ret = -EIO; - kfree(p); - } else { - ret = -ENOMEM; + return ret; +} + +int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props) +{ + int ret; + const struct firmware *fw = NULL; + + if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + props->firmware,ret); + return ret; } - release_firmware(fw); + info("downloading firmware from file '%s'",props->firmware); + + switch (props->usb_ctrl) { + case CYPRESS_AN2135: + case CYPRESS_AN2235: + case CYPRESS_FX2: + ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl); + break; + case DEVICE_SPECIFIC: + if (props->download_firmware) + ret = props->download_firmware(udev,fw); + else { + err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + release_firmware(fw); return ret; } + +int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + if (*pos >= fw->size) + return 0; + + memset(hx,0,sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = le16_to_cpu( *((u16 *) &b[1]) ); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); +/* hx->len -= 2; + data_offs += 2; */ + } + memcpy(hx->data,&b[data_offs],hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usb_get_hexline); + diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index dd8e0b94edba..2f9c3638adcf 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -145,38 +145,40 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties if (cold) { info("found a '%s' in cold state, will try to load a firmware",desc->name); - ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl); - } else { - info("found a '%s' in warm state.",desc->name); - d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); + ret = dvb_usb_download_firmware(udev,props); + if (!props->no_reconnect) return ret; + } + + info("found a '%s' in warm state.",desc->name); + d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL); + if (d == NULL) { + err("no memory for 'struct dvb_usb_device'"); + return ret; + } + memset(d,0,sizeof(struct dvb_usb_device)); + + d->udev = udev; + memcpy(&d->props,props,sizeof(struct dvb_usb_properties)); + d->desc = desc; + d->owner = owner; + + if (d->props.size_of_priv > 0) { + d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + kfree(d); + return -ENOMEM; } - memset(d,0,sizeof(struct dvb_usb_device)); - - d->udev = udev; - memcpy(&d->props,props,sizeof(struct dvb_usb_properties)); - d->desc = desc; - d->owner = owner; - - if (d->props.size_of_priv > 0) { - d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); - kfree(d); - return -ENOMEM; - } - memset(d->priv,0,d->props.size_of_priv); - } + memset(d->priv,0,d->props.size_of_priv); + } - usb_set_intfdata(intf, d); + usb_set_intfdata(intf, d); - if (du != NULL) - *du = d; + if (du != NULL) + *du = d; - ret = dvb_usb_init(d); - } + ret = dvb_usb_init(d); if (ret == 0) info("%s successfully initialized and connected.",desc->name); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index b4a1a98006c7..cd510fba60ee 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "dvb_demux.h" @@ -94,7 +95,11 @@ struct dvb_usb_device; * @usb_ctrl: which USB device-side controller is in use. Needed for firmware * download. * @firmware: name of the firmware file. - * + * @download_firmware: called to download the firmware when the usb_ctrl is + * DEVICE_SPECIFIC. + * @no_reconnect: device doesn't do a reconnect after downloading the firmware, + so do the warm initialization right after it + * @size_of_priv: how many bytes shall be allocated for the private field * of struct dvb_usb_device. * @@ -142,11 +147,14 @@ struct dvb_usb_properties { int caps; int pid_filter_count; -#define CYPRESS_AN2135 0 -#define CYPRESS_AN2235 1 -#define CYPRESS_FX2 2 +#define DEVICE_SPECIFIC 0 +#define CYPRESS_AN2135 1 +#define CYPRESS_AN2235 2 +#define CYPRESS_FX2 3 int usb_ctrl; - const char *firmware; + const char firmware[FIRMWARE_NAME_MAX]; + int (*download_firmware) (struct usb_device *, const struct firmware *); + int no_reconnect; int size_of_priv; @@ -326,5 +334,14 @@ extern int dvb_usb_pll_init_i2c(struct dvb_frontend *); extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]); extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *); +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *); #endif -- cgit v1.2.3 From 8a8e9c281de5dd63cdcbbafc0252fe0d8c758294 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Mon, 9 Jan 2006 15:25:04 -0200 Subject: DVB (2421): Fixed oddities at firmware download - Fixed oddities at firmware download - more tolerant vs crystal frequency offset - lower sampling clock Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tda1004x.c | 138 +++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 48 deletions(-) diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index dd02aff467fe..c6ae5bfae5b1 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -271,32 +271,57 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state, static int tda10046h_set_bandwidth(struct tda1004x_state *state, fe_bandwidth_t bandwidth) { - static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e }; - static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 }; - static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd }; - + static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; + static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; + static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d }; + + static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 }; + static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab }; + static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 }; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; switch (bandwidth) { case BANDWIDTH_6_MHZ: - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, + sizeof(bandwidth_6mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M, + sizeof(bandwidth_6mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab); } break; case BANDWIDTH_7_MHZ: - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, + sizeof(bandwidth_7mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M, + sizeof(bandwidth_7mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); } break; case BANDWIDTH_8_MHZ: - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, + sizeof(bandwidth_8mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M, + sizeof(bandwidth_8mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55); } break; @@ -418,9 +443,22 @@ static int tda10045_fwupload(struct dvb_frontend* fe) static void tda10046_init_plls(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10 + if(tda10046_clk53m) { + printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8 + } else { + printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3 + } if (state->config->xtal_freq == TDA10046_XTAL_4M ) { dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 @@ -428,26 +466,32 @@ static void tda10046_init_plls(struct dvb_frontend* fe) dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 } - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); + if(tda10046_clk53m) + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67); + else + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72); + /* Note clock frequency is handled implicitly */ switch (state->config->if_freq) { - case TDA10046_FREQ_3617: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); - break; - case TDA10046_FREQ_3613: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13); - break; case TDA10046_FREQ_045: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); break; case TDA10046_FREQ_052: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7); + break; + case TDA10046_FREQ_3617: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59); + break; + case TDA10046_FREQ_3613: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); break; } tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + /* let the PLLs settle */ + msleep(120); } static int tda10046_fwupload(struct dvb_frontend* fe) @@ -462,13 +506,13 @@ static int tda10046_fwupload(struct dvb_frontend* fe) /* let the clocks recover from sleep */ msleep(5); + /* The PLLs need to be reprogrammed after sleep */ + tda10046_init_plls(fe); + /* don't re-upload unless necessary */ if (tda1004x_check_upload_ok(state) == 0) return 0; - /* set parameters */ - tda10046_init_plls(fe); - if (state->config->request_firmware != NULL) { /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); @@ -484,7 +528,6 @@ static int tda10046_fwupload(struct dvb_frontend* fe) return ret; } else { /* boot from firmware eeprom */ - /* Hac Note: we might need to do some GPIO Magic here */ printk(KERN_INFO "tda1004x: booting from eeprom\n"); tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); msleep(300); @@ -606,10 +649,9 @@ static int tda10046_init(struct dvb_frontend* fe) // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream - tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer + tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream + tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer - tda10046_init_plls(fe); switch (state->config->agc_config) { case TDA10046_AGC_DEFAULT: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup @@ -626,25 +668,22 @@ static int tda10046_init(struct dvb_frontend* fe) case TDA10046_AGC_TDA827X: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold - tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities break; } + tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } - tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 + tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1 tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup - tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config - tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select - state->initialised = 1; return 0; } @@ -686,9 +725,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // Set standard params.. or put them to auto if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || - (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || - (fe_params->u.ofdm.constellation == QAM_AUTO) || - (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { + (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || + (fe_params->u.ofdm.constellation == QAM_AUTO) || + (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits @@ -851,6 +890,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) { struct tda1004x_state* state = fe->demodulator_priv; + dprintk("%s\n", __FUNCTION__); // inversion status @@ -875,16 +915,18 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete break; } break; - case TDA1004X_DEMOD_TDA10046: switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { - case 0x60: + case 0x5c: + case 0x54: fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break; - case 0x6e: + case 0x6a: + case 0x60: fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break; - case 0x80: + case 0x7b: + case 0x70: fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break; } -- cgit v1.2.3 From 2d0235df0e62cb9f07232bf9cf8009fabf13d304 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 9 Jan 2006 15:25:05 -0200 Subject: DVB (2428): Fixes for the topuptv/SCM mediaguard CAM module in KNC1 CI module - Fixes for the topuptv/SCM mediaguard CAM module in KNC1 CI module Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-av.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9f51bae7194c..8bc784ab1972 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -127,7 +127,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); if (result == -ETIMEDOUT) budget_av->slot_status = 0; @@ -145,7 +145,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0); + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); if (result == -ETIMEDOUT) budget_av->slot_status = 0; @@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int timeout = 500; // 5 seconds (4.4.6 Ready) + int timeout = 50; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; @@ -256,19 +256,37 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; + int cam_present = 0; if (slot != 0) return -EINVAL; - if (!budget_av->slot_status) { + if (!budget_av->slot_status) + { + // first of all test the card detect line saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); udelay(1); if (saa7146_read(saa, PSR) & MASK_06) { + cam_present = 1; + } + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + + // that is unreliable however, so try and read from IO memory + if (!cam_present) + { + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) + { + cam_present = 1; + } + } + + // did we find something? + if (cam_present) { printk(KERN_INFO "budget-av: cam inserted\n"); budget_av->slot_status = 1; } - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); } else if (!open) { saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) -- cgit v1.2.3 From eb3daf3c5acfa737bdf2bd9d1f93c3393dde5067 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 9 Jan 2006 15:25:05 -0200 Subject: DVB (2431): Fixed dishnetwork support for Nexus-S rev 2.3 - Fixed dishnetwork support for Nexus-S rev 2.3 Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 7dae91e5863c..48b846bcff69 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2314,8 +2314,10 @@ static int frontend_init(struct av7110 *av7110) case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ /* ALPS BSBE1 */ av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap); - if (av7110->fe) + if (av7110->fe) { av7110->fe->ops->set_voltage = lnbp21_set_voltage; + av7110->fe->ops->dishnetwork_send_legacy_command = NULL; + } break; } } -- cgit v1.2.3 From f49cc15bbe37b767286fdd7abe65810e750cf70a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 9 Jan 2006 15:25:06 -0200 Subject: DVB (2432): LNB power can now be switched off for Activy Budget-S rev GR/AL. - LNB power can now be switched off for Activy Budget-S rev GR/AL. Dishnetwork support fixed for Nova-S with bsbe1/lnbp21 frontend and Activy Budget-S rev AL. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-core.c | 4 +--- drivers/media/dvb/ttpci/budget.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 017fcbccb8cc..633e68c341c8 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -404,9 +404,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); /* frontend power on */ - if (bi->type == BUDGET_FS_ACTIVY) - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - else + if (bi->type != BUDGET_FS_ACTIVY) saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); if (budget_register(budget) == 0) { diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index fafe6407b3d0..746aad373293 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -112,6 +112,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long * Routines for the Fujitsu Siemens Activy budget card * 22 kHz tone and DiSEqC are handled by the frontend. * Voltage must be set here. + * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL */ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) { @@ -121,11 +122,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) switch (voltage) { case SEC_VOLTAGE_13: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); break; case SEC_VOLTAGE_18: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); break; + case SEC_VOLTAGE_OFF: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); + break; default: return -EINVAL; } @@ -580,6 +586,7 @@ static void frontend_init(struct budget *budget) if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; if (lnbp21_init(budget)) { printk("%s: No LNBP21 found!\n", __FUNCTION__); goto error_out; @@ -624,7 +631,7 @@ static void frontend_init(struct budget *budget) budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; - break; + budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; } break; @@ -632,7 +639,7 @@ static void frontend_init(struct budget *budget) budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; - break; + budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; } break; -- cgit v1.2.3 From 1c13b95c7d22d5c552246b465da4b364ba00ba65 Mon Sep 17 00:00:00 2001 From: Marco Schluessler Date: Mon, 9 Jan 2006 15:25:06 -0200 Subject: DVB (2440): Fixed mpeg audio on spdif from Nexus-CA card (rev 2.3), - Fixed mpeg audio on spdif from Nexus-CA card (rev 2.3), definitions for sound chip MSP3415 Signed-off-by: Marco Schluessler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 12 +++++++++--- drivers/media/dvb/ttpci/av7110.h | 3 ++- drivers/media/dvb/ttpci/av7110_av.c | 2 +- drivers/media/dvb/ttpci/av7110_v4l.c | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 48b846bcff69..240451dcd8b8 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110) /* remaining inits according to card and frontend type */ av7110->analog_tuner_flags = 0; av7110->current_input = 0; - if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) { + printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x5; + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on + } + else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_CRYSTAL; @@ -156,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110) else { av7110->adac_type = adac; printk("dvb-ttpci: adac type set to %d @ card %d\n", - av7110->dvb_adapter.num, av7110->adac_type); + av7110->adac_type, av7110->dvb_adapter.num); } - if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { + if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { // switch DVB SCART on ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); if (ret < 0) diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index cce00ef293e9..d5550f462062 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -98,7 +98,8 @@ struct av7110 { int adac_type; /* audio DAC type */ #define DVB_ADAC_TI 0 #define DVB_ADAC_CRYSTAL 1 -#define DVB_ADAC_MSP 2 +#define DVB_ADAC_MSP34x0 2 +#define DVB_ADAC_MSP34x5 3 #define DVB_ADAC_NONE -1 diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 0696a5a4f855..2d26ff316fe6 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) i2c_writereg(av7110, 0x20, 0x04, volright); return 0; - case DVB_ADAC_MSP: + case DVB_ADAC_MSP34x0: vol = (volleft > volright) ? volleft : volright; val = (vol * 0x73 / 255) << 8; if (vol > 0) diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index b5aea4129fa7..e3296b07caac 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -587,7 +587,7 @@ int av7110_init_analog_module(struct av7110 *av7110) printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP; + av7110->adac_type = DVB_ADAC_MSP34x0; msleep(100); // the probing above resets the msp... msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); -- cgit v1.2.3 From 47f3692096eef208d8cb455bfa2b3308cdfc40de Mon Sep 17 00:00:00 2001 From: "Dr. Werner Fink" Date: Mon, 9 Jan 2006 15:25:07 -0200 Subject: DVB (2441): Driver support for live-ac3, firmware >= 2621 required. - Driver support for live-ac3, firmware >= 2621 required. Signed-off-by: Dr. Werner Fink Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 9 +++++++-- drivers/media/dvb/ttpci/av7110_av.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 240451dcd8b8..8fa487fb507b 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -720,6 +720,8 @@ static struct dvb_device dvbdev_osd = { static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid) { + u16 aflags = 0; + dprintk(4, "%p\n", av7110); if (vpid == 0x1fff || apid == 0x1fff || @@ -731,8 +733,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, av7110->pids[DMX_PES_PCR] = 0; } - return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5, - pcrpid, vpid, apid, ttpid, subpid); + if (av7110->audiostate.bypass_mode) + aflags |= 0x8000; + + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, + pcrpid, vpid, apid, ttpid, subpid, aflags); } int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 2d26ff316fe6..400facec7407 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1256,7 +1256,9 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, break; case AUDIO_SET_BYPASS_MODE: - ret = -EINVAL; + if (FW_VERSION(av7110->arm_app) < 0x2621) + ret = -EINVAL; + av7110->audiostate.bypass_mode = (int)arg; break; case AUDIO_CHANNEL_SELECT: @@ -1295,7 +1297,11 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, break; case AUDIO_GET_CAPABILITIES: - *(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + if (FW_VERSION(av7110->arm_app) < 0x2621) + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + else + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | + AUDIO_CAP_MP1 | AUDIO_CAP_MP2; break; case AUDIO_CLEAR_BUFFER: -- cgit v1.2.3 From 36cb557a2f64513e2fdc1a542167e5e8a6c1c67e Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 9 Jan 2006 15:25:07 -0200 Subject: DVB (2444): Implement frontend-specific tuning and the ability to disable zigzag - Implement frontend-specific tuning and the ability to disable zigzag Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dst.c | 52 +++-- drivers/media/dvb/dvb-core/dvb_frontend.c | 307 +++++++++++++++++------------- drivers/media/dvb/dvb-core/dvb_frontend.h | 11 +- include/linux/dvb/frontend.h | 10 + 4 files changed, 228 insertions(+), 152 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 8977c7a313df..3a2ff1cc24b7 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; } -static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dst_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* p, + unsigned int mode_flags, + int *delay, + fe_status_t *status) { struct dst_state *state = fe->demodulator_priv; - dst_set_freq(state, p->frequency); - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + if (p != NULL) { + dst_set_freq(state, p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); - if (state->dst_type == DST_TYPE_IS_SAT) { - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); - dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); - - } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); - else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->u.qpsk.fec_inner); + dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_polarization(state); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + + } else if (state->dst_type == DST_TYPE_IS_TERR) + dst_set_bandwidth(state, p->u.ofdm.bandwidth); + else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->u.qam.fec_inner); + dst_set_symbolrate(state, p->u.qam.symbol_rate); + dst_set_modulation(state, p->u.qam.modulation); + } + dst_write_tuna(fe); } - dst_write_tuna(fe); + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + dst_read_status(fe, status); + + *delay = HZ/10; return 0; } @@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = { .release = dst_release, .init = dst_init, - .set_frontend = dst_set_frontend, + .tune = dst_set_frontend, .get_frontend = dst_get_frontend, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, @@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = { .release = dst_release, .init = dst_init, - .set_frontend = dst_set_frontend, + .tune = dst_set_frontend, .get_frontend = dst_get_frontend, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, @@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = { .release = dst_release, .init = dst_init, - .set_frontend = dst_set_frontend, + .tune = dst_set_frontend, .get_frontend = dst_get_frontend, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 95ea5095e07e..9b5fa540e1e7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex); struct dvb_frontend_private { + /* thread/frontend values */ struct dvb_device *dvbdev; struct dvb_frontend_parameters parameters; struct dvb_fe_events events; @@ -100,20 +101,25 @@ struct dvb_frontend_private { wait_queue_head_t wait_queue; pid_t thread_pid; unsigned long release_jiffies; - int state; - int bending; - int lnb_drift; - int inversion; - int auto_step; - int auto_sub_step; - int started_auto_step; - int min_delay; - int max_drift; - int step_size; - int exit; - int wakeup; + unsigned int exit; + unsigned int wakeup; fe_status_t status; - fe_sec_tone_mode_t tone; + unsigned int tune_mode_flags; + unsigned int delay; + + /* swzigzag values */ + unsigned int state; + unsigned int bending; + int lnb_drift; + unsigned int inversion; + unsigned int auto_step; + unsigned int auto_sub_step; + unsigned int started_auto_step; + unsigned int min_delay; + unsigned int max_drift; + unsigned int step_size; + int quality; + unsigned int check_wrapped; }; @@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe) fe->ops->init(fe); } -static void update_delay(int *quality, int *delay, int min_delay, int locked) +static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) { - int q2; + int q2; - dprintk ("%s\n", __FUNCTION__); + dprintk ("%s\n", __FUNCTION__); - if (locked) - (*quality) = (*quality * 220 + 36*256) / 256; - else - (*quality) = (*quality * 220 + 0) / 256; + if (locked) + (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; + else + (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; - q2 = *quality - 128; - q2 *= q2; + q2 = fepriv->quality - 128; + q2 *= q2; - *delay = min_delay + q2 * HZ / (128*128); + fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); } /** @@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked) * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT * @returns Number of complete iterations that have been performed. */ -static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) +static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) { int autoinversion; int ready = 0; @@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) return 0; } +static void dvb_frontend_swzigzag(struct dvb_frontend *fe) +{ + fe_status_t s; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + /* if we've got no parameters, just keep idling */ + if (fepriv->state & FESTATE_IDLE) { + fepriv->delay = 3*HZ; + fepriv->quality = 0; + return; + } + + /* in SCAN mode, we just set the frontend when asked and leave it alone */ + if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { + if (fepriv->state & FESTATE_RETUNE) { + if (fe->ops->set_frontend) + fe->ops->set_frontend(fe, &fepriv->parameters); + fepriv->state = FESTATE_TUNED; + } + fepriv->delay = 3*HZ; + fepriv->quality = 0; + return; + } + + /* get the frontend status */ + if (fepriv->state & FESTATE_RETUNE) { + s = 0; + } else { + if (fe->ops->read_status) + fe->ops->read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); + fepriv->status = s; + } + } + + /* if we're not tuned, and we have a lock, move to the TUNED state */ + if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + fepriv->state = FESTATE_TUNED; + + /* if we're tuned, then we have determined the correct inversion */ + if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && + (fepriv->parameters.inversion == INVERSION_AUTO)) { + fepriv->parameters.inversion = fepriv->inversion; + } + return; + } + + /* if we are tuned already, check we're still locked */ + if (fepriv->state & FESTATE_TUNED) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + /* we're tuned, and the lock is still good... */ + if (s & FE_HAS_LOCK) { + return; + } else { /* if we _WERE_ tuned, but now don't have a lock */ + fepriv->state = FESTATE_ZIGZAG_FAST; + fepriv->started_auto_step = fepriv->auto_step; + fepriv->check_wrapped = 0; + } + } + + /* don't actually do anything if we're in the LOSTLOCK state, + * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ + if ((fepriv->state & FESTATE_LOSTLOCK) && + (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + return; + } + + /* don't do anything if we're in the DISEQC state, since this + * might be someone with a motorized dish controlled by DISEQC. + * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ + if (fepriv->state & FESTATE_DISEQC) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + return; + } + + /* if we're in the RETUNE state, set everything up for a brand + * new scan, keeping the current inversion setting, as the next + * tune is _very_ likely to require the same */ + if (fepriv->state & FESTATE_RETUNE) { + fepriv->lnb_drift = 0; + fepriv->auto_step = 0; + fepriv->auto_sub_step = 0; + fepriv->started_auto_step = 0; + fepriv->check_wrapped = 0; + } + + /* fast zigzag. */ + if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { + fepriv->delay = fepriv->min_delay; + + /* peform a tune */ + if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) { + /* OK, if we've run out of trials at the fast speed. + * Drop back to slow for the _next_ attempt */ + fepriv->state = FESTATE_SEARCHING_SLOW; + fepriv->started_auto_step = fepriv->auto_step; + return; + } + fepriv->check_wrapped = 1; + + /* if we've just retuned, enter the ZIGZAG_FAST state. + * This ensures we cannot return from an + * FE_SET_FRONTEND ioctl before the first frontend tune + * occurs */ + if (fepriv->state & FESTATE_RETUNE) { + fepriv->state = FESTATE_TUNING_FAST; + } + } + + /* slow zigzag */ + if (fepriv->state & FESTATE_SEARCHING_SLOW) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + /* Note: don't bother checking for wrapping; we stay in this + * state until we get a lock */ + dvb_frontend_swzigzag_autotune(fe, 0); + } +} + static int dvb_frontend_is_exiting(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe) if (fepriv->dvbdev->writers == 1) if (time_after(jiffies, fepriv->release_jiffies + - dvb_shutdown_timeout * HZ)) + dvb_shutdown_timeout * HZ)) return 1; return 0; @@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) wake_up_interruptible(&fepriv->wait_queue); } -/* - * FIXME: use linux/kthread.h - */ static int dvb_frontend_thread(void *data) { struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; char name [15]; - int quality = 0, delay = 3*HZ; fe_status_t s; - int check_wrapped = 0; + struct dvb_frontend_parameters *params; dprintk("%s\n", __FUNCTION__); @@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data) sigfillset(¤t->blocked); unlock_kernel(); + fepriv->check_wrapped = 0; + fepriv->quality = 0; + fepriv->delay = 3*HZ; fepriv->status = 0; dvb_frontend_init(fe); fepriv->wakeup = 0; @@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data) timeout = wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe), - delay); + fepriv->delay); if (0 != dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ break; @@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data) if (down_interruptible(&fepriv->sem)) break; - /* if we've got no parameters, just keep idling */ - if (fepriv->state & FESTATE_IDLE) { - delay = 3*HZ; - quality = 0; - continue; - } + /* do an iteration of the tuning loop */ + if (fe->ops->tune) { + /* have we been asked to retune? */ + params = NULL; + if (fepriv->state & FESTATE_RETUNE) { + params = &fepriv->parameters; + fepriv->state = FESTATE_TUNED; + } - /* get the frontend status */ - if (fepriv->state & FESTATE_RETUNE) { - s = 0; - } else { - if (fe->ops->read_status) - fe->ops->read_status(fe, &s); + fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); fepriv->status = s; } - } - /* if we're not tuned, and we have a lock, move to the TUNED state */ - if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - fepriv->state = FESTATE_TUNED; - - /* if we're tuned, then we have determined the correct inversion */ - if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.inversion == INVERSION_AUTO)) { - fepriv->parameters.inversion = fepriv->inversion; - } - continue; - } - - /* if we are tuned already, check we're still locked */ - if (fepriv->state & FESTATE_TUNED) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - - /* we're tuned, and the lock is still good... */ - if (s & FE_HAS_LOCK) - continue; - else { /* if we _WERE_ tuned, but now don't have a lock */ - fepriv->state = FESTATE_ZIGZAG_FAST; - fepriv->started_auto_step = fepriv->auto_step; - check_wrapped = 0; - } - } - - /* don't actually do anything if we're in the LOSTLOCK state, - * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ - if ((fepriv->state & FESTATE_LOSTLOCK) && - (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - continue; - } - - /* don't do anything if we're in the DISEQC state, since this - * might be someone with a motorized dish controlled by DISEQC. - * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ - if (fepriv->state & FESTATE_DISEQC) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - continue; - } - - /* if we're in the RETUNE state, set everything up for a brand - * new scan, keeping the current inversion setting, as the next - * tune is _very_ likely to require the same */ - if (fepriv->state & FESTATE_RETUNE) { - fepriv->lnb_drift = 0; - fepriv->auto_step = 0; - fepriv->auto_sub_step = 0; - fepriv->started_auto_step = 0; - check_wrapped = 0; - } - - /* fast zigzag. */ - if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { - delay = fepriv->min_delay; - - /* peform a tune */ - if (dvb_frontend_autotune(fe, check_wrapped)) { - /* OK, if we've run out of trials at the fast speed. - * Drop back to slow for the _next_ attempt */ - fepriv->state = FESTATE_SEARCHING_SLOW; - fepriv->started_auto_step = fepriv->auto_step; - continue; - } - check_wrapped = 1; - - /* if we've just retuned, enter the ZIGZAG_FAST state. - * This ensures we cannot return from an - * FE_SET_FRONTEND ioctl before the first frontend tune - * occurs */ - if (fepriv->state & FESTATE_RETUNE) { - fepriv->state = FESTATE_TUNING_FAST; - } - } - - /* slow zigzag */ - if (fepriv->state & FESTATE_SEARCHING_SLOW) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - - /* Note: don't bother checking for wrapping; we stay in this - * state until we get a lock */ - dvb_frontend_autotune(fe, 0); + } else { + dvb_frontend_swzigzag(fe); } } @@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; - fepriv->tone = (fe_sec_tone_mode_t) parg; } break; @@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); } break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned int) parg; + break; }; up (&fepriv->sem); @@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; + + /* normal tune mode when opened R/W */ + fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; } return ret; @@ -990,7 +1038,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->events.sem); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; - fepriv->tone = SEC_TONE_OFF; printk ("DVB: registering frontend %i (%s)...\n", fe->dvb->num, diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 1e0840d02f1f..48c3f81be912 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -58,10 +58,19 @@ struct dvb_frontend_ops { int (*init)(struct dvb_frontend* fe); int (*sleep)(struct dvb_frontend* fe); + /* if this is set, it overrides the default swzigzag */ + int (*tune)(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + unsigned int mode_flags, + int *delay, + fe_status_t *status); + + /* these two are only used for the swzigzag code */ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); + int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*read_ber)(struct dvb_frontend* fe, u32* ber); int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index d41df7047ed7..c8cbd90ba375 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -240,6 +240,15 @@ struct dvb_frontend_event { }; +/** + * When set, this flag will disable any zigzagging or other "normal" tuning + * behaviour. Additionally, there will be no automatic monitoring of the lock + * status, and hence no frontend events will be generated. If a frontend device + * is closed, this flag will be automatically turned off when the device is + * reopened read-write. + */ +#define FE_TUNE_MODE_ONESHOT 0x01 + #define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info) @@ -260,6 +269,7 @@ struct dvb_frontend_event { #define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters) #define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters) +#define FE_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */ #define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event) #define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */ -- cgit v1.2.3 From b79cb6531d5ba9174f9677ce2213c017d1e2ef19 Mon Sep 17 00:00:00 2001 From: Steve Toth Date: Mon, 9 Jan 2006 15:25:07 -0200 Subject: DVB (2445): Added demodulator driver for Nova-S-Plus and Nova-SE2 DVB-S support. - Added demodulator driver for Nova-S-Plus and Nova-SE2 DVB-S support. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 6 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/cx24123.c | 694 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/cx24123.h | 185 +++++++++ 4 files changed, 886 insertions(+) create mode 100644 drivers/media/dvb/frontends/cx24123.c create mode 100644 drivers/media/dvb/frontends/cx24123.h diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 8e269e1c1f9d..17f90ef9ab68 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -16,6 +16,12 @@ config DVB_CX24110 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_CX24123 + tristate "Conexant CX24123 based" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + config DVB_TDA8083 tristate "Philips TDA8083 based" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a98760fe08a1..615ec830e1c9 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o +obj-$(CONFIG_DVB_CX24123) += cx24123.o diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c new file mode 100644 index 000000000000..0061c7793436 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24123.c @@ -0,0 +1,694 @@ +/* + Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver + + Copyright (C) 2005 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "cx24123.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk (KERN_DEBUG "cx24123: " args); \ + } while (0) + +struct cx24123_state { + + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct cx24123_config* config; + + struct dvb_frontend frontend; + + u32 lastber; + u16 snr; + u8 lnbreg; + + /* Some PLL specifics for tuning */ + u32 VCAarg; + u32 VGAarg; + u32 bandselectarg; + u32 pllarg; + + /* The Demod/Tuner can't easily provide these, we cache them */ + u32 currentfreq; + u32 currentsymbolrate; +}; + +static struct { + u8 reg; + u8 data; +} cx24123_regdata[] = +{ + {0x00, 0x03}, /* Reset system */ + {0x00, 0x00}, /* Clear reset */ + {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */ + {0x03, 0x07}, + {0x04, 0x10}, + {0x05, 0x04}, + {0x06, 0x31}, + {0x0d, 0x02}, + {0x0e, 0x03}, + {0x0f, 0xfe}, + {0x10, 0x01}, + {0x14, 0x01}, + {0x15, 0x98}, + {0x16, 0x00}, + {0x17, 0x01}, + {0x1b, 0x05}, + {0x1c, 0x80}, + {0x1d, 0x00}, + {0x1e, 0x00}, + {0x20, 0x41}, + {0x21, 0x15}, + {0x27, 0x14}, + {0x28, 0x46}, + {0x29, 0x00}, + {0x2a, 0xb0}, + {0x2b, 0x73}, + {0x2c, 0x00}, + {0x2d, 0x00}, + {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x00}, + {0x31, 0x00}, + {0x32, 0x8c}, + {0x33, 0x00}, + {0x34, 0x00}, + {0x35, 0x03}, + {0x36, 0x02}, + {0x37, 0x3a}, + {0x3a, 0x00}, /* Enable AGC accumulator */ + {0x44, 0x00}, + {0x45, 0x00}, + {0x46, 0x05}, + {0x56, 0x41}, + {0x57, 0xff}, + {0x67, 0x83}, +}; + +static int cx24123_writereg(struct cx24123_state* state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk("%s: writereg error(err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data) +{ + u8 buf[] = { reg, data }; + /* fixme: put the intersil addr int the config */ + struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk("%s: writelnbreg error (err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + /* cache the write, no way to read back */ + state->lnbreg = data; + + return 0; +} + +static int cx24123_readreg(struct cx24123_state* state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret); + return ret; + } + + return b1[0]; +} + +static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg) +{ + return state->lnbreg; +} + +static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) +{ + switch (inversion) { + case INVERSION_OFF: + cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f); + cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); + break; + case INVERSION_ON: + cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80); + cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); + break; + case INVERSION_AUTO: + cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion) +{ + u8 val; + + val = cx24123_readreg(state, 0x1b) >> 7; + + if (val == 0) + *inversion=INVERSION_OFF; + else + *inversion=INVERSION_ON; + + return 0; +} + +static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) +{ + if ( (fec < FEC_NONE) || (fec > FEC_AUTO) ) + fec=FEC_AUTO; + + /* Hardware has 5/11 and 3/5 but are never unused */ + switch (fec) { + case FEC_NONE: + return cx24123_writereg(state, 0x0f,0x01); + case FEC_1_2: + return cx24123_writereg(state, 0x0f, 0x02); + case FEC_2_3: + return cx24123_writereg(state, 0x0f, 0x04); + case FEC_3_4: + return cx24123_writereg(state, 0x0f, 0x08); + case FEC_5_6: + return cx24123_writereg(state, 0x0f, 0x20); + case FEC_7_8: + return cx24123_writereg(state, 0x0f, 0x80); + case FEC_AUTO: + return cx24123_writereg(state, 0x0f, 0xae); + default: + return -EOPNOTSUPP; + } +} + +static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) +{ + u8 val; + + val = cx24123_readreg (state, 0x1b) & 0x07; + switch (val) { + case 1: + *fec=FEC_1_2; + return 0; + case 3: + *fec=FEC_2_3; + return 0; + case 4: + *fec=FEC_3_4; + return 0; + case 5: + *fec=FEC_4_5; + return 0; + case 6: + *fec=FEC_5_6; + return 0; + case 7: + *fec=FEC_7_8; + return 0; + case 2: /* *fec=FEC_3_5; return 0; */ + case 0: /* *fec=FEC_5_11; return 0; */ + *fec=FEC_AUTO; + return 0; + default: + *fec=FEC_NONE; return 0; + } + + return -EREMOTEIO; +} + +/* fixme: Symbol rates < 3MSps may not work because of precision loss */ +static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) +{ + u32 val; + + val = (srate/1185)*100; + + /* Compensate for scaling up, by removing 17 symbols per 1Msps */ + val = val - (17*(srate / 1000000)); + + cx24123_writereg(state, 0x08, (val >>16) & 0xff ); + cx24123_writereg(state, 0x09, (val >> 8) & 0xff ); + cx24123_writereg(state, 0x0a, (val ) & 0xff ); + + return 0; +} + +/* + * Based on the required frequency and symbolrate, the tuner AGC has to be configured + * and the correct band selected. Calculate those values + */ +static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + u32 ndiv=0, adiv=0, vco_div=0; + int i=0; + + /* Defaults for low freq, low rate */ + state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[0].VGAprogdata; + state->bandselectarg = cx24123_bandselect_vals[0].progdata; + vco_div = cx24123_bandselect_vals[0].VCOdivider; + + /* For the given symbolerate, determine the VCA and VGA programming bits */ + for (i=0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) + { + if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) && + (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) { + state->VCAarg = cx24123_AGC_vals[i].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[i].VGAprogdata; + } + } + + /* For the given frequency, determine the bandselect programming bits */ + for (i=0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) + { + if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && + (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) { + state->bandselectarg = cx24123_bandselect_vals[i].progdata; + vco_div = cx24123_bandselect_vals[i].VCOdivider; + } + } + + /* Determine the N/A dividers for the requested lband freq (in kHz). */ + /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */ + ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff; + adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f; + + if (adiv == 0) + adiv++; + + /* determine the correct pll frequency values. */ + /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */ + state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14); + state->pllarg |= (ndiv << 5) | adiv; + + return 0; +} + +/* + * Tuner data is 21 bits long, must be left-aligned in data. + * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip. + */ +static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data) +{ + struct cx24123_state *state = fe->demodulator_priv; + + u8 timeout=0; + + /* align the 21 bytes into to bit23 boundary */ + data = data << 3; + + /* Reset the demod pll word length to 0x15 bits */ + cx24123_writereg(state, 0x21, 0x15); + + timeout=0; + /* write the msb 8 bits, wait for the send to be completed */ + cx24123_writereg(state, 0x22, (data>>16) & 0xff); + while ( ( cx24123_readreg(state, 0x20) & 0x40 ) == 0 ) + { + /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ + if (timeout++ >= 4) { + printk("%s: demodulator is no longer responding, aborting.\n",__FUNCTION__); + return -EREMOTEIO; + } + msleep(500); + } + + timeout=0; + /* send another 8 bytes, wait for the send to be completed */ + cx24123_writereg(state, 0x22, (data>>8) & 0xff ); + while ( (cx24123_readreg(state, 0x20) & 0x40 ) == 0 ) + { + /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ + if (timeout++ >= 4) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n",__FUNCTION__); + return -EREMOTEIO; + } + msleep(500); + } + + timeout=0; + /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */ + cx24123_writereg(state, 0x22, (data) & 0xff ); + while ((cx24123_readreg(state, 0x20) & 0x80)) + { + /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ + if (timeout++ >= 4) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n",__FUNCTION__); + return -EREMOTEIO; + } + msleep(500); + } + + /* Trigger the demod to configure the tuner */ + cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2); + cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd); + + return 0; +} + +static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + if (cx24123_pll_calculate(fe, p)!=0) { + printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); + return -EINVAL; + } + + /* Write the new VCO/VGA */ + cx24123_pll_writereg(fe, p, state->VCAarg); + cx24123_pll_writereg(fe, p, state->VGAarg); + + /* Write the new bandselect and pll args */ + cx24123_pll_writereg(fe, p, state->bandselectarg); + cx24123_pll_writereg(fe, p, state->pllarg); + + return 0; +} + +static int cx24123_initfe(struct dvb_frontend* fe) +{ + struct cx24123_state *state = fe->demodulator_priv; + int i; + + /* Configure the demod to a good set of defaults */ + for (i=0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++) + cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data); + + if (state->config->pll_init) + state->config->pll_init(fe); + + /* Configure the LNB for 14V */ + cx24123_writelnbreg(state, 0x0, 0x2a); + + return 0; +} + +static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + val = cx24123_readlnbreg(state, 0x0); + + switch (voltage) { + case SEC_VOLTAGE_13: + return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ + case SEC_VOLTAGE_18: + return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ + case SEC_VOLTAGE_OFF: + return cx24123_writelnbreg(state, 0x0, val & 0x30); + default: + return -EINVAL; + }; +} + +static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *cmd) +{ + /* fixme: Implement diseqc */ + printk("%s: No support yet\n",__FUNCTION__); + + return -ENOTSUPP; +} + +static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct cx24123_state *state = fe->demodulator_priv; + + int sync = cx24123_readreg(state, 0x14); + int lock = cx24123_readreg(state, 0x20); + + *status = 0; + if (lock & 0x01) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + if (sync & 0x04) + *status |= FE_HAS_VITERBI; + if (sync & 0x08) + *status |= FE_HAS_CARRIER; + if (sync & 0x80) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + + return 0; +} + +/* + * Configured to return the measurement of errors in blocks, because no UCBLOCKS value + * is available, so this value doubles up to satisfy both measurements + */ +static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct cx24123_state *state = fe->demodulator_priv; + + state->lastber = + ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) | + (cx24123_readreg(state, 0x1d) << 8 | + cx24123_readreg(state, 0x1e)); + + /* Do the signal quality processing here, it's derived from the BER. */ + /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */ + if (state->lastber < 5000) + state->snr = 655*100; + else if ( (state->lastber >= 5000) && (state->lastber < 55000) ) + state->snr = 655*90; + else if ( (state->lastber >= 55000) && (state->lastber < 150000) ) + state->snr = 655*80; + else if ( (state->lastber >= 150000) && (state->lastber < 250000) ) + state->snr = 655*70; + else if ( (state->lastber >= 250000) && (state->lastber < 450000) ) + state->snr = 655*65; + else + state->snr = 0; + + *ber = state->lastber; + + return 0; +} + +static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cx24123_state *state = fe->demodulator_priv; + *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */ + + return 0; +} + +static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cx24123_state *state = fe->demodulator_priv; + *snr = state->snr; + + return 0; +} + +static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct cx24123_state *state = fe->demodulator_priv; + *ucblocks = state->lastber; + + return 0; +} + +static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + state->currentfreq=p->frequency; + state->currentsymbolrate=p->u.qpsk.symbol_rate; + + cx24123_set_inversion(state, p->inversion); + cx24123_set_fec(state, p->u.qpsk.fec_inner); + cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); + cx24123_pll_tune(fe, p); + + /* Enable automatic aquisition and reset cycle */ + cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07) ); + cx24123_writereg(state, 0x00, 0x10); + cx24123_writereg(state, 0x00, 0); + + return 0; +} + +static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + if (cx24123_get_inversion(state, &p->inversion) != 0) { + printk("%s: Failed to get inversion status\n",__FUNCTION__); + return -EREMOTEIO; + } + if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { + printk("%s: Failed to get fec status\n",__FUNCTION__); + return -EREMOTEIO; + } + p->frequency = state->currentfreq; + p->u.qpsk.symbol_rate = state->currentsymbolrate; + + return 0; +} + +static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + val = cx24123_readlnbreg(state, 0x0); + + switch (tone) { + case SEC_TONE_ON: + return cx24123_writelnbreg(state, 0x0, val | 0x10); + case SEC_TONE_OFF: + return cx24123_writelnbreg(state, 0x0, val & 0x2f); + default: + printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); + return -EINVAL; + } +} + +static void cx24123_release(struct dvb_frontend* fe) +{ + struct cx24123_state* state = fe->demodulator_priv; + dprintk("%s\n",__FUNCTION__); + kfree(state); +} + +static struct dvb_frontend_ops cx24123_ops; + +struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, struct i2c_adapter* i2c) +{ + struct cx24123_state* state = NULL; + int ret; + + dprintk("%s\n",__FUNCTION__); + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL); + if (state == NULL) { + printk("Unable to kmalloc\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops)); + state->lastber = 0; + state->snr = 0; + state->lnbreg = 0; + state->VCAarg = 0; + state->VGAarg = 0; + state->bandselectarg = 0; + state->pllarg = 0; + state->currentfreq = 0; + state->currentsymbolrate = 0; + + /* check if the demod is there */ + ret = cx24123_readreg(state, 0x00); + if ((ret != 0xd1) && (ret != 0xe1)) { + printk("Version != d1 or e1\n"); + goto error; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + + return NULL; +} + +static struct dvb_frontend_ops cx24123_ops = { + + .info = { + .name = "Conexant CX24123/CX24109", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24123_release, + + .init = cx24123_initfe, + .set_frontend = cx24123_set_frontend, + .get_frontend = cx24123_get_frontend, + .read_status = cx24123_read_status, + .read_ber = cx24123_read_ber, + .read_signal_strength = cx24123_read_signal_strength, + .read_snr = cx24123_read_snr, + .read_ucblocks = cx24123_read_ucblocks, + .diseqc_send_master_cmd = cx24123_send_diseqc_msg, + .set_tone = cx24123_set_tone, + .set_voltage = cx24123_set_voltage, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cx24123_attach); + diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h new file mode 100644 index 000000000000..80b66a695261 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24123.h @@ -0,0 +1,185 @@ +/* + Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver + + Copyright (C) 2005 Steven Toth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CX24123_H +#define CX24123_H + +#include + +struct cx24123_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +/* Various tuner defaults need to be established for a given symbol rate Sps */ +struct +{ + u32 symbolrate_low; + u32 symbolrate_high; + u32 VCAslope; + u32 VCAoffset; + u32 VGA1offset; + u32 VGA2offset; + u32 VCAprogdata; + u32 VGAprogdata; +} cx24123_AGC_vals[] = +{ + { + .symbolrate_low = 1000000, + .symbolrate_high = 4999999, + .VCAslope = 0x07, + .VCAoffset = 0x0f, + .VGA1offset = 0x1f8, + .VGA2offset = 0x1f8, + .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, + }, + { + .symbolrate_low = 5000000, + .symbolrate_high = 14999999, + .VCAslope = 0x1f, + .VCAoffset = 0x1f, + .VGA1offset = 0x1e0, + .VGA2offset = 0x180, + .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, + }, + { + .symbolrate_low = 15000000, + .symbolrate_high = 45000000, + .VCAslope = 0x3f, + .VCAoffset = 0x3f, + .VGA1offset = 0x180, + .VGA2offset = 0x100, + .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, + }, +}; + +/* + * Various tuner defaults need to be established for a given frequency kHz. + * fixme: The bounds on the bands do not match the doc in real life. + * fixme: Some of them have been moved, other might need adjustment. + */ +struct +{ + u32 freq_low; + u32 freq_high; + u32 bandselect; + u32 VCOdivider; + u32 VCOnumber; + u32 progdata; +} cx24123_bandselect_vals[] = +{ + { + .freq_low = 950000, + .freq_high = 1018999, + .bandselect = 0x40, + .VCOdivider = 4, + .VCOnumber = 7, + .progdata = (0 << 18) | (0 << 9) | 0x40, + }, + { + .freq_low = 1019000, + .freq_high = 1074999, + .bandselect = 0x80, + .VCOdivider = 4, + .VCOnumber = 8, + .progdata = (0 << 18) | (0 << 9) | 0x80, + }, + { + .freq_low = 1075000, + .freq_high = 1227999, + .bandselect = 0x01, + .VCOdivider = 2, + .VCOnumber = 1, + .progdata = (0 << 18) | (1 << 9) | 0x01, + }, + { + .freq_low = 1228000, + .freq_high = 1349999, + .bandselect = 0x02, + .VCOdivider = 2, + .VCOnumber = 2, + .progdata = (0 << 18) | (1 << 9) | 0x02, + }, + { + .freq_low = 1350000, + .freq_high = 1481999, + .bandselect = 0x04, + .VCOdivider = 2, + .VCOnumber = 3, + .progdata = (0 << 18) | (1 << 9) | 0x04, + }, + { + .freq_low = 1482000, + .freq_high = 1595999, + .bandselect = 0x08, + .VCOdivider = 2, + .VCOnumber = 4, + .progdata = (0 << 18) | (1 << 9) | 0x08, + }, + { + .freq_low = 1596000, + .freq_high = 1717999, + .bandselect = 0x10, + .VCOdivider = 2, + .VCOnumber = 5, + .progdata = (0 << 18) | (1 << 9) | 0x10, + }, + { + .freq_low = 1718000, + .freq_high = 1855999, + .bandselect = 0x20, + .VCOdivider = 2, + .VCOnumber = 6, + .progdata = (0 << 18) | (1 << 9) | 0x20, + }, + { + .freq_low = 1856000, + .freq_high = 2035999, + .bandselect = 0x40, + .VCOdivider = 2, + .VCOnumber = 7, + .progdata = (0 << 18) | (1 << 9) | 0x40, + }, + { + .freq_low = 2036000, + .freq_high = 2149999, + .bandselect = 0x80, + .VCOdivider = 2, + .VCOnumber = 8, + .progdata = (0 << 18) | (1 << 9) | 0x80, + }, +}; + +extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, + struct i2c_adapter* i2c); + +#endif /* CX24123_H */ + -- cgit v1.2.3 From e3b152bc9ee2b7f841565dc93a042f527cf3116c Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 9 Jan 2006 15:25:08 -0200 Subject: DVB (2446): Minor cleanups. - Minor cleanups. Signed-off-by: Johannes Stezenbach Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24123.c | 238 +++++++++++++++++++++++++++------- drivers/media/dvb/frontends/cx24123.h | 143 -------------------- 2 files changed, 192 insertions(+), 189 deletions(-) diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 0061c7793436..cfb7d2edd5a9 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -33,8 +33,8 @@ static int debug; if (debug) printk (KERN_DEBUG "cx24123: " args); \ } while (0) -struct cx24123_state { - +struct cx24123_state +{ struct i2c_adapter* i2c; struct dvb_frontend_ops ops; const struct cx24123_config* config; @@ -56,6 +56,148 @@ struct cx24123_state { u32 currentsymbolrate; }; +/* Various tuner defaults need to be established for a given symbol rate Sps */ +static struct +{ + u32 symbolrate_low; + u32 symbolrate_high; + u32 VCAslope; + u32 VCAoffset; + u32 VGA1offset; + u32 VGA2offset; + u32 VCAprogdata; + u32 VGAprogdata; +} cx24123_AGC_vals[] = +{ + { + .symbolrate_low = 1000000, + .symbolrate_high = 4999999, + .VCAslope = 0x07, + .VCAoffset = 0x0f, + .VGA1offset = 0x1f8, + .VGA2offset = 0x1f8, + .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, + }, + { + .symbolrate_low = 5000000, + .symbolrate_high = 14999999, + .VCAslope = 0x1f, + .VCAoffset = 0x1f, + .VGA1offset = 0x1e0, + .VGA2offset = 0x180, + .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, + }, + { + .symbolrate_low = 15000000, + .symbolrate_high = 45000000, + .VCAslope = 0x3f, + .VCAoffset = 0x3f, + .VGA1offset = 0x180, + .VGA2offset = 0x100, + .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, + }, +}; + +/* + * Various tuner defaults need to be established for a given frequency kHz. + * fixme: The bounds on the bands do not match the doc in real life. + * fixme: Some of them have been moved, other might need adjustment. + */ +static struct +{ + u32 freq_low; + u32 freq_high; + u32 bandselect; + u32 VCOdivider; + u32 VCOnumber; + u32 progdata; +} cx24123_bandselect_vals[] = +{ + { + .freq_low = 950000, + .freq_high = 1018999, + .bandselect = 0x40, + .VCOdivider = 4, + .VCOnumber = 7, + .progdata = (0 << 18) | (0 << 9) | 0x40, + }, + { + .freq_low = 1019000, + .freq_high = 1074999, + .bandselect = 0x80, + .VCOdivider = 4, + .VCOnumber = 8, + .progdata = (0 << 18) | (0 << 9) | 0x80, + }, + { + .freq_low = 1075000, + .freq_high = 1227999, + .bandselect = 0x01, + .VCOdivider = 2, + .VCOnumber = 1, + .progdata = (0 << 18) | (1 << 9) | 0x01, + }, + { + .freq_low = 1228000, + .freq_high = 1349999, + .bandselect = 0x02, + .VCOdivider = 2, + .VCOnumber = 2, + .progdata = (0 << 18) | (1 << 9) | 0x02, + }, + { + .freq_low = 1350000, + .freq_high = 1481999, + .bandselect = 0x04, + .VCOdivider = 2, + .VCOnumber = 3, + .progdata = (0 << 18) | (1 << 9) | 0x04, + }, + { + .freq_low = 1482000, + .freq_high = 1595999, + .bandselect = 0x08, + .VCOdivider = 2, + .VCOnumber = 4, + .progdata = (0 << 18) | (1 << 9) | 0x08, + }, + { + .freq_low = 1596000, + .freq_high = 1717999, + .bandselect = 0x10, + .VCOdivider = 2, + .VCOnumber = 5, + .progdata = (0 << 18) | (1 << 9) | 0x10, + }, + { + .freq_low = 1718000, + .freq_high = 1855999, + .bandselect = 0x20, + .VCOdivider = 2, + .VCOnumber = 6, + .progdata = (0 << 18) | (1 << 9) | 0x20, + }, + { + .freq_low = 1856000, + .freq_high = 2035999, + .bandselect = 0x40, + .VCOdivider = 2, + .VCOnumber = 7, + .progdata = (0 << 18) | (1 << 9) | 0x40, + }, + { + .freq_low = 2036000, + .freq_high = 2149999, + .bandselect = 0x80, + .VCOdivider = 2, + .VCOnumber = 8, + .progdata = (0 << 18) | (1 << 9) | 0x80, + }, +}; + static struct { u8 reg; u8 data; @@ -195,9 +337,9 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers val = cx24123_readreg(state, 0x1b) >> 7; if (val == 0) - *inversion=INVERSION_OFF; + *inversion = INVERSION_OFF; else - *inversion=INVERSION_ON; + *inversion = INVERSION_ON; return 0; } @@ -205,12 +347,12 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) { if ( (fec < FEC_NONE) || (fec > FEC_AUTO) ) - fec=FEC_AUTO; + fec = FEC_AUTO; /* Hardware has 5/11 and 3/5 but are never unused */ switch (fec) { case FEC_NONE: - return cx24123_writereg(state, 0x0f,0x01); + return cx24123_writereg(state, 0x0f, 0x01); case FEC_1_2: return cx24123_writereg(state, 0x0f, 0x02); case FEC_2_3: @@ -230,37 +372,41 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) { + int ret; u8 val; - val = cx24123_readreg (state, 0x1b) & 0x07; + ret = cx24123_readreg (state, 0x1b); + if (ret < 0) + return ret; + val = ret & 0x07; switch (val) { case 1: - *fec=FEC_1_2; - return 0; + *fec = FEC_1_2; + break; case 3: - *fec=FEC_2_3; - return 0; + *fec = FEC_2_3; + break; case 4: - *fec=FEC_3_4; - return 0; + *fec = FEC_3_4; + break; case 5: - *fec=FEC_4_5; - return 0; + *fec = FEC_4_5; + break; case 6: - *fec=FEC_5_6; - return 0; + *fec = FEC_5_6; + break; case 7: - *fec=FEC_7_8; - return 0; - case 2: /* *fec=FEC_3_5; return 0; */ - case 0: /* *fec=FEC_5_11; return 0; */ - *fec=FEC_AUTO; - return 0; + *fec = FEC_7_8; + break; + case 2: /* *fec = FEC_3_5; break; */ + case 0: /* *fec = FEC_5_11; break; */ + *fec = FEC_AUTO; + break; default: - *fec=FEC_NONE; return 0; + *fec = FEC_NONE; // can't happen } - return -EREMOTEIO; + return 0; } /* fixme: Symbol rates < 3MSps may not work because of precision loss */ @@ -268,14 +414,14 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) { u32 val; - val = (srate/1185)*100; + val = (srate / 1185) * 100; /* Compensate for scaling up, by removing 17 symbols per 1Msps */ - val = val - (17*(srate / 1000000)); + val = val - (17 * (srate / 1000000)); - cx24123_writereg(state, 0x08, (val >>16) & 0xff ); - cx24123_writereg(state, 0x09, (val >> 8) & 0xff ); - cx24123_writereg(state, 0x0a, (val ) & 0xff ); + cx24123_writereg(state, 0x08, (val >> 16) & 0xff ); + cx24123_writereg(state, 0x09, (val >> 8) & 0xff ); + cx24123_writereg(state, 0x0a, (val ) & 0xff ); return 0; } @@ -287,8 +433,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct cx24123_state *state = fe->demodulator_priv; - u32 ndiv=0, adiv=0, vco_div=0; - int i=0; + u32 ndiv = 0, adiv = 0, vco_div = 0; + int i = 0; /* Defaults for low freq, low rate */ state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; @@ -297,7 +443,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa vco_div = cx24123_bandselect_vals[0].VCOdivider; /* For the given symbolerate, determine the VCA and VGA programming bits */ - for (i=0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) + for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) { if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) && (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) { @@ -307,7 +453,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa } /* For the given frequency, determine the bandselect programming bits */ - for (i=0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) + for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) { if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) { @@ -340,7 +486,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par { struct cx24123_state *state = fe->demodulator_priv; - u8 timeout=0; + u8 timeout = 0; /* align the 21 bytes into to bit23 boundary */ data = data << 3; @@ -348,9 +494,9 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par /* Reset the demod pll word length to 0x15 bits */ cx24123_writereg(state, 0x21, 0x15); - timeout=0; + timeout = 0; /* write the msb 8 bits, wait for the send to be completed */ - cx24123_writereg(state, 0x22, (data>>16) & 0xff); + cx24123_writereg(state, 0x22, (data >> 16) & 0xff); while ( ( cx24123_readreg(state, 0x20) & 0x40 ) == 0 ) { /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ @@ -361,7 +507,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par msleep(500); } - timeout=0; + timeout = 0; /* send another 8 bytes, wait for the send to be completed */ cx24123_writereg(state, 0x22, (data>>8) & 0xff ); while ( (cx24123_readreg(state, 0x20) & 0x40 ) == 0 ) @@ -374,7 +520,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par msleep(500); } - timeout=0; + timeout = 0; /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */ cx24123_writereg(state, 0x22, (data) & 0xff ); while ((cx24123_readreg(state, 0x20) & 0x80)) @@ -398,7 +544,7 @@ static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_paramet { struct cx24123_state *state = fe->demodulator_priv; - if (cx24123_pll_calculate(fe, p)!=0) { + if (cx24123_pll_calculate(fe, p) != 0) { printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); return -EINVAL; } @@ -420,7 +566,7 @@ static int cx24123_initfe(struct dvb_frontend* fe) int i; /* Configure the demod to a good set of defaults */ - for (i=0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++) + for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++) cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data); if (state->config->pll_init) @@ -452,7 +598,7 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage } static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *cmd) + struct dvb_diseqc_master_cmd *cmd) { /* fixme: Implement diseqc */ printk("%s: No support yet\n",__FUNCTION__); @@ -545,7 +691,7 @@ static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par state->config->set_ts_params(fe, 0); state->currentfreq=p->frequency; - state->currentsymbolrate=p->u.qpsk.symbol_rate; + state->currentsymbolrate = p->u.qpsk.symbol_rate; cx24123_set_inversion(state, p->inversion); cx24123_set_fec(state, p->u.qpsk.fec_inner); @@ -553,7 +699,7 @@ static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par cx24123_pll_tune(fe, p); /* Enable automatic aquisition and reset cycle */ - cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07) ); + cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); cx24123_writereg(state, 0x00, 0x10); cx24123_writereg(state, 0x00, 0); @@ -605,7 +751,8 @@ static void cx24123_release(struct dvb_frontend* fe) static struct dvb_frontend_ops cx24123_ops; -struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, struct i2c_adapter* i2c) +struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, + struct i2c_adapter* i2c) { struct cx24123_state* state = NULL; int ret; @@ -691,4 +838,3 @@ MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(cx24123_attach); - diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h index 80b66a695261..a6b85d517578 100644 --- a/drivers/media/dvb/frontends/cx24123.h +++ b/drivers/media/dvb/frontends/cx24123.h @@ -36,150 +36,7 @@ struct cx24123_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -/* Various tuner defaults need to be established for a given symbol rate Sps */ -struct -{ - u32 symbolrate_low; - u32 symbolrate_high; - u32 VCAslope; - u32 VCAoffset; - u32 VGA1offset; - u32 VGA2offset; - u32 VCAprogdata; - u32 VGAprogdata; -} cx24123_AGC_vals[] = -{ - { - .symbolrate_low = 1000000, - .symbolrate_high = 4999999, - .VCAslope = 0x07, - .VCAoffset = 0x0f, - .VGA1offset = 0x1f8, - .VGA2offset = 0x1f8, - .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8, - .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, - }, - { - .symbolrate_low = 5000000, - .symbolrate_high = 14999999, - .VCAslope = 0x1f, - .VCAoffset = 0x1f, - .VGA1offset = 0x1e0, - .VGA2offset = 0x180, - .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, - .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, - }, - { - .symbolrate_low = 15000000, - .symbolrate_high = 45000000, - .VCAslope = 0x3f, - .VCAoffset = 0x3f, - .VGA1offset = 0x180, - .VGA2offset = 0x100, - .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, - .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, - }, -}; - -/* - * Various tuner defaults need to be established for a given frequency kHz. - * fixme: The bounds on the bands do not match the doc in real life. - * fixme: Some of them have been moved, other might need adjustment. - */ -struct -{ - u32 freq_low; - u32 freq_high; - u32 bandselect; - u32 VCOdivider; - u32 VCOnumber; - u32 progdata; -} cx24123_bandselect_vals[] = -{ - { - .freq_low = 950000, - .freq_high = 1018999, - .bandselect = 0x40, - .VCOdivider = 4, - .VCOnumber = 7, - .progdata = (0 << 18) | (0 << 9) | 0x40, - }, - { - .freq_low = 1019000, - .freq_high = 1074999, - .bandselect = 0x80, - .VCOdivider = 4, - .VCOnumber = 8, - .progdata = (0 << 18) | (0 << 9) | 0x80, - }, - { - .freq_low = 1075000, - .freq_high = 1227999, - .bandselect = 0x01, - .VCOdivider = 2, - .VCOnumber = 1, - .progdata = (0 << 18) | (1 << 9) | 0x01, - }, - { - .freq_low = 1228000, - .freq_high = 1349999, - .bandselect = 0x02, - .VCOdivider = 2, - .VCOnumber = 2, - .progdata = (0 << 18) | (1 << 9) | 0x02, - }, - { - .freq_low = 1350000, - .freq_high = 1481999, - .bandselect = 0x04, - .VCOdivider = 2, - .VCOnumber = 3, - .progdata = (0 << 18) | (1 << 9) | 0x04, - }, - { - .freq_low = 1482000, - .freq_high = 1595999, - .bandselect = 0x08, - .VCOdivider = 2, - .VCOnumber = 4, - .progdata = (0 << 18) | (1 << 9) | 0x08, - }, - { - .freq_low = 1596000, - .freq_high = 1717999, - .bandselect = 0x10, - .VCOdivider = 2, - .VCOnumber = 5, - .progdata = (0 << 18) | (1 << 9) | 0x10, - }, - { - .freq_low = 1718000, - .freq_high = 1855999, - .bandselect = 0x20, - .VCOdivider = 2, - .VCOnumber = 6, - .progdata = (0 << 18) | (1 << 9) | 0x20, - }, - { - .freq_low = 1856000, - .freq_high = 2035999, - .bandselect = 0x40, - .VCOdivider = 2, - .VCOnumber = 7, - .progdata = (0 << 18) | (1 << 9) | 0x40, - }, - { - .freq_low = 2036000, - .freq_high = 2149999, - .bandselect = 0x80, - .VCOdivider = 2, - .VCOnumber = 8, - .progdata = (0 << 18) | (1 << 9) | 0x80, - }, -}; - extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, struct i2c_adapter* i2c); #endif /* CX24123_H */ - -- cgit v1.2.3 From 1c956a3ac087b7590296f5a0be2cdab2666158cd Mon Sep 17 00:00:00 2001 From: Vadim Catana Date: Mon, 9 Jan 2006 15:25:08 -0200 Subject: DVB (2451): Add support for KWorld DVB-S 100, based on the same chips as Hauppauge - Add support for KWorld DVB-S 100, based on the same chips as Hauppauge Nova-S Plus (CX23883/CX24123/CX24109), without the Intersil ISL6421, which is used for LNB control. - LNB voltage and tone are controled by LNBDC and LNBTone bits from register 0x29 of the CX24123 demodulator. - The MO_GP0_IO register from CX23883 is used to turn LNB power on and off. Signed-off-by: Vadim Catana Acked-by: Johannes Stezenbach Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24123.c | 98 +++++++++++++++++++++++++++-------- drivers/media/dvb/frontends/cx24123.h | 9 ++++ 2 files changed, 86 insertions(+), 21 deletions(-) diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index cfb7d2edd5a9..3e230fc59cac 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -3,6 +3,8 @@ Copyright (C) 2005 Steven Toth + Support for KWorld DVB-S 100 by Vadim Catana + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -573,7 +575,8 @@ static int cx24123_initfe(struct dvb_frontend* fe) state->config->pll_init(fe); /* Configure the LNB for 14V */ - cx24123_writelnbreg(state, 0x0, 0x2a); + if (state->config->use_isl6421) + cx24123_writelnbreg(state, 0x0, 0x2a); return 0; } @@ -583,18 +586,49 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage struct cx24123_state *state = fe->demodulator_priv; u8 val; - val = cx24123_readlnbreg(state, 0x0); + switch (state->config->use_isl6421) { - switch (voltage) { - case SEC_VOLTAGE_13: - return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ - case SEC_VOLTAGE_18: - return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ - case SEC_VOLTAGE_OFF: - return cx24123_writelnbreg(state, 0x0, val & 0x30); - default: - return -EINVAL; - }; + case 1: + + val = cx24123_readlnbreg(state, 0x0); + + switch (voltage) { + case SEC_VOLTAGE_13: + return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ + case SEC_VOLTAGE_18: + return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ + case SEC_VOLTAGE_OFF: + return cx24123_writelnbreg(state, 0x0, val & 0x30); + default: + return -EINVAL; + }; + + case 0: + + val = cx24123_readreg(state, 0x29); + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("%s: setting voltage 13V\n", __FUNCTION__); + if (state->config->enable_lnb_voltage) + state->config->enable_lnb_voltage(fe, 1); + return cx24123_writereg(state, 0x29, val | 0x80); + case SEC_VOLTAGE_18: + dprintk("%s: setting voltage 18V\n", __FUNCTION__); + if (state->config->enable_lnb_voltage) + state->config->enable_lnb_voltage(fe, 1); + return cx24123_writereg(state, 0x29, val & 0x7f); + case SEC_VOLTAGE_OFF: + dprintk("%s: setting voltage off\n", __FUNCTION__); + if (state->config->enable_lnb_voltage) + state->config->enable_lnb_voltage(fe, 0); + return 0; + default: + return -EINVAL; + }; + } + + return 0; } static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, @@ -729,17 +763,39 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) struct cx24123_state *state = fe->demodulator_priv; u8 val; - val = cx24123_readlnbreg(state, 0x0); + switch (state->config->use_isl6421) { + case 1: + + val = cx24123_readlnbreg(state, 0x0); - switch (tone) { - case SEC_TONE_ON: - return cx24123_writelnbreg(state, 0x0, val | 0x10); - case SEC_TONE_OFF: - return cx24123_writelnbreg(state, 0x0, val & 0x2f); - default: - printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); - return -EINVAL; + switch (tone) { + case SEC_TONE_ON: + return cx24123_writelnbreg(state, 0x0, val | 0x10); + case SEC_TONE_OFF: + return cx24123_writelnbreg(state, 0x0, val & 0x2f); + default: + printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); + return -EINVAL; + } + + case 0: + + val = cx24123_readreg(state, 0x29); + + switch (tone) { + case SEC_TONE_ON: + dprintk("%s: setting tone on\n", __FUNCTION__); + return cx24123_writereg(state, 0x29, val | 0x10); + case SEC_TONE_OFF: + dprintk("%s: setting tone off\n",__FUNCTION__); + return cx24123_writereg(state, 0x29, val & 0xef); + default: + printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); + return -EINVAL; + } } + + return 0; } static void cx24123_release(struct dvb_frontend* fe) diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h index a6b85d517578..0c922b5e9263 100644 --- a/drivers/media/dvb/frontends/cx24123.h +++ b/drivers/media/dvb/frontends/cx24123.h @@ -28,12 +28,21 @@ struct cx24123_config /* the demodulator's i2c address */ u8 demod_address; + /* + cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip + for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits + from register 0x29 of the CX24123 demodulator + */ + int use_isl6421; + /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + + void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on); }; extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, -- cgit v1.2.3 From effa791c22ef2f944b4621c94150e129fe1af28b Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Mon, 9 Jan 2006 15:25:09 -0200 Subject: DVB (2454): Port code for SU1278/SH2 (TUA6100) from pre-refactored code - Port code for SU1278/SH2 (TUA6100) from pre-refactored code Signed-off-by: Andrew de Quincey Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0299.c | 8 ++ drivers/media/dvb/frontends/stv0299.h | 1 + drivers/media/dvb/ttpci/budget-av.c | 156 ++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 177d71d56b67..1085bd15d56d 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len return ret == 2 ? 0 : ret; } +int stv0299_enable_plli2c (struct dvb_frontend* fe) +{ + struct stv0299_state* state = fe->demodulator_priv; + + return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ +} + static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) { dprintk ("%s\n", __FUNCTION__); @@ -717,5 +724,6 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(stv0299_enable_plli2c); EXPORT_SYMBOL(stv0299_writereg); EXPORT_SYMBOL(stv0299_attach); diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 9af3d71c89db..32c87b4c2f13 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -94,6 +94,7 @@ struct stv0299_config }; extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); +extern int stv0299_enable_plli2c (struct dvb_frontend* fe); extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, struct i2c_adapter* i2c); diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 8bc784ab1972..9a33f6d5d923 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -502,6 +502,140 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, return 0; } +#define MIN2(a,b) ((a) < (b) ? (a) : (b)) +#define MIN3(a,b,c) MIN2(MIN2(a,b),c) + +static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct dvb_frontend_parameters *params) +{ + u8 reg0 [2] = { 0x00, 0x00 }; + u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 }; + u8 reg2 [3] = { 0x02, 0x00, 0x00 }; + int _fband; + int first_ZF; + int R, A, N, P, M; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 }; + int freq = params->frequency; + + first_ZF = (freq) / 1000; + + if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) < + abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890)))) + _fband = 2; + else + _fband = 3; + + if (_fband == 2) { + if (((first_ZF >= 950) && (first_ZF < 1350)) || + ((first_ZF >= 1430) && (first_ZF < 1950))) + reg0[1] = 0x07; + else if (((first_ZF >= 1350) && (first_ZF < 1430)) || + ((first_ZF >= 1950) && (first_ZF < 2150))) + reg0[1] = 0x0B; + } + + if(_fband == 3) { + if (((first_ZF >= 950) && (first_ZF < 1350)) || + ((first_ZF >= 1455) && (first_ZF < 1950))) + reg0[1] = 0x07; + else if (((first_ZF >= 1350) && (first_ZF < 1420)) || + ((first_ZF >= 1950) && (first_ZF < 2150))) + reg0[1] = 0x0B; + else if ((first_ZF >= 1420) && (first_ZF < 1455)) + reg0[1] = 0x0F; + } + + if (first_ZF > 1525) + reg1[1] |= 0x80; + else + reg1[1] &= 0x7F; + + if (_fband == 2) { + if (first_ZF > 1430) { /* 1430MHZ */ + reg1[1] &= 0xCF; /* N2 */ + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } else { + reg1[1] &= 0xCF; /* N2 */ + reg1[1] |= 0x20; + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } + } + + if (_fband == 3) { + if ((first_ZF >= 1455) && + (first_ZF < 1630)) { + reg1[1] &= 0xCF; /* N2 */ + reg1[1] |= 0x20; + reg2[1] &= 0xCF; /* R2 */ + } else { + if (first_ZF < 1455) { + reg1[1] &= 0xCF; /* N2 */ + reg1[1] |= 0x20; + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } else { + if (first_ZF >= 1630) { + reg1[1] &= 0xCF; /* N2 */ + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } + } + } + } + + /* set ports, enable P0 for symbol rates > 4Ms/s */ + if (params->u.qpsk.symbol_rate >= 4000000) + reg1[1] |= 0x0c; + else + reg1[1] |= 0x04; + + reg2[1] |= 0x0c; + + R = 64; + A = 64; + P = 64; //32 + + M = (freq * R) / 4; /* in Mhz */ + N = (M - A * 1000) / (P * 1000); + + reg1[1] |= (N >> 9) & 0x03; + reg1[2] = (N >> 1) & 0xff; + reg1[3] = (N << 7) & 0x80; + + reg2[1] |= (R >> 8) & 0x03; + reg2[2] = R & 0xFF; /* R */ + + reg1[3] |= A & 0x7f; /* A */ + + if (P == 64) + reg1[1] |= 0x40; /* Prescaler 64/65 */ + + reg0[1] |= 0x03; + + /* already enabled - do not reenable i2c repeater or TX fails */ + msg.buf = reg0; + msg.len = sizeof(reg0); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + stv0299_enable_plli2c(fe); + msg.buf = reg1; + msg.len = sizeof(reg1); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + stv0299_enable_plli2c(fe); + msg.buf = reg2; + msg.len = sizeof(reg2); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + return 0; +} + static u8 typhoon_cinergy1200s_inittab[] = { 0x01, 0x15, 0x02, 0x30, @@ -571,6 +705,18 @@ static struct stv0299_config cinergy_1200s_config = { .pll_set = philips_su1278_ty_ci_pll_set, }; +static struct stv0299_config cinergy_1200s_1894_0010_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, + .pll_set = philips_su1278sh2_tua6100_pll_set, +}; static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -767,6 +913,15 @@ static void frontend_init(struct budget_av *budget_av) switch (saa->pci->subsystem_device) { case SUBID_DVBS_KNC1: + if (saa->pci->subsystem_vendor == 0x1894) { + fe = stv0299_attach(&cinergy_1200s_1894_0010_config, + &budget_av->budget.i2c_adap); + } else { + fe = stv0299_attach(&typhoon_config, + &budget_av->budget.i2c_adap); + } + break; + case SUBID_DVBS_KNC1_PLUS: case SUBID_DVBS_TYPHOON: fe = stv0299_attach(&typhoon_config, @@ -1021,6 +1176,7 @@ MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), + MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), -- cgit v1.2.3 From 26a0f5db8425fbcbd20e60c924c61592b2c132a6 Mon Sep 17 00:00:00 2001 From: Noone Important Date: Mon, 9 Jan 2006 15:25:09 -0200 Subject: DVB (2390): Adds a time-delay to IR remote button presses for av7110 ir input, - Adds a time-delay to IR remote button presses for av7110_ir input, such that it acts more like a keyboard. A short press will be treated as a single button press. Holding down a button on the remote will respond like holding down a key on the keyboard, and result in a key-repeat. This just introduces a delay between the 1st press, and going into key-repeat so that it is possible to get a single 'up'. Signed-off-by: Noone Important Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110_ir.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index f5e59fc924af..9138132ad25f 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -17,6 +17,8 @@ static int av_cnt; static struct av7110 *av_list[4]; static struct input_dev *input_dev; +static u8 delay_timer_finished; + static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, @@ -112,13 +114,16 @@ static void av7110_emit_key(unsigned long parm) if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); if (keyup_timer.data != keycode || new_toggle != old_toggle) { + delay_timer_finished = 0; input_event(input_dev, EV_KEY, keyup_timer.data, !!0); input_event(input_dev, EV_KEY, keycode, !0); } else - input_event(input_dev, EV_KEY, keycode, 2); - - } else + if (delay_timer_finished) + input_event(input_dev, EV_KEY, keycode, 2); + } else { + delay_timer_finished = 0; input_event(input_dev, EV_KEY, keycode, !0); + } keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.data = keycode; @@ -145,7 +150,8 @@ static void input_register_keys(void) static void input_repeat_key(unsigned long data) { - /* dummy routine to disable autorepeat in the input driver */ + /* called by the input driver after rep[REP_DELAY] ms */ + delay_timer_finished = 1; } -- cgit v1.2.3 From 174329d951e2fe39f779d67e9488b7a7f15df69c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:10 -0200 Subject: V4L/DVB (3062): Fix wrong tuner.h define for tuner 46 - Fix wrong tuner.h define for tuner 46 (it's a Panasonic, not a Microtune). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 2 +- include/media/tuner.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index cf241ab1e1b0..d579e35a1077 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -512,7 +512,7 @@ static struct tunertype tuners[] = { .UHF = 0x30, .config = 0x8e, }, - [TUNER_MICROTUNE_4042_FI5] = { /* Panasonic NTSC */ + [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ .name = "Panasonic VP27s/ENGE4324D", .thresh1= 16 * 160.00 /*MHz*/, .thresh2= 16 * 454.00 /*MHz*/, diff --git a/include/media/tuner.h b/include/media/tuner.h index b28aa17213f5..e224722a7ff7 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -82,9 +82,9 @@ #define TUNER_PHILIPS_FM1236_MK3 43 #define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */ -/* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */ +/* Microtune merged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */ #define TUNER_MICROTUNE_4049FM5 45 -#define TUNER_MICROTUNE_4042_FI5 46 +#define TUNER_PANASONIC_VP27 46 #define TUNER_LG_NTSC_TAPE 47 #define TUNER_TNF_8831BGFF 48 -- cgit v1.2.3 From 14725165dd2e25a54315a2350d332b49635ed6c1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:10 -0200 Subject: V4L/DVB (3064): Some cleanups on msp3400 - Change function order to reduce usage of function prototypes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400.c | 72 ++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 183253e2dd91..64691d553a96 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -157,6 +157,9 @@ struct msp3400c { #define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@') #define HAVE_RADIO(msp) ((msp->rev1 & 0xff) >= 'G'-'@') +/* defined at the end of the source */ +extern struct i2c_client client_template; + #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ /* ---------------------------------------------------------------------- */ @@ -1553,33 +1556,17 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) /* ----------------------------------------------------------------------- */ -static int msp_attach(struct i2c_adapter *adap, int addr, int kind); -static int msp_detach(struct i2c_client *client); -static int msp_probe(struct i2c_adapter *adap); -static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); - -static int msp_suspend(struct device * dev, pm_message_t state); -static int msp_resume(struct device * dev); - -static void msp_wake_thread(struct i2c_client *client); - -static struct i2c_driver driver = { - .id = I2C_DRIVERID_MSP3400, - .attach_adapter = msp_probe, - .detach_client = msp_detach, - .command = msp_command, - .driver = { - .name = "i2c msp3400 driver", - .suspend = msp_suspend, - .resume = msp_resume, - }, -}; - -static struct i2c_client client_template = +static void msp_wake_thread(struct i2c_client *client) { - .name = "(unset)", - .driver = &driver, -}; + struct msp3400c *msp = i2c_get_clientdata(client); + + if (NULL == msp->kthread) + return; + msp3400c_setvolume(client,msp->muted,0,0); + msp->watch_stereo = 0; + msp->restart = 1; + wake_up_interruptible(&msp->wq); +} static int msp_attach(struct i2c_adapter *adap, int addr, int kind) { @@ -1739,18 +1726,6 @@ static int msp_probe(struct i2c_adapter *adap) return 0; } -static void msp_wake_thread(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - - if (NULL == msp->kthread) - return; - msp3400c_setvolume(client,msp->muted,0,0); - msp->watch_stereo = 0; - msp->restart = 1; - wake_up_interruptible(&msp->wq); -} - /* ----------------------------------------------------------------------- */ static int mode_v4l2_to_v4l1(int rxsubchans) @@ -2207,6 +2182,27 @@ static int msp_resume(struct device * dev) /* ----------------------------------------------------------------------- */ +static struct i2c_driver driver = { + .owner = THIS_MODULE, + .name = "msp3400", + .id = I2C_DRIVERID_MSP3400, + .flags = I2C_DF_NOTIFY, + .attach_adapter = msp_probe, + .detach_client = msp_detach, + .command = msp_command, + .driver = { + .suspend = msp_suspend, + .resume = msp_resume, + }, +}; + +static struct i2c_client client_template = +{ + .name = "(unset)", + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, +}; + static int __init msp3400_init_module(void) { return i2c_add_driver(&driver); -- cgit v1.2.3 From 2aeb49b6884c3719eedaa96f0752b9d5e0609fe3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:11 -0200 Subject: V4L/DVB (3065): Fix gcc-4.0.2 compile error in msp3400.c - Fix gcc-4.0.2 compile error in msp3400.c. - msp_attach moved to reduce a prototype. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400.c | 292 ++++++++++++++++++++++++------------------ 1 file changed, 165 insertions(+), 127 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 64691d553a96..fc2896bc42c0 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -157,9 +157,6 @@ struct msp3400c { #define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@') #define HAVE_RADIO(msp) ((msp->rev1 & 0xff) >= 'G'-'@') -/* defined at the end of the source */ -extern struct i2c_client client_template; - #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ /* ---------------------------------------------------------------------- */ @@ -1568,130 +1565,6 @@ static void msp_wake_thread(struct i2c_client *client) wake_up_interruptible(&msp->wq); } -static int msp_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct msp3400c *msp; - struct i2c_client *client = &client_template; - int (*thread_func)(void *data) = NULL; - int i; - - client_template.adapter = adap; - client_template.addr = addr; - - if (-1 == msp3400c_reset(&client_template)) { - msp3400_dbg("no chip found\n"); - return -1; - } - - if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { - kfree(client); - return -ENOMEM; - } - - memset(msp,0,sizeof(struct msp3400c)); - msp->norm = VIDEO_MODE_NTSC; - msp->left = 58880; /* 0db gain */ - msp->right = 58880; /* 0db gain */ - msp->bass = 32768; - msp->treble = 32768; - msp->input = -1; - msp->muted = 0; - msp->i2s_mode = 0; - for (i = 0; i < DFP_COUNT; i++) - msp->dfp_regs[i] = -1; - - i2c_set_clientdata(client, msp); - init_waitqueue_head(&msp->wq); - - if (-1 == msp3400c_reset(client)) { - kfree(msp); - kfree(client); - msp3400_dbg("no chip found\n"); - return -1; - } - - msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e); - if (-1 != msp->rev1) - msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f); - if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { - kfree(msp); - kfree(client); - msp3400_dbg("error while reading chip version\n"); - return -1; - } - msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2); - - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); - - snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", - ((msp->rev1>>4)&0x0f) + '3', - (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@', - ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f); - - msp->opmode = opmode; - if (OPMODE_AUTO == msp->opmode) { - if (HAVE_SIMPLER(msp)) - msp->opmode = OPMODE_SIMPLER; - else if (HAVE_SIMPLE(msp)) - msp->opmode = OPMODE_SIMPLE; - else - msp->opmode = OPMODE_MANUAL; - } - - /* hello world :-) */ - msp3400_info("chip=%s", client->name); - if (HAVE_NICAM(msp)) - printk(" +nicam"); - if (HAVE_SIMPLE(msp)) - printk(" +simple"); - if (HAVE_SIMPLER(msp)) - printk(" +simpler"); - if (HAVE_RADIO(msp)) - printk(" +radio"); - - /* version-specific initialization */ - switch (msp->opmode) { - case OPMODE_MANUAL: - printk(" mode=manual"); - thread_func = msp3400c_thread; - break; - case OPMODE_SIMPLE: - printk(" mode=simple"); - thread_func = msp3410d_thread; - break; - case OPMODE_SIMPLER: - printk(" mode=simpler"); - thread_func = msp34xxg_thread; - break; - } - printk("\n"); - - /* startup control thread if needed */ - if (thread_func) { - msp->kthread = kthread_run(thread_func, client, "msp34xx"); - - if (NULL == msp->kthread) - msp3400_warn("kernel_thread() failed\n"); - msp_wake_thread(client); - } - - /* done */ - i2c_attach_client(client); - - /* update our own array */ - for (i = 0; i < MSP3400_MAX; i++) { - if (NULL == msps[i]) { - msps[i] = client; - break; - } - } - - return 0; -} - static int msp_detach(struct i2c_client *client) { struct msp3400c *msp = i2c_get_clientdata(client); @@ -2182,6 +2055,9 @@ static int msp_resume(struct device * dev) /* ----------------------------------------------------------------------- */ +static int msp_probe(struct i2c_adapter *adap); +static int msp_detach(struct i2c_client *client); + static struct i2c_driver driver = { .owner = THIS_MODULE, .name = "msp3400", @@ -2203,6 +2079,168 @@ static struct i2c_client client_template = .driver = &driver, }; +static int msp_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct msp3400c *msp; + struct i2c_client *client = &client_template; + int (*thread_func)(void *data) = NULL; + int i; + + client_template.adapter = adap; + client_template.addr = addr; + + if (-1 == msp3400c_reset(&client_template)) { + msp3400_dbg("no chip found\n"); + return -1; + } + + if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { + kfree(client); + return -ENOMEM; + } + + memset(msp,0,sizeof(struct msp3400c)); + msp->norm = VIDEO_MODE_NTSC; + msp->left = 58880; /* 0db gain */ + msp->right = 58880; /* 0db gain */ + msp->bass = 32768; + msp->treble = 32768; + msp->input = -1; + msp->muted = 0; + msp->i2s_mode = 0; + for (i = 0; i < DFP_COUNT; i++) + msp->dfp_regs[i] = -1; + + i2c_set_clientdata(client, msp); + init_waitqueue_head(&msp->wq); + + if (-1 == msp3400c_reset(client)) { + kfree(msp); + kfree(client); + msp3400_dbg("no chip found\n"); + return -1; + } + + msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e); + if (-1 != msp->rev1) + msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f); + if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { + kfree(msp); + kfree(client); + msp3400_dbg("error while reading chip version\n"); + return -1; + } + msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2); + + msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + + snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", + ((msp->rev1>>4)&0x0f) + '3', + (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@', + ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f); + + msp->opmode = opmode; + if (OPMODE_AUTO == msp->opmode) { + if (HAVE_SIMPLER(msp)) + msp->opmode = OPMODE_SIMPLER; + else if (HAVE_SIMPLE(msp)) + msp->opmode = OPMODE_SIMPLE; + else + msp->opmode = OPMODE_MANUAL; + } + + /* hello world :-) */ + msp3400_info("chip=%s", client->name); + if (HAVE_NICAM(msp)) + printk(" +nicam"); + if (HAVE_SIMPLE(msp)) + printk(" +simple"); + if (HAVE_SIMPLER(msp)) + printk(" +simpler"); + if (HAVE_RADIO(msp)) + printk(" +radio"); + + /* version-specific initialization */ + switch (msp->opmode) { + case OPMODE_MANUAL: + printk(" mode=manual"); + thread_func = msp3400c_thread; + break; + case OPMODE_SIMPLE: + printk(" mode=simple"); + thread_func = msp3410d_thread; + break; + case OPMODE_SIMPLER: + printk(" mode=simpler"); + thread_func = msp34xxg_thread; + break; + } + printk("\n"); + + /* startup control thread if needed */ + if (thread_func) { + msp->kthread = kthread_run(thread_func, client, "msp34xx"); + + if (NULL == msp->kthread) + msp3400_warn("kernel_thread() failed\n"); + msp_wake_thread(client); + } + + /* done */ + i2c_attach_client(client); + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (NULL == msps[i]) { + msps[i] = client; + break; + } + } + + return 0; +} + +static int msp_detach(struct i2c_client *client) +{ + struct msp3400c *msp = i2c_get_clientdata(client); + int i; + + /* shutdown control thread */ + if (msp->kthread) { + msp->restart = 1; + kthread_stop(msp->kthread); + } + msp3400c_reset(client); + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (client == msps[i]) { + msps[i] = NULL; + break; + } + } + + i2c_detach_client(client); + + kfree(msp); + kfree(client); + return 0; +} + +static int msp_probe(struct i2c_adapter *adap) +{ +#ifdef I2C_CLASS_TV_ANALOG + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, msp_attach); + return 0; +#else + return i2c_probe(adap, &addr_data, msp_attach); +#endif +} + static int __init msp3400_init_module(void) { return i2c_add_driver(&driver); -- cgit v1.2.3 From 5c07db0cb4f537731dba31002f314f3dc270d83f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:11 -0200 Subject: V4L/DVB (3081): added offset parameter for adjusting tuner offset by hand - added offset parameter for adjusting tuner offset by hand Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index d579e35a1077..528e1205da46 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -8,6 +8,10 @@ #include #include +static int offset = 0; +module_param(offset, int, 0666); +MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); + /* ---------------------------------------------------------------------- */ /* tv standard selection for Temic 4046 FM5 @@ -908,7 +912,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) IFPCoff = 623; } - div=freq + IFPCoff; + div=freq + IFPCoff + offset; if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { buffer[0] = tun->config; buffer[1] = config; -- cgit v1.2.3 From f5b90a27ffe25c428329edae5b1ef81e1a8e383f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:12 -0200 Subject: V4L/DVB (3084): Added a new debug msg to help identifying tuner Problems - Added a new debug msg to help identifying tuner Problems Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 528e1205da46..9bd52993d366 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -913,6 +913,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) } div=freq + IFPCoff + offset; + + tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", + freq / 16, freq % 16 * 100 / 16, + IFPCoff / 16, IFPCoff % 16 * 100 / 16, + offset / 16, offset % 16 * 100 / 16, + div); + if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { buffer[0] = tun->config; buffer[1] = config; -- cgit v1.2.3 From 35dc0fefb18eea1b4180a8fafbb83db6a9b7c401 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:12 -0200 Subject: V4L/DVB (3086): vfree(NULL) is legal. - vfree(NULL) is legal. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 5956c35d34ac..4bb779aeff6a 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1745,9 +1745,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); - if (ca->slot_info[i].rx_buffer.data != NULL) { - vfree(ca->slot_info[i].rx_buffer.data); - } + vfree(ca->slot_info[i].rx_buffer.data); } kfree(ca->slot_info); dvb_unregister_device(ca->dvbdev); -- cgit v1.2.3 From 611900c1858747a87657eb405ebab5b1e72bb57c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:12 -0200 Subject: V4L/DVB (3089): Adding support for the Hauppauge HVR1100 and HVR1100-LP products. - Add support for the Hauppauge HVR1100 and HVR1100-LP products. - Add i2c_gate_ctrl callback function to dvb_frontend_ops struct. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 2 + drivers/media/dvb/dvb-core/dvb_frontend.h | 1 + drivers/media/dvb/frontends/cx22702.c | 22 ++++++++--- drivers/media/video/cx88/cx88-cards.c | 63 ++++++++++++++++++++++++++++--- drivers/media/video/cx88/cx88-dvb.c | 17 +++++++++ drivers/media/video/cx88/cx88-i2c.c | 15 +++++++- drivers/media/video/cx88/cx88-input.c | 1 + drivers/media/video/cx88/cx88.h | 5 +++ 8 files changed, 114 insertions(+), 12 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 13ec5e965f41..fa88056dbe85 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -38,3 +38,5 @@ 37 -> Hauppauge Nova-S-Plus DVB-S [0070:9201,0070:9202] 38 -> Hauppauge Nova-SE2 DVB-S [0070:9200] 39 -> KWorld DVB-S 100 [17de:08b2] + 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402] + 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802] diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 48c3f81be912..f40ee4efbe31 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -85,6 +85,7 @@ struct dvb_frontend_ops { int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); + int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); }; #define MAX_EVENT 8 diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 5de0e6d350b1..0fc899f81c5e 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet return 0; } +static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct cx22702_state* state = fe->demodulator_priv; + dprintk ("%s(%d)\n", __FUNCTION__, enable); + if (enable) + return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe); + else + return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1); +} + /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { @@ -202,7 +212,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet struct cx22702_state* state = fe->demodulator_priv; /* set PLL */ - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + cx22702_i2c_gate_ctrl(fe, 1); if (state->config->pll_set) { state->config->pll_set(fe, p); } else if (state->config->pll_desc) { @@ -216,7 +226,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet } else { BUG(); } - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); + cx22702_i2c_gate_ctrl(fe, 0); /* set inversion */ cx22702_set_inversion (state, p->inversion); @@ -349,11 +359,10 @@ static int cx22702_init (struct dvb_frontend* fe) cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); /* init PLL */ - if (state->config->pll_init) { - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe); + if (state->config->pll_init) state->config->pll_init(fe); - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); - } + + cx22702_i2c_gate_ctrl(fe, 0); return 0; } @@ -531,6 +540,7 @@ static struct dvb_frontend_ops cx22702_ops = { .read_signal_strength = cx22702_read_signal_strength, .read_snr = cx22702_read_snr, .read_ucblocks = cx22702_read_ucblocks, + .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, }; module_param(debug, int, 0644); diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index fd173e6ac605..b4fd1ef007ea 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -903,7 +903,6 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* fixme: add the analog gpio stuff here */ .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, @@ -946,6 +945,43 @@ struct cx88_board cx88_boards[] = { }}, .dvb = 1, }, + [CX88_BOARD_HAUPPAUGE_HVR1100] = { + .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + }}, + /* fixme: Add radio support */ + .dvb = 1, + }, + [CX88_BOARD_HAUPPAUGE_HVR1100LP] = { + .name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + }}, + /* fixme: Add radio support */ + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1109,6 +1145,22 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x17de, .subdevice = 0x08b2, .card = CX88_BOARD_KWORLD_DVBS_100, + },{ + .subvendor = 0x0070, + .subdevice = 0x9400, + .card = CX88_BOARD_HAUPPAUGE_HVR1100, + },{ + .subvendor = 0x0070, + .subdevice = 0x9402, + .card = CX88_BOARD_HAUPPAUGE_HVR1100, + },{ + .subvendor = 0x0070, + .subdevice = 0x9800, + .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, + },{ + .subvendor = 0x0070, + .subdevice = 0x9802, + .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1140,9 +1192,6 @@ static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) core->name, core->tuner_type, eeprom_data[0]); } - -/* ----------------------------------------------------------------------- */ - static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) { struct tveeprom tv; @@ -1161,7 +1210,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) case 90500: /* Nova-T-PCI (oem) */ case 90501: /* Nova-T-PCI (oem/IR) */ case 92000: /* Nova-SE2 (OEM, No Video or IR) */ - + case 94009: /* WinTV-HVR1100 (Video and IR Retail) */ + case 94501: /* WinTV-HVR1100 (Video and IR OEM) */ + case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */ /* known */ break; default: @@ -1279,6 +1330,8 @@ void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: case CX88_BOARD_HAUPPAUGE_DVB_T1: + case CX88_BOARD_HAUPPAUGE_HVR1100: + case CX88_BOARD_HAUPPAUGE_HVR1100LP: if (0 == core->i2c_rc) hauppauge_eeprom(core,eeprom); break; diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 054094e48fc3..c4551d996119 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -191,6 +191,12 @@ static struct cx22702_config hauppauge_novat_config = { .pll_address = 0x61, .pll_desc = &dvb_pll_thomson_dtt759x, }; +static struct cx22702_config hauppauge_hvr1100_config = { + .demod_address = 0x63, + .output_mode = CX22702_SERIAL_OUTPUT, + .pll_address = 0x61, + .pll_desc = &dvb_pll_fmd1216me, +}; #endif #ifdef HAVE_OR51132 @@ -370,6 +376,11 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, &dev->core->i2c_adap); break; + case CX88_BOARD_HAUPPAUGE_HVR1100: + case CX88_BOARD_HAUPPAUGE_HVR1100LP: + dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config, + &dev->core->i2c_adap); + break; #endif #ifdef HAVE_MT352 case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: @@ -532,6 +543,9 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, err = dvb_register(dev); if (0 != err) goto fail_fini; + + /* Maintain a reference to cx88-video can query the 8802 device. */ + core->dvbdev = dev; return 0; fail_fini: @@ -547,6 +561,9 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); + /* Destroy any 8802 reference. */ + dev->core->dvbdev = NULL; + /* dvb */ videobuf_dvb_unregister(&dev->dvb); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 4a8fb161b16a..7363dd6e66e2 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -135,7 +135,20 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) { if (0 != core->i2c_rc) return; - i2c_clients_command(&core->i2c_adap, cmd, arg); + + if (core->dvbdev == NULL) { + i2c_clients_command(&core->i2c_adap, cmd, arg); + } else { + + if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl) + core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); + + i2c_clients_command(&core->i2c_adap, cmd, arg); + + if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl) + core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0); + } + } static struct i2c_algo_bit_data cx8800_i2c_algo_template = { diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index d7e9813384d8..a89bb2b195f3 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -390,6 +390,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_DVB_T1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: + case CX88_BOARD_HAUPPAUGE_HVR1100: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 11dc0335151c..3e2bcd241a27 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -182,6 +182,8 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37 #define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38 #define CX88_BOARD_KWORLD_DVBS_100 39 +#define CX88_BOARD_HAUPPAUGE_HVR1100 40 +#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -304,6 +306,9 @@ struct cx88_core { /* various v4l controls */ u32 freq; + + /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ + struct cx8802_dev *dvbdev; }; struct cx8800_dev; -- cgit v1.2.3 From bcb17c421e8fa20d31a0b4a60686908b6d469ce7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:13 -0200 Subject: V4L/DVB (3090): Cleanup check for dvb. - Cleanup check for dvb. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-i2c.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 7363dd6e66e2..c6492089ee1a 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -136,10 +136,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) if (0 != core->i2c_rc) return; - if (core->dvbdev == NULL) { - i2c_clients_command(&core->i2c_adap, cmd, arg); - } else { - + if (core->dvbdev) { if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl) core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); @@ -147,8 +144,8 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl) core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0); - } - + } else + i2c_clients_command(&core->i2c_adap, cmd, arg); } static struct i2c_algo_bit_data cx8800_i2c_algo_template = { -- cgit v1.2.3 From c432a072b6b597c7af138f2fee337d79261b44f4 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:13 -0200 Subject: V4L/DVB (3092): Add support for another Nova-T-PCI PCI subdevice 0x9001 - Add support for another Nova-T-PCI PCI subdevice 0x9001 Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 2 +- drivers/media/video/cx88/cx88-cards.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index fa88056dbe85..bb93a0a1871c 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -16,7 +16,7 @@ 15 -> DViCO FusionHDTV DVB-T1 [18ac:db00] 16 -> KWorld LTV883RF 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810] - 18 -> Hauppauge Nova-T DVB-T [0070:9002] + 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001] 19 -> Conexant DVB-T reference design [14f1:0187] 20 -> Provideo PV259 [1540:2580] 21 -> DViCO FusionHDTV DVB-T Plus [18ac:db10] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index b4fd1ef007ea..c95438abcd7b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1161,6 +1161,10 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x9802, .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, + },{ + .subvendor = 0x0070, + .subdevice = 0x9001, + .card = CX88_BOARD_HAUPPAUGE_DVB_T1, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); -- cgit v1.2.3 From c0477ad9feca01bd8eff95d7482c33753d05c700 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:14 -0200 Subject: V4L/DVB (3099): Fixed device controls for em28xx on WinTV USB2 devices - Controls now come from video and audio decoder driver for msp3400 and tvp5150. - Added audio and sound controls as provided by msp3400 and tvp5150. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 161 +++++++++++++++++++++++------- drivers/media/video/msp3400.c | 159 +++++++++++++++++++++++++++++ drivers/media/video/tvp5150.c | 81 ++++++++------- 3 files changed, 327 insertions(+), 74 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 8516ec12836e..446ba3b2ac36 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -32,6 +32,7 @@ #include "em28xx.h" #include +#include #define DRIVER_AUTHOR "Ludovico Cavedon , " \ "Markus Rechberger , " \ @@ -106,7 +107,31 @@ static const unsigned char saa7114_i2c_init[] = { #define TVNORMS ARRAY_SIZE(tvnorms) /* supported controls */ +/* Common to all boards */ static struct v4l2_queryctrl em28xx_qctrl[] = { + { + .id = V4L2_CID_AUDIO_VOLUME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Volume", + .minimum = 0x0, + .maximum = 0x1f, + .step = 0x1, + .default_value = 0x1f, + .flags = 0, + },{ + .id = V4L2_CID_AUDIO_MUTE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + } +}; + +/* FIXME: These are specific to saa711x - should be moved to its code */ +static struct v4l2_queryctrl saa711x_qctrl[] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -134,24 +159,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { .step = 0x1, .default_value = 0x10, .flags = 0, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Volume", - .minimum = 0x0, - .maximum = 0x1f, - .step = 0x1, - .default_value = 0x1f, - .flags = 0, - },{ - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = 0, },{ .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { .step = 0x1, .default_value = 0x20, .flags = 0, - } + } }; static struct usb_driver em28xx_usb_driver; @@ -674,7 +681,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) */ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) { - s32 tmp; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = dev->mute; @@ -682,6 +688,16 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) case V4L2_CID_AUDIO_VOLUME: ctrl->value = dev->volume; return 0; + default: + return -EINVAL; + } +} + +/*FIXME: should be moved to saa711x */ +static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) +{ + s32 tmp; + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: if ((tmp = em28xx_brightness_get(dev)) < 0) return -EIO; @@ -731,6 +747,15 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) case V4L2_CID_AUDIO_VOLUME: dev->volume = ctrl->value; return em28xx_audio_analog_set(dev); + default: + return -EINVAL; + } +} + +/*FIXME: should be moved to saa711x */ +static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) +{ + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: return em28xx_brightness_set(dev, ctrl->value); case V4L2_CID_CONTRAST: @@ -994,14 +1019,34 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; - u8 i, n; - n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]); - for (i = 0; i < n; i++) - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), + int i, id=qc->id; + + memset(qc,0,sizeof(*qc)); + qc->id=id; + + if (!dev->has_msp34xx) { + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), + sizeof(*qc)); + return 0; + } + } + } + if (dev->decoder == EM28XX_TVP5150) { + em28xx_i2c_call_clients(dev,cmd,qc); + if (qc->type) + return 0; + else + return -EINVAL; + } + for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { + if (qc->id && qc->id == saa711x_qctrl[i].id) { + memcpy(qc, &(saa711x_qctrl[i]), sizeof(*qc)); return 0; } + } return -EINVAL; } @@ -1009,29 +1054,66 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; + int retval=-EINVAL; + if (!dev->has_msp34xx) + retval=em28xx_get_ctrl(dev, ctrl); + if (retval==-EINVAL) { + if (dev->decoder == EM28XX_TVP5150) { + em28xx_i2c_call_clients(dev,cmd,arg); + return 0; + } - return em28xx_get_ctrl(dev, ctrl); + return saa711x_get_ctrl(dev, ctrl); + } else return retval; } - case VIDIOC_S_CTRL_OLD: /* ??? */ case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; - u8 i, n; - + u8 i; + + if (!dev->has_msp34xx){ + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (ctrl->id == em28xx_qctrl[i].id) { + if (ctrl->value < + em28xx_qctrl[i].minimum + || ctrl->value > + em28xx_qctrl[i].maximum) + return -ERANGE; + return em28xx_set_ctrl(dev, ctrl); + } + } + } - n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]); - for (i = 0; i < n; i++) - if (ctrl->id == em28xx_qctrl[i].id) { - if (ctrl->value < - em28xx_qctrl[i].minimum - || ctrl->value > - em28xx_qctrl[i].maximum) - return -ERANGE; + if (dev->decoder == EM28XX_TVP5150) { + em28xx_i2c_call_clients(dev,cmd,arg); + return 0; + } else { - return em28xx_set_ctrl(dev, ctrl); + if (!dev->has_msp34xx){ + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (ctrl->id == em28xx_qctrl[i].id) { + if (ctrl->value < + em28xx_qctrl[i].minimum + || ctrl->value > + em28xx_qctrl[i].maximum) + return -ERANGE; + return em28xx_set_ctrl(dev, ctrl); + } + } + for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { + if (ctrl->id == saa711x_qctrl[i].id) { + if (ctrl->value < + saa711x_qctrl[i].minimum + || ctrl->value > + saa711x_qctrl[i].maximum) + return -ERANGE; + return saa711x_set_ctrl(dev, ctrl); + } } + } + return -EINVAL; } @@ -1850,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) struct em28xx *dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); +/*FIXME: IR should be disconnected */ + if (!dev) return; + down_write(&em28xx_disconnect); down(&dev->lock); diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index fc2896bc42c0..8d47d7894248 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -1642,6 +1642,45 @@ static void msp_any_detect_stereo(struct i2c_client *client) } } +static struct v4l2_queryctrl msp34xx_qctrl[] = { + { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 58880, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_AUDIO_BASS, + .name = "Bass", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_TREBLE, + .name = "Treble", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + }, +}; + + static void msp_any_set_audmode(struct i2c_client *client, int audmode) { struct msp3400c *msp = i2c_get_clientdata(client); @@ -1658,6 +1697,95 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode) } } +static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct msp3400c *msp = i2c_get_clientdata(client); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = msp->muted; + return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume = MAX(msp->left, msp->right); + + ctrl->value = (32768 * MIN(msp->left, msp->right)) / + (volume ? volume : 1); + ctrl->value = (msp->left < msp->right) ? + (65535 - ctrl->value) : ctrl->value; + if (0 == volume) + ctrl->value = 32768; + return 0; + } + case V4L2_CID_AUDIO_BASS: + ctrl->value = msp->bass; + return 0; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = msp->treble; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = MAX(msp->left, msp->right); + return 0; + default: + return -EINVAL; + } +} + +static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct msp3400c *msp = i2c_get_clientdata(client); + int set_volume=0, balance, volume; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value>=0 && ctrl->value<2) + msp->muted = ctrl->value; + else + return -ERANGE; + + msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + return 0; + case V4L2_CID_AUDIO_BALANCE: + balance=ctrl->value; + volume = MAX(msp->left, msp->right); + set_volume=1; + break; + case V4L2_CID_AUDIO_BASS: + msp->bass=ctrl->value; + msp3400c_setbass(client, msp->bass); + return 0; + case V4L2_CID_AUDIO_TREBLE: + msp->treble=ctrl->value; + msp3400c_settreble(client, msp->treble); + return 0; + case V4L2_CID_AUDIO_VOLUME: + volume = MAX(msp->left, msp->right); + + balance = (32768 * MIN(msp->left, msp->right)) / + (volume ? volume : 1); + balance = (msp->left < msp->right) ? + (65535 - balance) : balance; + if (0 == volume) + balance = 32768; + + volume=ctrl->value; + set_volume=1; + break; + default: + return -EINVAL; + } + + if (set_volume) { + msp->left = (MIN(65536 - balance, 32768) * volume) / 32768; + msp->right = (MIN(balance, 32768) * volume) / 32768; + + msp3400_dbg("volume=%d, balance=%d, left=%d, right=%d", + volume,balance,msp->left,msp->right); + + msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + } + return 0; +} static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -2027,6 +2155,37 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + msp3400_dbg("VIDIOC_QUERYCTRL"); + + for (i = 0; i < ARRAY_SIZE(msp34xx_qctrl); i++) + if (qc->id && qc->id == msp34xx_qctrl[i].id) { + memcpy(qc, &(msp34xx_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + msp3400_dbg("VIDIOC_G_CTRL\n"); + + return msp_get_ctrl(client, ctrl); + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl = arg; + + msp3400_dbg("VIDIOC_S_CTRL\n"); + + return msp_set_ctrl(client, ctrl); + } default: /* nothing */ diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index a60442ea4f94..d62b2302af49 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -37,24 +37,24 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); /* supported controls */ static struct v4l2_queryctrl tvp5150_qctrl[] = { { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0, - .flags = 0, - }, { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 0x10, - .flags = 0, - }, { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 0x1, + .default_value = 0x10, + .flags = 0, + }, { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Saturation", @@ -63,16 +63,16 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = { .step = 0x1, .default_value = 0x10, .flags = 0, - }, { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 0x1, - .default_value = 0x10, - .flags = 0, - } + }, { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 0x1, + .default_value = 0x10, + .flags = 0, + } }; struct tvp5150 { @@ -437,11 +437,24 @@ enum tvp5150_input { static inline void tvp5150_selmux(struct i2c_client *c, enum tvp5150_input input) { + int opmode=0; + struct tvp5150 *decoder = i2c_get_clientdata(c); if (!decoder->enable) input |= TVP5150_BLACK_SCREEN; + switch (input) { + case TVP5150_ANALOG_CH0: + case TVP5150_ANALOG_CH1: + opmode=0x30; /* TV Mode */ + break; + default: + opmode=0; /* Auto Mode */ + break; + } + + tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode); tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input); }; @@ -498,9 +511,8 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) case V4L2_CID_HUE: ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL); return 0; - default: - return -EINVAL; } + return -EINVAL; } static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) @@ -520,9 +532,8 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) case V4L2_CID_HUE: tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value); return 0; - default: - return -EINVAL; } + return -EINVAL; } /**************************************************************************** @@ -627,12 +638,11 @@ static int tvp5150_command(struct i2c_client *client, case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; - u8 i, n; + int i; dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL"); - n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]); - for (i = 0; i < n; i++) + for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++) if (qc->id && qc->id == tvp5150_qctrl[i].id) { memcpy(qc, &(tvp5150_qctrl[i]), sizeof(*qc)); @@ -648,7 +658,6 @@ static int tvp5150_command(struct i2c_client *client, return tvp5150_get_ctrl(client, ctrl); } - case VIDIOC_S_CTRL_OLD: /* ??? */ case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; -- cgit v1.2.3 From 7865c44d8ae832d6fb6522862268c7bd7814fd44 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:14 -0200 Subject: V4L/DVB (3100): fix compile error, remove dead code and volume scaling - Fix compile error (missing '}') in em28xx-video.c. Remove dead code and volume scaling from msp3400.c. Volume scaling does not belong there, it should be done in the driver for the card that uses the msp3400 if needed, not in the msp3400.c source. The volume scaling code gave problems with the ivtv driver which does not need to do any scaling. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 4 +--- drivers/media/video/msp3400.c | 21 +-------------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 446ba3b2ac36..5e831fccf3fd 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1089,9 +1089,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, if (dev->decoder == EM28XX_TVP5150) { em28xx_i2c_call_clients(dev,cmd,arg); return 0; - } else { - - if (!dev->has_msp34xx){ + } else if (!dev->has_msp34xx) { for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { if (ctrl->id == em28xx_qctrl[i].id) { if (ctrl->value < diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 8d47d7894248..6cff06a7eab7 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -473,10 +473,8 @@ static void msp3400c_setvolume(struct i2c_client *client, int vol = 0, val = 0, balance = 0; if (!muted) { - /* 0x7f instead if 0x73 here has sound quality issues, - * probably due to overmodulation + clipping ... */ vol = (left > right) ? left : right; - val = (vol * 0x73 / 65535) << 8; + val = (vol * 0x7f / 65535) << 8; } if (vol > 0) { balance = ((right - left) * 127) / vol; @@ -2351,21 +2349,12 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) /* done */ i2c_attach_client(client); - /* update our own array */ - for (i = 0; i < MSP3400_MAX; i++) { - if (NULL == msps[i]) { - msps[i] = client; - break; - } - } - return 0; } static int msp_detach(struct i2c_client *client) { struct msp3400c *msp = i2c_get_clientdata(client); - int i; /* shutdown control thread */ if (msp->kthread) { @@ -2374,14 +2363,6 @@ static int msp_detach(struct i2c_client *client) } msp3400c_reset(client); - /* update our own array */ - for (i = 0; i < MSP3400_MAX; i++) { - if (client == msps[i]) { - msps[i] = NULL; - break; - } - } - i2c_detach_client(client); kfree(msp); -- cgit v1.2.3 From cd43c3f60b73512744bb22fe27a266f611466827 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:15 -0200 Subject: V4L/DVB (3103): Add VIDIOC_LOG_STATUS to tuner-core.c - Mark tda9887.c status log values as hexadecimal (add 0x prefix). Add VIDIOC_LOG_STATUS support to tuner-core.c. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 2 +- drivers/media/video/tuner-core.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 93bf10436b82..ae4029a07449 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -796,7 +796,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: { - tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]); + tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]); break; } default: diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index c13c7b95ef35..ae76113886fd 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -475,6 +475,38 @@ static inline int check_v4l2(struct tuner *t) return 0; } +static void tuner_status(struct i2c_client *client) +{ + struct tuner *t = i2c_get_clientdata(client); + unsigned long freq, freq_fraction; + const char *p; + + switch (t->mode) { + case V4L2_TUNER_RADIO: p = "radio"; break; + case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break; + case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break; + default: p = "undefined"; break; + } + if (t->mode == V4L2_TUNER_RADIO) { + freq = t->freq / 16000; + freq_fraction = (t->freq % 16000) * 100 / 16000; + } else { + freq = t->freq / 16; + freq_fraction = (t->freq % 16) * 100 / 16; + } + tuner_info("Tuner mode: %s\n", p); + tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); + tuner_info("Standard: 0x%08llx\n", t->std); + if (t->mode == V4L2_TUNER_RADIO) { + if (t->has_signal) { + tuner_info("Signal strength: %d\n", t->has_signal(client)); + } + if (t->is_stereo) { + tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); + } + } +} + static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); @@ -708,6 +740,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) } break; } + case VIDIOC_LOG_STATUS: + tuner_status(client); + break; default: tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n", cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd), -- cgit v1.2.3 From ade0836c8c3bf72edafd18d3256c4fd874a8236f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:15 -0200 Subject: V4L/DVB (3104): MSP3400 miscelaneous fixes - Removes obsoleted stuff - Reorders some stuff to make it clearer to read - Clears some debug messages Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400.c | 76 ++++++++++++------------------------------- 1 file changed, 20 insertions(+), 56 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 6cff06a7eab7..546e3f0067fe 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -53,9 +52,26 @@ #include #include +#include #include #include "msp3400.h" +/* ---------------------------------------------------------------------- */ + +#define I2C_MSP3400C 0x80 +#define I2C_MSP3400C_ALT 0x88 + +#define I2C_MSP3400C_DEM 0x10 +#define I2C_MSP3400C_DFP 0x12 + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + I2C_MSP3400C >> 1, + I2C_MSP3400C_ALT >> 1, + I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; + #define msp3400_dbg(fmt, arg...) \ do { \ if (debug) \ @@ -180,21 +196,6 @@ MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Defau MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); -/* ---------------------------------------------------------------------- */ - -#define I2C_MSP3400C 0x80 -#define I2C_MSP3400C_ALT 0x88 - -#define I2C_MSP3400C_DEM 0x10 -#define I2C_MSP3400C_DFP 0x12 - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { - I2C_MSP3400C >> 1, - I2C_MSP3400C_ALT >> 1, - I2C_CLIENT_END -}; -I2C_CLIENT_INSMOD; MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); MODULE_AUTHOR("Gerd Knorr"); @@ -713,8 +714,6 @@ msp3400c_print_mode(struct i2c_client *client) } } -#define MSP3400_MAX 4 -static struct i2c_client *msps[MSP3400_MAX]; static void msp3400c_restore_dfp(struct i2c_client *client) { struct msp3400c *msp = i2c_get_clientdata(client); @@ -1563,40 +1562,6 @@ static void msp_wake_thread(struct i2c_client *client) wake_up_interruptible(&msp->wq); } -static int msp_detach(struct i2c_client *client) -{ - struct msp3400c *msp = i2c_get_clientdata(client); - int i; - - /* shutdown control thread */ - if (msp->kthread) { - msp->restart = 1; - kthread_stop(msp->kthread); - } - msp3400c_reset(client); - - /* update our own array */ - for (i = 0; i < MSP3400_MAX; i++) { - if (client == msps[i]) { - msps[i] = NULL; - break; - } - } - - i2c_detach_client(client); - - kfree(msp); - kfree(client); - return 0; -} - -static int msp_probe(struct i2c_adapter *adap) -{ - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, msp_attach); - return 0; -} - /* ----------------------------------------------------------------------- */ static int mode_v4l2_to_v4l1(int rxsubchans) @@ -2147,8 +2112,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) else msp->i2s_mode=0; } - msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n", - a->index,msp->i2s_mode); + msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",a->index,msp->i2s_mode); msp3400c_set_scart(client,msp->in_scart,a->index+1); break; @@ -2196,7 +2160,7 @@ static int msp_suspend(struct device * dev, pm_message_t state) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); - msp3400_dbg("msp34xx: suspend\n"); + msp3400_dbg("suspend\n"); msp3400c_reset(client); return 0; } @@ -2205,7 +2169,7 @@ static int msp_resume(struct device * dev) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); - msp3400_dbg("msp34xx: resume\n"); + msp3400_dbg("resume\n"); msp_wake_thread(client); return 0; } -- cgit v1.2.3 From 39e8f40da20a803a17e16304e73fd31050b1871c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:16 -0200 Subject: V4L/DVB (3105): Remove AUDC_CONFIG_PINNACLE horror, fix mt20xx radio support. - Remove AUDC_CONFIG_PINNACLE horror. This also fixes radio support for mt20xx tuners. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-cards.c | 18 +++++++++++------ drivers/media/video/bttv-driver.c | 1 - drivers/media/video/bttvp.h | 2 +- drivers/media/video/mt20xx.c | 7 +++++++ drivers/media/video/tda9887.c | 41 --------------------------------------- drivers/media/video/tuner-core.c | 13 ------------- include/media/audiochip.h | 11 ----------- 7 files changed, 20 insertions(+), 73 deletions(-) diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 80bcbc4ea3a4..c94092351b79 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -3056,26 +3056,33 @@ static void miro_pinnacle_gpio(struct bttv *btv) switch (id) { case 1: info = "PAL / mono"; + btv->tda9887_conf = TDA9887_INTERCARRIER; break; case 2: info = "PAL+SECAM / stereo"; btv->has_radio = 1; + btv->tda9887_conf = TDA9887_QSS; break; case 3: info = "NTSC / stereo"; btv->has_radio = 1; + btv->tda9887_conf = TDA9887_QSS; break; case 4: info = "PAL+SECAM / mono"; + btv->tda9887_conf = TDA9887_QSS; break; case 5: info = "NTSC / mono"; + btv->tda9887_conf = TDA9887_INTERCARRIER; break; case 6: info = "NTSC / stereo"; + btv->tda9887_conf = TDA9887_INTERCARRIER; break; case 7: info = "PAL / stereo"; + btv->tda9887_conf = TDA9887_INTERCARRIER; break; default: info = "oops: unknown card"; @@ -3086,8 +3093,7 @@ static void miro_pinnacle_gpio(struct bttv *btv) printk(KERN_INFO "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); - btv->tuner_type = 33; - btv->pinnacle_id = id; + btv->tuner_type = TUNER_MT2032; } } @@ -3389,9 +3395,9 @@ void __devinit bttv_init_card2(struct bttv *btv) bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup); } - if (btv->pinnacle_id != UNSET) { - bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE, - &btv->pinnacle_id); + if (btv->tda9887_conf) { + bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG, + &btv->tda9887_conf); } btv->svhs = bttv_tvcards[btv->c.type].svhs; @@ -3443,7 +3449,7 @@ void __devinit bttv_init_card2(struct bttv *btv) /* tuner modules */ tda9887 = 0; - if (btv->pinnacle_id != UNSET) + if (btv->tda9887_conf) tda9887 = 1; if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb && bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 03f925724ce9..39e9178e599e 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3947,7 +3947,6 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->i2c_rc = -1; btv->tuner_type = UNSET; - btv->pinnacle_id = UNSET; btv->new_input = UNSET; btv->has_radio=radio[btv->c.nr]; diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 1e6a5632c3c7..d04d02385349 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -270,7 +270,7 @@ struct bttv { /* card configuration info */ unsigned int cardid; /* pci subsystem id (bt878 based ones) */ unsigned int tuner_type; /* tuner chip type */ - unsigned int pinnacle_id; + unsigned int tda9887_conf; unsigned int svhs; struct bttv_pll_info pll; int triton1; diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 2180018f06de..e2df722ebaeb 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -494,6 +494,13 @@ int microtune_init(struct i2c_client *c) t->tv_freq = NULL; t->radio_freq = NULL; t->standby = NULL; + if (t->std & V4L2_STD_525_60) { + tuner_dbg("pinnacle ntsc\n"); + t->radio_if2 = 41300 * 1000; + } else { + tuner_dbg("pinnacle pal\n"); + t->radio_if2 = 33300 * 1000; + } name = "unknown"; i2c_master_send(c,buf,1); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index ae4029a07449..ceaa29975c8e 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -57,7 +57,6 @@ struct tda9887 { v4l2_std_id std; enum tuner_mode mode; unsigned int config; - unsigned int pinnacle_id; unsigned int using_v4l2; unsigned int radio_mode; unsigned char data[4]; @@ -481,34 +480,6 @@ static int tda9887_set_config(struct tda9887 *t, char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_set_pinnacle(struct tda9887 *t, char *buf) -{ - unsigned int bCarrierMode = UNSET; - - if (t->std & V4L2_STD_625_50) { - if ((1 == t->pinnacle_id) || (7 == t->pinnacle_id)) { - bCarrierMode = cIntercarrier; - } else { - bCarrierMode = cQSS; - } - } - if (t->std & V4L2_STD_525_60) { - if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) { - bCarrierMode = cIntercarrier; - } else { - bCarrierMode = cQSS; - } - } - - if (bCarrierMode != UNSET) { - buf[1] &= ~0x04; - buf[1] |= bCarrierMode; - } - return 0; -} - -/* ---------------------------------------------------------------------- */ - static char pal[] = "-"; module_param_string(pal, pal, sizeof(pal), 0644); static char secam[] = "-"; @@ -593,9 +564,6 @@ static int tda9887_configure(struct tda9887 *t) t->data[1] |= cOutputPort1Inactive; t->data[1] |= cOutputPort2Inactive; - if (UNSET != t->pinnacle_id) { - tda9887_set_pinnacle(t,t->data); - } tda9887_set_config(t,t->data); tda9887_set_insmod(t,t->data); @@ -634,7 +602,6 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) t->client = client_template; t->std = 0; - t->pinnacle_id = UNSET; t->radio_mode = V4L2_TUNER_MODE_STEREO; tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name); @@ -698,14 +665,6 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) tda9887_configure(t); break; } - case AUDC_CONFIG_PINNACLE: - { - int *i = arg; - - t->pinnacle_id = *i; - tda9887_configure(t); - break; - } case TDA9887_SET_CONFIG: { int *i = arg; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index ae76113886fd..c8ff849e8903 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -510,7 +510,6 @@ static void tuner_status(struct i2c_client *client) static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); - unsigned int *iarg = (int *)arg; switch (cmd) { /* --- configuration --- */ @@ -533,18 +532,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) t->standby (client); break; } - case AUDC_CONFIG_PINNACLE: - switch (*iarg) { - case 2: - tuner_dbg("pinnacle pal\n"); - t->radio_if2 = 33300 * 1000; - break; - case 3: - tuner_dbg("pinnacle ntsc\n"); - t->radio_if2 = 41300 * 1000; - break; - } - break; case VIDIOCSAUDIO: if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) return 0; diff --git a/include/media/audiochip.h b/include/media/audiochip.h index b7d4b0930408..411f09fc4574 100644 --- a/include/media/audiochip.h +++ b/include/media/audiochip.h @@ -40,15 +40,4 @@ enum audiochip { #define AUDIO_MUTE 0x80 #define AUDIO_UNMUTE 0x81 -/* all the stuff below is obsolete and just here for reference. I'll - * remove it once the driver is tested and works fine. - * - * Instead creating alot of tiny API's for all kinds of different - * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not - * yet...). It is a bit less flexible, but most/all used i2c chips - * make sense in v4l context only. So I think that's acceptable... - */ - -/* misc stuff to pass around config info to i2c chips */ -#define AUDC_CONFIG_PINNACLE _IOW('m',32,int) #endif /* AUDIOCHIP_H */ -- cgit v1.2.3 From e64a86ee2b5ef5e23ccda2cc8981a22a8111a3b3 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:16 -0200 Subject: V4L/DVB (3108): tveeprom cleanup of hardcoded tuner format values. - Cleaned up the structure to use the V4L2_STD_xxx definitions rather than a one off set of hardcoded values - which could change in the future. Signed-off-by: Steven Toth Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 8ac4cb82a459..a26ce7515dfa 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -63,10 +63,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ c->adapter->nr, c->addr , ##arg); } while (0) - -/* ----------------------------------------------------------------------- */ -/* some hauppauge specific stuff */ - +/* + * The Hauppauge eeprom uses an 8bit field to determine which + * tuner formats the tuner supports. + */ static struct HAUPPAUGE_TUNER_FMT { int id; @@ -74,14 +74,14 @@ static struct HAUPPAUGE_TUNER_FMT } hauppauge_tuner_fmt[] = { - { 0x00000000, " unknown1" }, - { 0x00000000, " unknown2" }, - { 0x00000007, " PAL(B/G)" }, - { 0x00001000, " NTSC(M)" }, - { 0x00000010, " PAL(I)" }, - { 0x00400000, " SECAM(L/L')" }, - { 0x00000e00, " PAL(D/K)" }, - { 0x03000000, " ATSC/DVB Digital" }, + { V4L2_STD_UNKNOWN," UNKNOWN" }, + { V4L2_STD_UNKNOWN," FM" }, + { V4L2_STD_PAL_BG, " PAL(B/G)" }, + { V4L2_STD_NTSC_M, " NTSC(M)" }, + { V4L2_STD_PAL_I, " PAL(I)" }, + { V4L2_STD_SECAM_L," SECAM(L/L')" }, + { V4L2_STD_PAL_DK, " PAL(D/D1/K)" }, + { V4L2_STD_ATSC, " ATSC/DVB Digital" }, }; /* This is the full list of possible tuners. Many thanks to Hauppauge for -- cgit v1.2.3 From 2304759d7e5debbd400eca6e9bb979a186c798a9 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Mon, 9 Jan 2006 15:25:17 -0200 Subject: V4L/DVB (3110): Replace all uses of pci_module_init with pci_register_driver This patch replace all calls to pci_module_init, that's deprecated and will be removed in future, with pci_register_driver that should be the used function now. Signed-off-by: Otavio Salvador Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-driver.c | 2 +- drivers/media/video/saa7134/saa7134-core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 39e9178e599e..b93f4b5c0386 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -4253,7 +4253,7 @@ static int bttv_init_module(void) bttv_check_chipset(); bus_register(&bttv_sub_bus_type); - return pci_module_init(&bttv_pci_driver); + return pci_register_driver(&bttv_pci_driver); } static void bttv_cleanup_module(void) diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 23d8747338ed..21cb3d6be839 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1156,7 +1156,7 @@ static int saa7134_init(void) printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_module_init(&saa7134_pci_driver); + return pci_register_driver(&saa7134_pci_driver); } static void saa7134_fini(void) -- cgit v1.2.3 From 0345c387de72b5d7fbfeda9d92818fa7013a6d1c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:17 -0200 Subject: V4L/DVB (3112): Several fixes for Hauppauge Roselyn Design (blackbird) - This patch adds eeprom awareness for the Roslyn. In effect, the blackbird will query the tuner V4L2_STD_xxxx definitions to determine whether it's connected to a NTSC or PAL tuner. Based on that, various default values will change for blackbird encoding. - Fixes back panel SVIDEO/COMPOSITE with audio, work properly. - Fixes a problem with lip sync issues, due to bad framerate vs audio rate assumptions. - Fixed a problem with the GPIO configuration in cx88-cards. - Removed the comments in cx88-cards that made no sense. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 12 ++++++++++++ drivers/media/video/cx88/cx88-cards.c | 6 ++++-- drivers/media/video/cx88/cx88-tvaudio.c | 6 +++++- drivers/media/video/cx88/cx88.h | 3 +++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 74e57a53116f..99bfa3238294 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1689,6 +1689,18 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params)); memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params)); + if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) { + + if (core->tuner_formats & V4L2_STD_525_60) { + dev->height = 480; + dev->params.vi_frame_rate = 30; + } else { + dev->height = 576; + dev->params.vi_frame_rate = 25; + } + + } + err = cx8802_init_common(dev); if (0 != err) goto fail_free; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index c95438abcd7b..c20c07117537 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -611,12 +611,12 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0xed12, /* internal decoder */ + .gpio0 = 0xed1a, .gpio2 = 0x00ff, },{ .type = CX88_VMUX_DEBUG, .vmux = 0, - .gpio0 = 0xff01, /* mono from tuner chip */ + .gpio0 = 0xff01, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -1202,11 +1202,13 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); core->tuner_type = tv.tuner_type; + core->tuner_formats = tv.tuner_formats; core->has_radio = tv.has_radio; /* Make sure we support the board model */ switch (tv.model) { + case 28552: /* WinTV-PVR 'Roslyn' (No IR) */ case 90002: /* Nova-T-PCI (9002) */ case 92001: /* Nova-S-Plus (Video and IR) */ case 92002: /* Nova-S-Plus (Video and IR) */ diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index a1b120c8a9b5..00051a4c1dc2 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -139,7 +139,11 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) if (cx88_boards[core->board].blackbird) { /* sets sound input from external adc */ - cx_set(AUD_CTL, EN_I2SIN_ENABLE); + if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) + cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + else + cx_set(AUD_CTL, EN_I2SIN_ENABLE); + cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3e2bcd241a27..0bbf68b325c4 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -285,6 +285,9 @@ struct cx88_core { unsigned int tda9887_conf; unsigned int has_radio; + /* Supported V4L _STD_ tuner formats */ + unsigned int tuner_formats; + /* config info -- dvb */ struct dvb_pll_desc *pll_desc; unsigned int pll_addr; -- cgit v1.2.3 From a82c51d59344117320eeda3715f93c0695a9fbe6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:18 -0200 Subject: V4L/DVB (3115): Add missing VIDEO_ADV_DEBUG config option. - Add missing VIDEO_ADV_DEBUG config option. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fc87efc5049c..c89cc0a922ee 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -342,6 +342,13 @@ config VIDEO_DECODER depends on VIDEO_DEV && I2C && EXPERIMENTAL ---help--- Say Y here to compile drivers for SAA7115, SAA7127 and CX25840 - video decoders. + video decoders. + +config VIDEO_ADV_DEBUG + bool "Enable advanced debug functionality" + depends on VIDEO_DEV && VIDEO_DECODER && EXPERIMENTAL + ---help--- + Say Y here to enable advanced debugging functionality in the + SAA7115, SAA7127 and CX25840 video decoders. endmenu -- cgit v1.2.3 From f98c55ea18e87905bdf69eb4a187e94572ed9494 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:18 -0200 Subject: V4L/DVB (3116): tda9887 improvements: better defaults, better configurability. - Set the tuner takeover point to 0x10 for NTSC/radio and 0x14 for PAL/SECAM. - Allow override through TDA9887_SET_CONFIG - PAL-N belongs with PAL-BG as does PAL-H. PAL-Nc belongs to PAL-M - Add SECAM-BGH - Set video freq to cVideoIF_38_90 for DK standards. - Add cTunerGainLow to radio, change deemphasis to 75 for mono. - Add ntsc module param for 'M' and 'J' (Japanese) standards. - Fix module handling for 2.4. - Now able to select all standards through pal/secam/ntsc module options Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 164 +++++++++++++++++++++++++++++++++--------- include/media/tuner.h | 31 ++++---- 2 files changed, 150 insertions(+), 45 deletions(-) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index ceaa29975c8e..32f133ed0b0b 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -114,6 +114,9 @@ static struct i2c_client client_template; #define cAudioGain0 0x00 // bit c7 #define cAudioGain6 0x80 // bit c7 +#define cTopMask 0x1f // bit c0:4 +#define cTopPalSecamDefault 0x14 // bit c0:4 +#define cTopNtscRadioDefault 0x10 // bit c0:4 //// third reg (e) #define cAudioIF_4_5 0x00 // bit e0:1 @@ -145,13 +148,15 @@ static struct i2c_client client_template; static struct tvnorm tvnorms[] = { { - .std = V4L2_STD_PAL_BG, - .name = "PAL-BG", + .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, + .name = "PAL-BGHN", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_5_5 | + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_5_5 | cVideoIF_38_90 ), },{ .std = V4L2_STD_PAL_I, @@ -159,8 +164,10 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_6_0 | + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_0 | cVideoIF_38_90 ), },{ .std = V4L2_STD_PAL_DK, @@ -168,23 +175,37 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_6_5 | - cVideoIF_38_00 ), + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), },{ - .std = V4L2_STD_PAL_M | V4L2_STD_PAL_N, - .name = "PAL-M/N", + .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, + .name = "PAL-M/Nc", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis75 ), - .e = ( cAudioIF_4_5 | + cDeemphasis75 | + cTopNtscRadioDefault), + .e = ( cGating_36 | + cAudioIF_4_5 | cVideoIF_45_75 ), + },{ + .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, + .name = "SECAM-BGH", + .b = ( cPositiveAmTV | + cQSS ), + .c = ( cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_5_5 | + cVideoIF_38_90 ), },{ .std = V4L2_STD_SECAM_L, .name = "SECAM-L", .b = ( cPositiveAmTV | cQSS ), + .c = ( cTopPalSecamDefault), .e = ( cGating_36 | cAudioIF_6_5 | cVideoIF_38_90 ), @@ -194,6 +215,7 @@ static struct tvnorm tvnorms[] = { .b = ( cOutputPort2Inactive | cPositiveAmTV | cQSS ), + .c = ( cTopPalSecamDefault), .e = ( cGating_36 | cAudioIF_6_5 | cVideoIF_33_90 ), @@ -203,26 +225,30 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), - .e = ( cAudioIF_6_5 | - cVideoIF_38_00 ), + cDeemphasis50 | + cTopPalSecamDefault), + .e = ( cGating_36 | + cAudioIF_6_5 | + cVideoIF_38_90 ), },{ .std = V4L2_STD_NTSC_M, .name = "NTSC-M", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis75 ), + cDeemphasis75 | + cTopNtscRadioDefault), .e = ( cGating_36 | cAudioIF_4_5 | cVideoIF_45_75 ), },{ .std = V4L2_STD_NTSC_M_JP, - .name = "NTSC-JP", + .name = "NTSC-M-JP", .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), + cDeemphasis50 | + cTopNtscRadioDefault), .e = ( cGating_36 | cAudioIF_4_5 | cVideoIF_58_75 ), @@ -234,8 +260,10 @@ static struct tvnorm radio_stereo = { .b = ( cFmRadio | cQSS ), .c = ( cDeemphasisOFF | - cAudioGain6 ), - .e = ( cAudioIF_5_5 | + cAudioGain6 | + cTopNtscRadioDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | cRadioIF_38_90 ), }; @@ -244,8 +272,10 @@ static struct tvnorm radio_mono = { .b = ( cFmRadio | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50), - .e = ( cAudioIF_5_5 | + cDeemphasis75 | + cTopNtscRadioDefault), + .e = ( cTunerGainLow | + cAudioIF_5_5 | cRadioIF_38_90 ), }; @@ -408,7 +438,8 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) static unsigned int port1 = UNSET; static unsigned int port2 = UNSET; static unsigned int qss = UNSET; -static unsigned int adjust = 0x10; +static unsigned int adjust = UNSET; + module_param(port1, int, 0644); module_param(port2, int, 0644); module_param(qss, int, 0644); @@ -436,8 +467,10 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf) buf[1] &= ~cQSS; } - if (adjust >= 0x00 && adjust < 0x20) + if (adjust >= 0x00 && adjust < 0x20) { + buf[2] &= ~cTopMask; buf[2] |= adjust; + } return 0; } @@ -473,6 +506,10 @@ static int tda9887_set_config(struct tda9887 *t, char *buf) break; } } + if (t->config & TDA9887_TOP_SET) { + buf[2] &= ~cTopMask; + buf[2] |= (t->config >> 8) & cTopMask; + } if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; return 0; @@ -480,10 +517,13 @@ static int tda9887_set_config(struct tda9887 *t, char *buf) /* ---------------------------------------------------------------------- */ -static char pal[] = "-"; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + module_param_string(pal, pal, sizeof(pal), 0644); -static char secam[] = "-"; module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); static int tda9887_fixup_std(struct tda9887 *t) { @@ -494,8 +534,17 @@ static int tda9887_fixup_std(struct tda9887 *t) case 'B': case 'g': case 'G': - tda9887_dbg("insmod fixup: PAL => PAL-BG\n"); - t->std = V4L2_STD_PAL_BG; + case 'h': + case 'H': + case 'n': + case 'N': + if (pal[1] == 'c' || pal[1] == 'C') { + tda9887_dbg("insmod fixup: PAL => PAL-Nc\n"); + t->std = V4L2_STD_PAL_Nc; + } else { + tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n"); + t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N; + } break; case 'i': case 'I': @@ -509,6 +558,11 @@ static int tda9887_fixup_std(struct tda9887 *t) tda9887_dbg("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; + case 'm': + case 'M': + tda9887_dbg("insmod fixup: PAL => PAL-M\n"); + t->std = V4L2_STD_PAL_M; + break; case '-': /* default parameter, do nothing */ break; @@ -519,6 +573,15 @@ static int tda9887_fixup_std(struct tda9887 *t) } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n"); + t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + break; case 'd': case 'D': case 'k': @@ -528,8 +591,13 @@ static int tda9887_fixup_std(struct tda9887 *t) break; case 'l': case 'L': - tda9887_dbg("insmod fixup: SECAM => SECAM-L\n"); - t->std = V4L2_STD_SECAM_L; + if (secam[1] == 'c' || secam[1] == 'C') { + tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n"); + t->std = V4L2_STD_SECAM_LC; + } else { + tda9887_dbg("insmod fixup: SECAM => SECAM-L\n"); + t->std = V4L2_STD_SECAM_L; + } break; case '-': /* default parameter, do nothing */ @@ -539,6 +607,26 @@ static int tda9887_fixup_std(struct tda9887 *t) break; } } + if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + switch (ntsc[0]) { + case 'm': + case 'M': + tda9887_dbg("insmod fixup: NTSC => NTSC-M\n"); + t->std = V4L2_STD_NTSC_M; + break; + case 'j': + case 'J': + tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); + t->std = V4L2_STD_NTSC_M_JP; + break; + case '-': + /* default parameter, do nothing */ + break; + default: + tda9887_info("ntsc= argument not recognised\n"); + break; + } + } return 0; } @@ -561,6 +649,19 @@ static int tda9887_configure(struct tda9887 *t) memset(t->data,0,sizeof(t->data)); tda9887_set_tvnorm(t,t->data); + /* A note on the port settings: + These settings tend to depend on the specifics of the board. + By default they are set to inactive (bit value 1) by this driver, + overwriting any changes made by the tvnorm. This means that it + is the responsibility of the module using the tda9887 to set + these values in case of changes in the tvnorm. + In many cases port 2 should be made active (0) when selecting + SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. + + For the other standards the tda9887 application note says that + the ports should be set to active (0), but, again, that may + differ depending on the precise hardware configuration. + */ t->data[1] |= cOutputPort1Inactive; t->data[1] |= cOutputPort2Inactive; @@ -571,7 +672,6 @@ static int tda9887_configure(struct tda9887 *t) t->data[1] |= cForcedMuteAudioON; } - tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1],t->data[2],t->data[3]); if (debug > 1) diff --git a/include/media/tuner.h b/include/media/tuner.h index e224722a7ff7..567f05549e3a 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -120,20 +120,25 @@ #define TDA9887_SET_CONFIG _IOW('t',5,int) /* tv card specific */ -# define TDA9887_PRESENT (1<<0) -# define TDA9887_PORT1_INACTIVE (1<<1) -# define TDA9887_PORT2_INACTIVE (1<<2) -# define TDA9887_QSS (1<<3) -# define TDA9887_INTERCARRIER (1<<4) -# define TDA9887_PORT1_ACTIVE (1<<5) -# define TDA9887_PORT2_ACTIVE (1<<6) -# define TDA9887_INTERCARRIER_NTSC (1<<7) +#define TDA9887_PRESENT (1<<0) +#define TDA9887_PORT1_INACTIVE (1<<1) +#define TDA9887_PORT2_INACTIVE (1<<2) +#define TDA9887_QSS (1<<3) +#define TDA9887_INTERCARRIER (1<<4) +#define TDA9887_PORT1_ACTIVE (1<<5) +#define TDA9887_PORT2_ACTIVE (1<<6) +#define TDA9887_INTERCARRIER_NTSC (1<<7) +/* Tuner takeover point adjustment, in dB, -16 <= top <= 15 */ +#define TDA9887_TOP_MASK (0x3f << 8) +#define TDA9887_TOP_SET (1 << 13) +#define TDA9887_TOP(top) (TDA9887_TOP_SET | (((16 + (top)) & 0x1f) << 8)) + /* config options */ -# define TDA9887_DEEMPHASIS_MASK (3<<16) -# define TDA9887_DEEMPHASIS_NONE (1<<16) -# define TDA9887_DEEMPHASIS_50 (2<<16) -# define TDA9887_DEEMPHASIS_75 (3<<16) -# define TDA9887_AUTOMUTE (1<<18) +#define TDA9887_DEEMPHASIS_MASK (3<<16) +#define TDA9887_DEEMPHASIS_NONE (1<<16) +#define TDA9887_DEEMPHASIS_50 (2<<16) +#define TDA9887_DEEMPHASIS_75 (3<<16) +#define TDA9887_AUTOMUTE (1<<18) #ifdef __KERNEL__ -- cgit v1.2.3 From a1789d3aea9e1eca676de011e1e3ebe9171cf9cb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:19 -0200 Subject: V4L/DVB (3117): Fix broken TV standard check. - Fix incorrect matching of TV standards leading to incorrect IFPCoff values. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 9bd52993d366..95818bfcb5c0 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -902,11 +902,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) 171.2=16*10.70 FM Radio (at set_radio_freq) */ - if (t->std & V4L2_STD_NTSC_M_JP) { + if (t->std == V4L2_STD_NTSC_M_JP) { IFPCoff = 940; - } else if (t->std & V4L2_STD_MN) { + } else if ((t->std & V4L2_STD_MN) && + !(t->std & ~V4L2_STD_MN)) { IFPCoff = 732; - } else if (t->std & V4L2_STD_SECAM_LC) { + } else if (t->std == V4L2_STD_SECAM_LC) { IFPCoff = 543; } else { IFPCoff = 623; -- cgit v1.2.3 From 899ad11b55206c30db7e3667d14c8bdb167f51f8 Mon Sep 17 00:00:00 2001 From: George Gazurkoff Date: Mon, 9 Jan 2006 15:25:19 -0200 Subject: V4L/DVB (3118): Enable remote control on AVERTV STUDIO 303 - Enable remote control on AVERTV STUDIO 303 - This patch adapted from a patch found on a website posted by an anonymous user. Thanks to original anonymous author for creating this patch. Tested successfully by George Gazurkoff. Signed-off-by: George Gazurkoff Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-input.c | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index a89bb2b195f3..e123367773b3 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -258,6 +258,54 @@ static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { /* ---------------------------------------------------------------------- */ +/* AVERTV STUDIO 303 Remote */ +static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = { + [ 0x2a ] = KEY_KP1, + [ 0x32 ] = KEY_KP2, + [ 0x3a ] = KEY_KP3, + [ 0x4a ] = KEY_KP4, + [ 0x52 ] = KEY_KP5, + [ 0x5a ] = KEY_KP6, + [ 0x6a ] = KEY_KP7, + [ 0x72 ] = KEY_KP8, + [ 0x7a ] = KEY_KP9, + [ 0x0e ] = KEY_KP0, + + [ 0x02 ] = KEY_POWER, + [ 0x22 ] = KEY_VIDEO, + [ 0x42 ] = KEY_AUDIO, + [ 0x62 ] = KEY_ZOOM, + [ 0x0a ] = KEY_TV, + [ 0x12 ] = KEY_CD, + [ 0x1a ] = KEY_TEXT, + + [ 0x16 ] = KEY_SUBTITLE, + [ 0x1e ] = KEY_REWIND, + [ 0x06 ] = KEY_PRINT, + + [ 0x2e ] = KEY_SEARCH, + [ 0x36 ] = KEY_SLEEP, + [ 0x3e ] = KEY_SHUFFLE, + [ 0x26 ] = KEY_MUTE, + + [ 0x4e ] = KEY_RECORD, + [ 0x56 ] = KEY_PAUSE, + [ 0x5e ] = KEY_STOP, + [ 0x46 ] = KEY_PLAY, + + [ 0x6e ] = KEY_RED, + [ 0x0b ] = KEY_GREEN, + [ 0x66 ] = KEY_YELLOW, + [ 0x03 ] = KEY_BLUE, + + [ 0x76 ] = KEY_LEFT, + [ 0x7e ] = KEY_RIGHT, + [ 0x13 ] = KEY_DOWN, + [ 0x1b ] = KEY_UP, +}; + +/* ---------------------------------------------------------------------- */ + struct cx88_IR { struct cx88_core *core; struct input_dev *input; @@ -430,6 +478,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keyup = 0x40; ir->polling = 1; /* ms */ break; + case CX88_BOARD_AVERTV_303: + ir_codes = ir_codes_avertv_303; + ir->gpio_addr = MO_GP2_IO; + ir->mask_keycode = 0xfb; + ir->mask_keydown = 0x02; + ir->polling = 50; /* ms */ + break; } if (NULL == ir_codes) { -- cgit v1.2.3 From b5b8ab8d93ec46fec279b22eb1a613be18f49f7a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:20 -0200 Subject: V4L/DVB (3123): include reorder to be in sync with V4L tree - include reorder to be in sync with V4L tree Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-driver.c | 4 ++-- drivers/media/video/bttv-i2c.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index b93f4b5c0386..47347674a5e0 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -34,13 +34,13 @@ #include #include #include +#include "bttvp.h" + #include #include #include -#include "bttvp.h" - #include "rds.h" diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index d6418c023d39..8bb055de8d84 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -28,10 +28,10 @@ #include #include #include -#include -#include #include "bttvp.h" +#include +#include static struct i2c_algo_bit_data bttv_i2c_algo_bit_template; static struct i2c_adapter bttv_i2c_adap_sw_template; -- cgit v1.2.3 From b060c25f70adb20532dacefa72029d1d2db1a7f1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:20 -0200 Subject: V4L/DVB (3123a): remove uneeded #if from V4L subsystem - some uneeded #if were introduced by a previous patch. this patch removes these. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt832.c | 5 ----- drivers/media/video/bttv-i2c.c | 6 ------ drivers/media/video/cs53l32a.c | 4 ---- drivers/media/video/cx25840/cx25840-core.c | 4 ---- drivers/media/video/em28xx/em28xx-i2c.c | 2 -- drivers/media/video/msp3400.c | 4 ---- drivers/media/video/saa6588.c | 10 ---------- drivers/media/video/saa7115.c | 4 ---- drivers/media/video/saa7127.c | 4 ---- drivers/media/video/saa7134/saa7134-i2c.c | 2 -- drivers/media/video/tda7432.c | 5 ----- drivers/media/video/tda9875.c | 5 ----- drivers/media/video/tda9887.c | 10 ---------- drivers/media/video/tvaudio.c | 9 --------- drivers/media/video/tvmixer.c | 14 -------------- drivers/media/video/wm8775.c | 4 ---- 16 files changed, 92 deletions(-) diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index 1c3ff5f38a6d..d2cb5ccff56b 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -183,13 +183,8 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind) static int bt832_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, bt832_attach); -#else - if (adap->id == I2C_HW_B_BT848) - return i2c_probe(adap, &addr_data, bt832_attach); -#endif return 0; } diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index 8bb055de8d84..a8873f48c808 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -105,9 +105,7 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { static struct i2c_adapter bttv_i2c_adap_sw_template = { .owner = THIS_MODULE, -#ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, -#endif .name = "bt848", .id = I2C_HW_B_BT848, .client_register = attach_inform, @@ -276,9 +274,7 @@ static struct i2c_algorithm bttv_algo = { static struct i2c_adapter bttv_i2c_adap_hw_template = { .owner = THIS_MODULE, -#ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, -#endif .name = "bt878", .id = I2C_HW_B_BT848 /* FIXME */, .algo = &bttv_algo, @@ -441,12 +437,10 @@ int __devinit init_bttv_i2c(struct bttv *btv) i2c_set_adapdata(&btv->c.i2c_adap, btv); btv->i2c_client.adapter = &btv->c.i2c_adap; -#ifdef I2C_CLASS_TV_ANALOG if (bttv_tvcards[btv->c.type].no_video) btv->c.i2c_adap.class &= ~I2C_CLASS_TV_ANALOG; if (bttv_tvcards[btv->c.type].has_dvb) btv->c.i2c_adap.class |= I2C_CLASS_TV_DIGITAL; -#endif if (btv->use_i2c_hw) { btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index 643ead1a87ee..aa31b6736a7a 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -190,11 +190,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) static int cs53l32a_probe(struct i2c_adapter *adapter) { -#ifdef I2C_CLASS_TV_ANALOG if (adapter->class & I2C_CLASS_TV_ANALOG) -#else - if (adapter->id == I2C_HW_B_BT848) -#endif return i2c_probe(adapter, &addr_data, cs53l32a_attach); return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 3b09f46dddf6..54ffae686dc9 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -815,11 +815,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, static int cx25840_attach_adapter(struct i2c_adapter *adapter) { -#ifdef I2C_CLASS_TV_ANALOG if (adapter->class & I2C_CLASS_TV_ANALOG) -#else - if (adapter->id == I2C_HW_B_BT848) -#endif return i2c_probe(adapter, &addr_data, &cx25840_detect_client); return 0; } diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index d14bcf4ceaea..5385338efbf4 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -486,9 +486,7 @@ static struct i2c_adapter em28xx_adap_template = { .inc_use = inc_use, .dec_use = dec_use, #endif -#ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, -#endif .name = "em28xx", .id = I2C_HW_B_EM28XX, .algo = &em28xx_algo, diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 546e3f0067fe..1bf0fb38b918 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -2336,13 +2336,9 @@ static int msp_detach(struct i2c_client *client) static int msp_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, msp_attach); return 0; -#else - return i2c_probe(adap, &addr_data, msp_attach); -#endif } static int __init msp3400_init_module(void) diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index d60a783e0473..ad582bd39819 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -427,18 +427,8 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) static int saa6588_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, saa6588_attach); -#else - switch (adap->id) { - case I2C_HW_B_BT848: - case I2C_HW_B_RIVA: - case I2C_HW_SAA7134: - return i2c_probe(adap, &addr_data, saa6588_attach); - break; - } -#endif return 0; } diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 29e28c742cd4..685ca1780c66 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1326,11 +1326,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) static int saa7115_probe(struct i2c_adapter *adapter) { -#ifdef I2C_CLASS_TV_ANALOG if (adapter->class & I2C_CLASS_TV_ANALOG) -#else - if (adapter->id == I2C_HW_B_BT848) -#endif return i2c_probe(adapter, &addr_data, &saa7115_attach); return 0; } diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index bca6ed0e2752..aee0f2d73da3 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -787,11 +787,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) static int saa7127_probe(struct i2c_adapter *adapter) { -#ifdef I2C_CLASS_TV_ANALOG if (adapter->class & I2C_CLASS_TV_ANALOG) -#else - if (adapter->id == I2C_HW_B_BT848) -#endif return i2c_probe(adapter, &addr_data, saa7127_attach); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 1792d03d621d..7283caa0484b 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -390,9 +390,7 @@ static struct i2c_algorithm saa7134_algo = { static struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, -#ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, -#endif .name = "saa7134", .id = I2C_HW_SAA7134, .algo = &saa7134_algo, diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 549c9929f107..3bd7dfb8cc7c 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -323,13 +323,8 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind) static int tda7432_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda7432_attach); -#else - if (adap->id == I2C_HW_B_BT848) - return i2c_probe(adap, &addr_data, tda7432_attach); -#endif return 0; } diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 9c3ecf7a0fed..760ec3c2ac67 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -257,13 +257,8 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind) static int tda9875_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9875_attach); -#else - if (adap->id == I2C_HW_B_BT848) - return i2c_probe(adap, &addr_data, tda9875_attach); -#endif return 0; } diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 32f133ed0b0b..9ae43a8cea52 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -714,18 +714,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) static int tda9887_probe(struct i2c_adapter *adap) { -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9887_attach); -#else - switch (adap->id) { - case I2C_HW_B_BT848: - case I2C_HW_B_RIVA: - case I2C_HW_SAA7134: - return i2c_probe(adap, &addr_data, tda9887_attach); - break; - } -#endif return 0; } diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 0292c5abf14a..19625e6410d1 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1563,17 +1563,8 @@ static int chip_probe(struct i2c_adapter *adap) because dedicated drivers are used */ if ((adap->id == I2C_HW_SAA7146)) return 0; -#ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, chip_attach); -#else - switch (adap->id) { - case I2C_HW_B_BT848: - case I2C_HW_B_RIVA: - case I2C_HW_SAA7134: - return i2c_probe(adap, &addr_data, chip_attach); - } -#endif return 0; } diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index e837f9f7fed6..ce0da9c1a768 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -267,22 +267,8 @@ static int tvmixer_clients(struct i2c_client *client) struct video_audio va; int i,minor; -#ifdef I2C_CLASS_TV_ANALOG if (!(client->adapter->class & I2C_CLASS_TV_ANALOG)) return -1; -#else - /* TV card ??? */ - switch (client->adapter->id) { - case I2C_HW_SMBUS_VOODOO3: - case I2C_HW_B_BT848: - case I2C_HW_B_RIVA: - /* ok, have a look ... */ - break; - default: - /* ignore that one */ - return -1; - } -#endif /* unregister ?? */ for (i = 0; i < DEV_MAX; i++) { diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index bbfd55cd9948..3472f08e41fd 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -206,11 +206,7 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) static int wm8775_probe(struct i2c_adapter *adapter) { -#ifdef I2C_CLASS_TV_ANALOG if (adapter->class & I2C_CLASS_TV_ANALOG) -#else - if (adapter->id == I2C_HW_B_BT848) -#endif return i2c_probe(adapter, &addr_data, wm8775_attach); return 0; } -- cgit v1.2.3 From d21838dd7d098e102ced2fafed62dcb133c4d71c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:21 -0200 Subject: V4L/DVB (3123b): syncs V4L subsystem tree with kernel - This patch makes kernel in sync with v4l subsystem tree. - some lines reordered to be sync. - some reduntant codes removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 3 +-- drivers/media/video/cx88/cx88-input.c | 3 +-- drivers/media/video/em28xx/em28xx-core.c | 6 +++--- drivers/media/video/ir-kbd-gpio.c | 8 +++----- drivers/media/video/ir-kbd-i2c.c | 16 ++++++++++------ drivers/media/video/saa7134/saa7134-alsa.c | 2 +- drivers/media/video/saa7134/saa7134-core.c | 2 +- drivers/media/video/saa7134/saa7134.h | 7 +++---- drivers/media/video/videodev.c | 6 ++++-- 9 files changed, 27 insertions(+), 26 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 99bfa3238294..5a7f940565cc 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -34,8 +34,7 @@ #include "cx88.h" MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); -MODULE_AUTHOR("Jelle Foks "); -MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); static unsigned int mpegbufs = 32; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index e123367773b3..649bbf7bcc29 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -29,9 +29,8 @@ #include #include -#include - #include "cx88.h" +#include /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 6d32bd64ce55..c0db0e9d2cea 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -32,7 +32,7 @@ /* #define ENABLE_DEBUG_ISOC_FRAMES */ -static unsigned int core_debug; +static unsigned int core_debug = 0; module_param(core_debug,int,0644); MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); @@ -41,7 +41,7 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); printk(KERN_INFO "%s %s :"fmt, \ dev->name, __FUNCTION__ , ##arg); } while (0) -static unsigned int reg_debug; +static unsigned int reg_debug = 0; module_param(reg_debug,int,0644); MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]"); @@ -50,7 +50,7 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]"); printk(KERN_INFO "%s %s :"fmt, \ dev->name, __FUNCTION__ , ##arg); } while (0) -static unsigned int isoc_debug; +static unsigned int isoc_debug = 0; module_param(isoc_debug,int,0644); MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]"); diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index de1385e5d05e..556da9ff128f 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c @@ -26,9 +26,8 @@ #include #include -#include - #include "bttv.h" +#include /* ---------------------------------------------------------------------- */ @@ -672,6 +671,8 @@ static int ir_probe(struct device *dev) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(sub->core->pci)); + ir->input = input_dev; + ir->sub = sub; ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); input_dev->name = ir->name; input_dev->phys = ir->phys; @@ -686,9 +687,6 @@ static int ir_probe(struct device *dev) } input_dev->cdev.dev = &sub->core->pci->dev; - ir->input = input_dev; - ir->sub = sub; - if (ir->polling) { INIT_WORK(&ir->work, ir_work, ir); init_timer(&ir->timer); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3cc1d6a6019b..caa0f58d149e 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -304,18 +304,20 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL); input_dev = input_allocate_device(); if (!ir || !input_dev) { - kfree(ir); input_free_device(input_dev); + kfree(ir); return -ENOMEM; } + memset(ir,0,sizeof(*ir)); ir->c = client_template; ir->input = input_dev; - i2c_set_clientdata(&ir->c, ir); ir->c.adapter = adap; ir->c.addr = addr; + i2c_set_clientdata(&ir->c, ir); + switch(addr) { case 0x64: name = "Pixelview"; @@ -378,13 +380,15 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->c.dev.bus_id); /* init + register input device */ - ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); - input_dev->id.bustype = BUS_I2C; - input_dev->name = ir->c.name; - input_dev->phys = ir->phys; + ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes); + input_dev->id.bustype = BUS_I2C; + input_dev->name = ir->c.name; + input_dev->phys = ir->phys; /* register event device */ input_register_device(ir->input); + printk(DEVNAME ": %s detected at %s [%s]\n", + ir->input->name,ir->input->phys,adap->name); /* start polling via eventd */ INIT_WORK(&ir->work, ir_work, ir); diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index ade05f75fdb0..a7a6ab9298a9 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -20,13 +20,13 @@ * */ -#include #include #include #include #include #include #include +#include #include #include #include diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 21cb3d6be839..0bdbd99d0ae6 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -211,7 +211,7 @@ static int pending_call(struct notifier_block *self, unsigned long state, return NOTIFY_DONE; } -static int pending_registered; +static int pending_registered=0; static struct notifier_block pending_notifier = { .notifier_call = pending_call, }; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 185115226b4b..2f28e83102fd 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -37,6 +37,9 @@ #include #include #include +#include +#include +#include #include #ifndef TRUE @@ -47,10 +50,6 @@ #endif #define UNSET (-1U) -#include -#include -#include - /* ----------------------------------------------------------- */ /* enums */ diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 6de5b0094b82..7df6a55dd59e 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -68,7 +68,8 @@ static void video_release(struct class_device *cd) { struct video_device *vfd = container_of(cd, struct video_device, class_dev); -#if 1 /* needed until all drivers are fixed */ +#if 1 + /* needed until all drivers are fixed */ if (!vfd->release) return; #endif @@ -344,7 +345,8 @@ int video_register_device(struct video_device *vfd, int type, int nr) class_device_create_file(&vfd->class_dev, &class_device_attr_name); -#if 1 /* needed until all drivers are fixed */ +#if 1 + /* needed until all drivers are fixed */ if (!vfd->release) printk(KERN_WARNING "videodev: \"%s\" has no release callback. " "Please fix your driver for proper sysfs support, see " -- cgit v1.2.3 From 2c3f11b20fc6c41b4d3f64f301f525e35f18b6bc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 9 Jan 2006 15:25:21 -0200 Subject: V4L/DVB (3129): correct FE_READ_UNCORRECTED_BLOCKS - Make FE_READ_UNCORRECTED_BLOCKS reset the count after each call, thus returning a momentary value like all other demods do, instead of an absolute, ever increasing count. Signed-off-by: Stephen Williams Signed-off-by: Johannes Stezenbach Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 1d69bf031fb9..e2598bbc2bb5 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -564,10 +564,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file, (__u16 __user *) arg); case FE_READ_UNCORRECTED_BLOCKS: - /* UNC are already converted to host byte order... */ - return put_user(stat->uncorrected_block_count, - (__u32 __user *) arg); + { + uint32_t unc_count; + unc_count = stat->uncorrected_block_count; + stat->uncorrected_block_count = 0; + + /* UNC are already converted to host byte order... */ + return put_user(unc_count,(__u32 __user *) arg); + } case FE_SET_FRONTEND: { struct dvbt_set_parameters_msg *param = &cinergyt2->param; -- cgit v1.2.3 From 0144f31466f0b7f1a8b21b470bfeb93c174a2006 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:22 -0200 Subject: V4L/DVB (3130): cx24123: cleanup timout handling - Cleanup timeout handling in cx24123_pll_writereg(), and use a reasonable value for the timeout. Signed-off-by: Steven Toth Signed-off-by: Johannes Stezenbach Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24123.c | 39 ++++++++++++++--------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 3e230fc59cac..d661c6f9cbe5 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -487,8 +487,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data) { struct cx24123_state *state = fe->demodulator_priv; - - u8 timeout = 0; + unsigned long timeout; /* align the 21 bytes into to bit23 boundary */ data = data << 3; @@ -496,43 +495,37 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par /* Reset the demod pll word length to 0x15 bits */ cx24123_writereg(state, 0x21, 0x15); - timeout = 0; /* write the msb 8 bits, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); cx24123_writereg(state, 0x22, (data >> 16) & 0xff); - while ( ( cx24123_readreg(state, 0x20) & 0x40 ) == 0 ) - { - /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ - if (timeout++ >= 4) { - printk("%s: demodulator is no longer responding, aborting.\n",__FUNCTION__); + while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { + if (time_after(jiffies, timeout)) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__); return -EREMOTEIO; } - msleep(500); + msleep(10); } - timeout = 0; /* send another 8 bytes, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); cx24123_writereg(state, 0x22, (data>>8) & 0xff ); - while ( (cx24123_readreg(state, 0x20) & 0x40 ) == 0 ) - { - /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ - if (timeout++ >= 4) { - printk("%s: demodulator is not responding, possibly hung, aborting.\n",__FUNCTION__); + while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { + if (time_after(jiffies, timeout)) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__); return -EREMOTEIO; } - msleep(500); + msleep(10); } - timeout = 0; /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); cx24123_writereg(state, 0x22, (data) & 0xff ); - while ((cx24123_readreg(state, 0x20) & 0x80)) - { - /* Safety - No reason why the write should not complete, and we never get here, avoid hang */ - if (timeout++ >= 4) { - printk("%s: demodulator is not responding, possibly hung, aborting.\n",__FUNCTION__); + while ((cx24123_readreg(state, 0x20) & 0x80)) { + if (time_after(jiffies, timeout)) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__); return -EREMOTEIO; } - msleep(500); + msleep(10); } /* Trigger the demod to configure the tuner */ -- cgit v1.2.3 From 4302c15ea237a649780894e263125fcd8c548998 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:22 -0200 Subject: V4L/DVB (3145): syncronizes some changes between v4l and dvb - digitv_ctrl_msg() if (wo) test is reversed. fixed. - usb timeout is in Hz, not in jiffies. - NULL replaced by 0 to be coherent. - removed uneeded headers. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-reg.h | 4 +++- drivers/media/dvb/dvb-usb/digitv.c | 2 +- drivers/media/dvb/dvb-usb/dtt200u.c | 4 ++-- drivers/media/dvb/dvb-usb/dvb-usb-firmware.c | 2 +- drivers/media/dvb/dvb-usb/dvb-usb.h | 1 - drivers/media/dvb/dvb-usb/vp7045.c | 2 +- drivers/media/dvb/frontends/cx24110.c | 1 - drivers/media/dvb/frontends/lgdt330x.c | 2 ++ 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 23cc6431e2b8..3153f9513c63 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -39,11 +39,13 @@ extern const char *flexcop_device_names[]; /* FlexCop IBI Registers */ #if defined(__LITTLE_ENDIAN) #include "flexcop_ibi_value_le.h" -#elif defined(__BIG_ENDIAN) +#else +#if defined(__BIG_ENDIAN) #include "flexcop_ibi_value_be.h" #else #error no endian defined #endif +#endif #define fc_data_Tag_ID_DVB 0x3e #define fc_data_Tag_ID_ATSC 0x3f diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 450417a9e64b..e6c55c9c9417 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d, sndbuf[1] = vv; sndbuf[2] = wo ? wlen : rlen; - if (!wo) { + if (wo) { memcpy(&sndbuf[3],wbuf,wlen); dvb_usb_generic_write(d,sndbuf,7); } else { diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 6e2bac873445..54c436996512 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = { .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, - { NULL }, + { 0 }, } }; @@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = { .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, - { NULL }, + { 0 }, } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c index ab87af99d36f..51ce7403999b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c @@ -30,7 +30,7 @@ static struct usb_cypress_controller cypress[] = { static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) { return usb_control_msg(udev, usb_sndctrlpipe(udev,0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ); + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); } static int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index cd510fba60ee..4060fe1ca082 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 3835235b68df..028204956bb0 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = { .cold_ids = { &vp7045_usb_table[2], NULL }, .warm_ids = { &vp7045_usb_table[3], NULL }, }, - { NULL }, + { 0 }, } }; diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 0c4db80ec332..ecd056e951f1 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "dvb_frontend.h" #include "cx24110.h" diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index cb5301865d07..56fcb9e97b57 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -402,6 +402,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, state->config->pll_set(fe, param); /* Keep track of the new frequency */ + /* FIXME this is the wrong way to do this... */ + /* The tuner is shared with the video4linux analog API */ state->current_frequency = param->frequency; lgdt330x_SwReset(state); -- cgit v1.2.3 From 6a5bdd322e5366730803beb59adca7ebb144d7e4 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 9 Jan 2006 15:25:23 -0200 Subject: V4L/DVB (3173): [PATCH] Decrease number of pointer derefs in flexcop-fe-tuner.c - Here's a small patch to decrease the number of pointer derefs in drivers/media/dvb/b2c2/flexcop-fe-tuner.c Benefits of the patch: - Fewer pointer dereferences should make the code slightly faster. - Size of generated code is smaller - Improved readability Signed-off-by: Jesper Juhl Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 21a9045b3ef6..fa7058108bf4 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -485,12 +485,16 @@ static struct stv0297_config alps_tdee4_stv0297_config = { /* try to figure out the frontend, each card/box can have on of the following list */ int flexcop_frontend_init(struct flexcop_device *fc) { + struct dvb_frontend_ops *ops; + /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { - fc->fe->ops->set_voltage = flexcop_set_voltage; + ops = fc->fe->ops; + + ops->set_voltage = flexcop_set_voltage; - fc->fe_sleep = fc->fe->ops->sleep; - fc->fe->ops->sleep = flexcop_sleep; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; fc->dev_type = FC_SKY; info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); @@ -522,15 +526,17 @@ int flexcop_frontend_init(struct flexcop_device *fc) } else /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { - fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; - fc->fe->ops->set_tone = flexcop_set_tone; - fc->fe->ops->set_voltage = flexcop_set_voltage; + ops = fc->fe->ops; + + ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + ops->diseqc_send_burst = flexcop_diseqc_send_burst; + ops->set_tone = flexcop_set_tone; + ops->set_voltage = flexcop_set_voltage; - fc->fe_sleep = fc->fe->ops->sleep; - fc->fe->ops->sleep = flexcop_sleep; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; - fc->dev_type = FC_SKY_OLD; + fc->dev_type = FC_SKY_OLD; info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); } @@ -540,8 +546,9 @@ int flexcop_frontend_init(struct flexcop_device *fc) } else { if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { err("frontend registration failed!"); - if (fc->fe->ops->release != NULL) - fc->fe->ops->release(fc->fe); + ops = fc->fe->ops; + if (ops->release != NULL) + ops->release(fc->fe); fc->fe = NULL; return -EINVAL; } -- cgit v1.2.3 From e4acba3c01ca8b275dda22664191c30ee352a38e Mon Sep 17 00:00:00 2001 From: Deti Fliegl Date: Mon, 9 Jan 2006 15:25:23 -0200 Subject: DVB (2401): USB hot unplug Oops fix. - USB hot unplug Oops fix. Signed-off-by: Deti Fliegl Signed-off-by: Johannes Stezenbach Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/cinergyT2/cinergyT2.c | 71 ++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index e2598bbc2bb5..c4b4c5b6b7c8 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -131,6 +131,8 @@ struct cinergyt2 { wait_queue_head_t poll_wq; int pending_fe_events; + int disconnect_pending; + atomic_t inuse; void *streambuf; dma_addr_t streambuf_dmahandle; @@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed) struct dvb_demux *demux = dvbdmxfeed->demux; struct cinergyt2 *cinergyt2 = demux->priv; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (cinergyt2->streaming == 0) @@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed) struct dvb_demux *demux = dvbdmxfeed->demux; struct cinergyt2 *cinergyt2 = demux->priv; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (--cinergyt2->streaming == 0) @@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - int err; + int err = -ERESTARTSYS; - if ((err = dvb_generic_open(inode, file))) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + if ((err = dvb_generic_open(inode, file))) { + up(&cinergyt2->sem); return err; + } - if (down_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { cinergyt2_sleep(cinergyt2, 0); schedule_delayed_work(&cinergyt2->query_work, HZ/2); } + atomic_inc(&cinergyt2->inuse); + up(&cinergyt2->sem); return 0; } +static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) +{ + dvb_unregister_device(cinergyt2->fedev); + dvb_unregister_adapter(&cinergyt2->adapter); + + cinergyt2_free_stream_urbs(cinergyt2); + kfree(cinergyt2); +} + static int cinergyt2_release (struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; @@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file) if (down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) { cancel_delayed_work(&cinergyt2->query_work); flush_scheduled_work(); cinergyt2_sleep(cinergyt2, 1); @@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file) up(&cinergyt2->sem); + if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) { + warn("delayed unregister in release"); + cinergyt2_unregister(cinergyt2); + } + return dvb_generic_release(inode, file); } @@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; + + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + poll_wait(file, &cinergyt2->poll_wq, wait); + + up(&cinergyt2->sem); + return (POLLIN | POLLRDNORM | POLLPRI); } @@ -585,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file, if (copy_from_user(&p, (void __user*) arg, sizeof(p))) return -EFAULT; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; @@ -696,7 +724,7 @@ static void cinergyt2_query_rc (void *data) struct cinergyt2_rc_event rc_events[12]; int n, len, i; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return; len = cinergyt2_command(cinergyt2, buf, sizeof(buf), @@ -791,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { cancel_delayed_work(&cinergyt2->rc_query_work); - flush_scheduled_work(); input_unregister_device(cinergyt2->rc_input_dev); } @@ -822,7 +849,7 @@ static void cinergyt2_query (void *data) uint8_t lock_bits; uint32_t unc; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return; unc = s->uncorrected_block_count; @@ -922,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); - if (down_interruptible(&cinergyt2->sem)) - return; + flush_scheduled_work(); cinergyt2_unregister_rc(cinergyt2); + cancel_delayed_work(&cinergyt2->query_work); + wake_up_interruptible(&cinergyt2->poll_wq); + cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); - dvb_net_release(&cinergyt2->dvbnet); - dvb_dmxdev_release(&cinergyt2->dmxdev); - dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_device(cinergyt2->fedev); - dvb_unregister_adapter(&cinergyt2->adapter); + cinergyt2->disconnect_pending = 1; - cinergyt2_free_stream_urbs(cinergyt2); - up(&cinergyt2->sem); - kfree(cinergyt2); + if (!atomic_read(&cinergyt2->inuse)) + cinergyt2_unregister(cinergyt2); } static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (state.event > PM_EVENT_ON) { @@ -966,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf) struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); struct dvbt_set_parameters_msg *param = &cinergyt2->param; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (!cinergyt2->sleeping) { @@ -1019,4 +1043,3 @@ module_exit (cinergyt2_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); - -- cgit v1.2.3 From f961e71a0a96b4a992210b7dd46d837d78b162c6 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Mon, 9 Jan 2006 15:25:24 -0200 Subject: V4L/DVB (3154): TTUSB DEC driver patch roundup - Collection of patches from Peter Beutner addressing: - add symbolrates to the DVB-S frontend description - fix capability flags in DVB-S frontend describtion - remove some void casts - disable zig-zag scanning as it makes no sense for DVB-T - set sensible min_delay value - return an error for requested filter types the driver can't handle Signed-off-by: Peter Beutner Signed-off-by: Alex Woods Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 15 ++++----- drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 53 +++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 8abc21890129..36bc9838cf17 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -369,7 +369,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) { - struct ttusb_dec *dec = (struct ttusb_dec *)priv; + struct ttusb_dec *dec = priv; dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, &dec->audio_filter->feed->feed.ts, @@ -380,7 +380,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) { - struct ttusb_dec *dec = (struct ttusb_dec *)priv; + struct ttusb_dec *dec = priv; dec->video_filter->feed->cb.ts(data, 188, NULL, 0, &dec->video_filter->feed->feed.ts, @@ -965,8 +965,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TS_PES_TELETEXT: dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT\n"); - break; + dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); + return -ENOSYS; case DMX_TS_PES_PCR: dprintk(" pes_type: DMX_TS_PES_PCR\n"); @@ -975,8 +975,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) break; case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER\n"); - break; + dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + return -ENOSYS; default: dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); @@ -1395,6 +1395,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) /* We can't trust the USB IDs that some firmwares give the box */ switch (model) { + case 0x00070001: case 0x00070008: case 0x0007000c: ttusb_dec_set_model(dec, TTUSB_DEC3000S); @@ -1588,7 +1589,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command, int param_length, const u8 params[], int *result_length, u8 cmd_result[]) { - struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv; + struct ttusb_dec* dec = fe->dvb->priv; return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); } diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 725af3af5b27..a5a46175fa09 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -42,8 +42,39 @@ struct ttusbdecfe_state { static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) { - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + struct ttusbdecfe_state* state = fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + u8 result[4]; + int len, ret; + + *status=0; + + ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); + if(ret) + return ret; + + if(len != 4) { + printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__); + return -EIO; + } + + switch(result[3]) { + case 1: /* not tuned yet */ + case 2: /* no signal/no lock*/ + break; + case 3: /* signal found and locked*/ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + break; + case 4: + *status = FE_TIMEDOUT; + break; + default: + pr_info("%s: returned unknown value: %d\n", + __FUNCTION__, result[3]); + return -EIO; + } return 0; } @@ -64,6 +95,16 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron return 0; } +static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 1500; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; @@ -212,6 +253,8 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .set_frontend = ttusbdecfe_dvbt_set_frontend, + .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, + .read_status = ttusbdecfe_read_status, }; @@ -223,11 +266,11 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, + .symbol_rate_min = 1000000, /* guessed */ + .symbol_rate_max = 45000000, /* guessed */ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, + FE_CAN_QPSK }, .release = ttusbdecfe_release, -- cgit v1.2.3 From f4a3bc82ed5dcef03a74ff974a31b55eade7ed0f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:24 -0200 Subject: V4L/DVB (3159): Replaces MAX()/MIN() by kernel.h max()/min() macros - Replaces MAX()/MIN() by kernel.h max()/min() macros Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 1bf0fb38b918..fd0589352822 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -166,8 +166,6 @@ struct msp3400c { int watch_stereo:1; }; -#define MIN(a,b) (((a)>(b))?(b):(a)) -#define MAX(a,b) (((a)>(b))?(a):(b)) #define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00) #define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@') #define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@') @@ -1670,9 +1668,9 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) return 0; case V4L2_CID_AUDIO_BALANCE: { - int volume = MAX(msp->left, msp->right); + int volume = max(msp->left, msp->right); - ctrl->value = (32768 * MIN(msp->left, msp->right)) / + ctrl->value = (32768 * min(msp->left, msp->right)) / (volume ? volume : 1); ctrl->value = (msp->left < msp->right) ? (65535 - ctrl->value) : ctrl->value; @@ -1687,7 +1685,7 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) ctrl->value = msp->treble; return 0; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = MAX(msp->left, msp->right); + ctrl->value = max(msp->left, msp->right); return 0; default: return -EINVAL; @@ -1710,7 +1708,7 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) return 0; case V4L2_CID_AUDIO_BALANCE: balance=ctrl->value; - volume = MAX(msp->left, msp->right); + volume = max(msp->left, msp->right); set_volume=1; break; case V4L2_CID_AUDIO_BASS: @@ -1722,9 +1720,9 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) msp3400c_settreble(client, msp->treble); return 0; case V4L2_CID_AUDIO_VOLUME: - volume = MAX(msp->left, msp->right); + volume = max(msp->left, msp->right); - balance = (32768 * MIN(msp->left, msp->right)) / + balance = (32768 * min(msp->left, msp->right)) / (volume ? volume : 1); balance = (msp->left < msp->right) ? (65535 - balance) : balance; @@ -1739,8 +1737,8 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) } if (set_volume) { - msp->left = (MIN(65536 - balance, 32768) * volume) / 32768; - msp->right = (MIN(balance, 32768) * volume) / 32768; + msp->left = (min(65536 - balance, 32768) * volume) / 32768; + msp->right = (min(balance, 32768) * volume) / 32768; msp3400_dbg("volume=%d, balance=%d, left=%d, right=%d", volume,balance,msp->left,msp->right); @@ -1861,8 +1859,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (msp->muted) va->flags |= VIDEO_AUDIO_MUTE; - va->volume = MAX(msp->left, msp->right); - va->balance = (32768 * MIN(msp->left, msp->right)) / + va->volume = max(msp->left, msp->right); + va->balance = (32768 * min(msp->left, msp->right)) / (va->volume ? va->volume : 1); va->balance = (msp->left < msp->right) ? (65535 - va->balance) : va->balance; @@ -1881,9 +1879,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp3400_dbg("VIDIOCSAUDIO\n"); msp->muted = (va->flags & VIDEO_AUDIO_MUTE); - msp->left = (MIN(65536 - va->balance, 32768) * + msp->left = (min(65536 - va->balance, 32768) * va->volume) / 32768; - msp->right = (MIN(va->balance, 32768) * va->volume) / 32768; + msp->right = (min((int)va->balance, 32768) * va->volume) / 32768; msp->bass = va->bass; msp->treble = va->treble; msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n", -- cgit v1.2.3 From e0b2d7a89bb250fb0c9068c4481c9fd26c3fb227 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 9 Jan 2006 15:25:25 -0200 Subject: V4L/DVB (3160): Updates to the tveeprom eeprom checking Updates to the tveeprom eeprom checking Signed-of-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index a26ce7515dfa..9bb367863a6f 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -387,7 +387,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) && (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95)) start=0xa0; /* Generic em28xx offset */ - else if (((eeprom_data[0] & 0xf0) == 0x10) && + else if (((eeprom_data[0] & 0xe1) == 0x01) && (eeprom_data[1] == 0x00) && (eeprom_data[2] == 0x00) && (eeprom_data[8] == 0x84)) -- cgit v1.2.3 From 4abdfed5676e5ef7f2461bb76f5929068a9cc9cf Mon Sep 17 00:00:00 2001 From: Ricardo Cerqueira Date: Mon, 9 Jan 2006 15:25:25 -0200 Subject: V4L/DVB (3161): ir-kbd-gpio is now part of bttv - Merged ir-kbd-gpio into bttv as bttv-input, for consistency with other input modules Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 5 +- drivers/media/video/bttv-cards.c | 3 - drivers/media/video/bttv-driver.c | 13 +- drivers/media/video/bttv-gpio.c | 18 - drivers/media/video/bttv-input.c | 688 ++++++++++++++++++++++++++++++++++ drivers/media/video/bttv.h | 36 +- drivers/media/video/bttvp.h | 6 +- drivers/media/video/ir-kbd-gpio.c | 766 -------------------------------------- 8 files changed, 736 insertions(+), 799 deletions(-) create mode 100644 drivers/media/video/bttv-input.c delete mode 100644 drivers/media/video/ir-kbd-gpio.c diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 618a08ab940a..49aae8a54aa4 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -3,7 +3,8 @@ # bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ - bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o + bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ + bttv-input.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o @@ -12,7 +13,7 @@ tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ - tda7432.o tda9875.o ir-kbd-i2c.o ir-kbd-gpio.o + tda7432.o tda9875.o ir-kbd-i2c.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index c94092351b79..440f635e020f 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -2139,7 +2139,6 @@ struct tvcard bttv_tvcards[] = { .has_remote = 1, .gpiomask = 0x1b, .no_gpioirq = 1, - .any_irq = 1, }, [BTTV_BOARD_PV143] = { /* Jorge Boncompte - DTI2 */ @@ -3412,8 +3411,6 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->has_remote=1; if (!bttv_tvcards[btv->c.type].no_gpioirq) btv->gpioirq=1; - if (bttv_tvcards[btv->c.type].any_irq) - btv->any_irq = 1; if (bttv_tvcards[btv->c.type].audio_hook) btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 47347674a5e0..8bee7d5796dd 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3702,8 +3702,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs) btv=(struct bttv *)dev_id; - if (btv->any_irq) - handled = bttv_any_irq(&btv->c); + if (btv->custom_irq) + handled = btv->custom_irq(btv); count=0; while (1) { @@ -3739,9 +3739,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (astat&BT848_INT_VSYNC) btv->field_count++; - if (astat & BT848_INT_GPINT) { + if ((astat & BT848_INT_GPINT) && btv->remote) { wake_up(&btv->gpioq); - bttv_gpio_irq(&btv->c); + bttv_input_irq(btv); } if (astat & BT848_INT_I2CDONE) { @@ -4070,6 +4070,8 @@ static int __devinit bttv_probe(struct pci_dev *dev, if (bttv_tvcards[btv->c.type].has_dvb) bttv_sub_add_device(&btv->c, "dvb"); + bttv_input_init(btv); + /* everything is fine */ bttv_num++; return 0; @@ -4104,7 +4106,8 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev) /* tell gpio modules we are leaving ... */ btv->shutdown=1; wake_up(&btv->gpioq); - bttv_sub_del_devices(&btv->c); + bttv_input_fini(btv); + //bttv_sub_del_devices(&btv->c); /* unregister i2c_bus + input */ fini_bttv_i2c(btv); diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c index 616a5b7e510c..575ce8b8e714 100644 --- a/drivers/media/video/bttv-gpio.c +++ b/drivers/media/video/bttv-gpio.c @@ -113,24 +113,6 @@ void bttv_gpio_irq(struct bttv_core *core) } } -int bttv_any_irq(struct bttv_core *core) -{ - struct bttv_sub_driver *drv; - struct bttv_sub_device *dev; - struct list_head *item; - int handled = 0; - - list_for_each(item,&core->subs) { - dev = list_entry(item,struct bttv_sub_device,list); - drv = to_bttv_sub_drv(dev->dev.driver); - if (drv && drv->any_irq) { - if (drv->any_irq(dev)) - handled = 1; - } - } - return handled; -} - /* ----------------------------------------------------------------------- */ /* external: sub-driver register/unregister */ diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c new file mode 100644 index 000000000000..5027e10537cf --- /dev/null +++ b/drivers/media/video/bttv-input.c @@ -0,0 +1,688 @@ +/* + * + * Copyright (c) 2003 Gerd Knorr + * Copyright (c) 2003 Pavel Machek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "bttvp.h" + +/* ---------------------------------------------------------------------- */ + +static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = { + [ 34 ] = KEY_KP0, + [ 40 ] = KEY_KP1, + [ 24 ] = KEY_KP2, + [ 56 ] = KEY_KP3, + [ 36 ] = KEY_KP4, + [ 20 ] = KEY_KP5, + [ 52 ] = KEY_KP6, + [ 44 ] = KEY_KP7, + [ 28 ] = KEY_KP8, + [ 60 ] = KEY_KP9, + + [ 48 ] = KEY_EJECTCD, // Unmarked on my controller + [ 0 ] = KEY_POWER, + [ 18 ] = BTN_LEFT, // DISPLAY/L + [ 50 ] = BTN_RIGHT, // LOOP/R + [ 10 ] = KEY_MUTE, + [ 38 ] = KEY_RECORD, + [ 22 ] = KEY_PAUSE, + [ 54 ] = KEY_STOP, + [ 30 ] = KEY_VOLUMEDOWN, + [ 62 ] = KEY_VOLUMEUP, + + [ 32 ] = KEY_TUNER, // TV/FM + [ 16 ] = KEY_CD, + [ 8 ] = KEY_VIDEO, + [ 4 ] = KEY_AUDIO, + [ 12 ] = KEY_ZOOM, // full screen + [ 2 ] = KEY_INFO, // preview + [ 42 ] = KEY_SEARCH, // autoscan + [ 26 ] = KEY_STOP, // freeze + [ 58 ] = KEY_RECORD, // capture + [ 6 ] = KEY_PLAY, // unmarked + [ 46 ] = KEY_RED, // unmarked + [ 14 ] = KEY_GREEN, // unmarked + + [ 33 ] = KEY_YELLOW, // unmarked + [ 17 ] = KEY_CHANNELDOWN, + [ 49 ] = KEY_CHANNELUP, + [ 1 ] = KEY_BLUE, // unmarked +}; + +/* Matt Jesson >' + [ 0x3a ] = KEY_RECORD, // 'capture' + [ 0x0a ] = KEY_MUTE, // 'mute' + [ 0x2c ] = KEY_RECORD, // 'record' + [ 0x1c ] = KEY_PAUSE, // 'pause' + [ 0x3c ] = KEY_STOP, // 'stop' + [ 0x0c ] = KEY_PLAY, // 'play' + [ 0x2e ] = KEY_RED, // 'red' + [ 0x01 ] = KEY_BLUE, // 'blue' / 'cancel' + [ 0x0e ] = KEY_YELLOW, // 'yellow' / 'ok' + [ 0x21 ] = KEY_GREEN, // 'green' + [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -' + [ 0x31 ] = KEY_CHANNELUP, // 'channel +' + [ 0x1e ] = KEY_VOLUMEDOWN, // 'volume -' + [ 0x3e ] = KEY_VOLUMEUP, // 'volume +' +}; + +/* Attila Kondoros */ +static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = { + + [ 1 ] = KEY_KP1, + [ 2 ] = KEY_KP2, + [ 3 ] = KEY_KP3, + [ 4 ] = KEY_KP4, + [ 5 ] = KEY_KP5, + [ 6 ] = KEY_KP6, + [ 7 ] = KEY_KP7, + [ 8 ] = KEY_KP8, + [ 9 ] = KEY_KP9, + [ 0 ] = KEY_KP0, + [ 23 ] = KEY_LAST, // +100 + [ 10 ] = KEY_LIST, // recall + + + [ 28 ] = KEY_TUNER, // TV/FM + [ 21 ] = KEY_SEARCH, // scan + [ 18 ] = KEY_POWER, // power + [ 31 ] = KEY_VOLUMEDOWN, // vol up + [ 27 ] = KEY_VOLUMEUP, // vol down + [ 30 ] = KEY_CHANNELDOWN, // chn up + [ 26 ] = KEY_CHANNELUP, // chn down + + [ 17 ] = KEY_VIDEO, // video + [ 15 ] = KEY_ZOOM, // full screen + [ 19 ] = KEY_MUTE, // mute/unmute + [ 16 ] = KEY_TEXT, // min + + [ 13 ] = KEY_STOP, // freeze + [ 14 ] = KEY_RECORD, // record + [ 29 ] = KEY_PLAYPAUSE, // stop + [ 25 ] = KEY_PLAY, // play + + [ 22 ] = KEY_GOTO, // osd + [ 20 ] = KEY_REFRESH, // default + [ 12 ] = KEY_KPPLUS, // fine tune >>>> + [ 24 ] = KEY_KPMINUS // fine tune <<<< +}; + +/* ---------------------------------------------------------------------- */ + +static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = { + + [ 30 ] = KEY_POWER, // power + [ 7 ] = KEY_MEDIA, // source + [ 28 ] = KEY_SEARCH, // scan + +/* FIXME: duplicate keycodes? + * + * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>> + * The GPIO values are + * 6397fb for both "Scan <" and "CH -", + * 639ffb for "Scan >" and "CH+", + * 6384fb for "Tune <" and "<<<", + * 638cfb for "Tune >" and ">>>", regardless of the mask. + * + * [ 23 ] = KEY_BACK, // fm scan << + * [ 31 ] = KEY_FORWARD, // fm scan >> + * + * [ 4 ] = KEY_LEFT, // fm tuning < + * [ 12 ] = KEY_RIGHT, // fm tuning > + * + * For now, these four keys are disabled. Pressing them will generate + * the CH+/CH-/<<>> events + */ + + [ 3 ] = KEY_TUNER, // TV/FM + + [ 0 ] = KEY_RECORD, + [ 8 ] = KEY_STOP, + [ 17 ] = KEY_PLAY, + + [ 26 ] = KEY_PLAYPAUSE, // freeze + [ 25 ] = KEY_ZOOM, // zoom + [ 15 ] = KEY_TEXT, // min + + [ 1 ] = KEY_KP1, + [ 11 ] = KEY_KP2, + [ 27 ] = KEY_KP3, + [ 5 ] = KEY_KP4, + [ 9 ] = KEY_KP5, + [ 21 ] = KEY_KP6, + [ 6 ] = KEY_KP7, + [ 10 ] = KEY_KP8, + [ 18 ] = KEY_KP9, + [ 2 ] = KEY_KP0, + [ 16 ] = KEY_LAST, // +100 + [ 19 ] = KEY_LIST, // recall + + [ 31 ] = KEY_CHANNELUP, // chn down + [ 23 ] = KEY_CHANNELDOWN, // chn up + [ 22 ] = KEY_VOLUMEUP, // vol down + [ 20 ] = KEY_VOLUMEDOWN, // vol up + + [ 4 ] = KEY_KPMINUS, // <<< + [ 14 ] = KEY_SETUP, // function + [ 12 ] = KEY_KPPLUS, // >>> + + [ 13 ] = KEY_GOTO, // mts + [ 29 ] = KEY_REFRESH, // reset + [ 24 ] = KEY_MUTE // mute/unmute +}; + +static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = { + [0x00] = KEY_KP0, + [0x01] = KEY_KP1, + [0x02] = KEY_KP2, + [0x03] = KEY_KP3, + [0x04] = KEY_KP4, + [0x05] = KEY_KP5, + [0x06] = KEY_KP6, + [0x07] = KEY_KP7, + [0x08] = KEY_KP8, + [0x09] = KEY_KP9, + [0x0a] = KEY_TV, + [0x0b] = KEY_AUX, + [0x0c] = KEY_DVD, + [0x0d] = KEY_POWER, + [0x0e] = KEY_MHP, /* labelled 'Picture' */ + [0x0f] = KEY_AUDIO, + [0x10] = KEY_INFO, + [0x11] = KEY_F13, /* 16:9 */ + [0x12] = KEY_F14, /* 14:9 */ + [0x13] = KEY_EPG, + [0x14] = KEY_EXIT, + [0x15] = KEY_MENU, + [0x16] = KEY_UP, + [0x17] = KEY_DOWN, + [0x18] = KEY_LEFT, + [0x19] = KEY_RIGHT, + [0x1a] = KEY_ENTER, + [0x1b] = KEY_CHANNELUP, + [0x1c] = KEY_CHANNELDOWN, + [0x1d] = KEY_VOLUMEUP, + [0x1e] = KEY_VOLUMEDOWN, + [0x1f] = KEY_RED, + [0x20] = KEY_GREEN, + [0x21] = KEY_YELLOW, + [0x22] = KEY_BLUE, + [0x23] = KEY_SUBTITLE, + [0x24] = KEY_F15, /* AD */ + [0x25] = KEY_TEXT, + [0x26] = KEY_MUTE, + [0x27] = KEY_REWIND, + [0x28] = KEY_STOP, + [0x29] = KEY_PLAY, + [0x2a] = KEY_FASTFORWARD, + [0x2b] = KEY_F16, /* chapter */ + [0x2c] = KEY_PAUSE, + [0x2d] = KEY_PLAY, + [0x2e] = KEY_RECORD, + [0x2f] = KEY_F17, /* picture in picture */ + [0x30] = KEY_KPPLUS, /* zoom in */ + [0x31] = KEY_KPMINUS, /* zoom out */ + [0x32] = KEY_F18, /* capture */ + [0x33] = KEY_F19, /* web */ + [0x34] = KEY_EMAIL, + [0x35] = KEY_PHONE, + [0x36] = KEY_PC +}; + +static int debug; +module_param(debug, int, 0644); /* debug level (0,1,2) */ +static int repeat_delay = 500; +module_param(repeat_delay, int, 0644); +static int repeat_period = 33; +module_param(repeat_period, int, 0644); + +#define DEVNAME "bttv-input" + +/* ---------------------------------------------------------------------- */ + +static void ir_handle_key(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + u32 gpio,data; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + if (ir->polling) { + if (ir->last_gpio == gpio) + return; + ir->last_gpio = gpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + dprintk(KERN_INFO DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || + (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { + ir_input_keydown(ir->dev,&ir->ir,data,data); + } else { + ir_input_nokey(ir->dev,&ir->ir); + } + +} + +void bttv_input_irq(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + + if (!ir->polling) + ir_handle_key(btv); +} + +static void bttv_input_timer(unsigned long data) +{ + struct bttv *btv = (struct bttv*)data; + struct bttv_ir *ir = btv->remote; + unsigned long timeout; + + ir_handle_key(btv); + timeout = jiffies + (ir->polling * HZ / 1000); + mod_timer(&ir->timer, timeout); +} + +/* ---------------------------------------------------------------*/ + +static int rc5_remote_gap = 885; +module_param(rc5_remote_gap, int, 0644); +static int rc5_key_timeout = 200; +module_param(rc5_key_timeout, int, 0644); + +#define RC5_START(x) (((x)>>12)&3) +#define RC5_TOGGLE(x) (((x)>>11)&1) +#define RC5_ADDR(x) (((x)>>6)&31) +#define RC5_INSTR(x) ((x)&63) + +/* decode raw bit pattern to RC5 code */ +static u32 rc5_decode(unsigned int code) +{ + unsigned int org_code = code; + unsigned int pair; + unsigned int rc5 = 0; + int i; + + code = (code << 1) | 1; + for (i = 0; i < 14; ++i) { + pair = code & 0x3; + code >>= 2; + + rc5 <<= 1; + switch (pair) { + case 0: + case 2: + break; + case 1: + rc5 |= 1; + break; + case 3: + dprintk(KERN_WARNING "bad code: %x\n", org_code); + return 0; + } + } + dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " + "instr=%x\n", rc5, org_code, RC5_START(rc5), + RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); + return rc5; +} + +static int bttv_rc5_irq(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + struct timeval tv; + u32 gpio; + u32 gap; + unsigned long current_jiffies, timeout; + + /* read gpio port */ + gpio = bttv_gpio_read(&btv->c); + + /* remote IRQ? */ + if (!(gpio & 0x20)) + return 0; + + /* get time of bit */ + current_jiffies = jiffies; + do_gettimeofday(&tv); + + /* avoid overflow with gap >1s */ + if (tv.tv_sec - ir->base_time.tv_sec > 1) { + gap = 200000; + } else { + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + } + + /* active code => add bit */ + if (ir->active) { + /* only if in the code (otherwise spurious IRQ or timer + late) */ + if (ir->last_bit < 28) { + ir->last_bit = (gap - rc5_remote_gap / 2) / + rc5_remote_gap; + ir->code |= 1 << ir->last_bit; + } + /* starting new code */ + } else { + ir->active = 1; + ir->code = 0; + ir->base_time = tv; + ir->last_bit = 0; + + timeout = current_jiffies + (500 + 30 * HZ) / 1000; + mod_timer(&ir->timer_end, timeout); + } + + /* toggle GPIO pin 4 to reset the irq */ + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + bttv_gpio_write(&btv->c, gpio | (1 << 4)); + return 1; +} + + +static void bttv_rc5_timer_end(unsigned long data) +{ + struct bttv_ir *ir = (struct bttv_ir *)data; + struct timeval tv; + unsigned long current_jiffies, timeout; + u32 gap; + + /* get time */ + current_jiffies = jiffies; + do_gettimeofday(&tv); + + /* avoid overflow with gap >1s */ + if (tv.tv_sec - ir->base_time.tv_sec > 1) { + gap = 200000; + } else { + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + } + + /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */ + if (gap < 28000) { + dprintk(KERN_WARNING "spurious timer_end\n"); + return; + } + + ir->active = 0; + if (ir->last_bit < 20) { + /* ignore spurious codes (caused by light/other remotes) */ + dprintk(KERN_WARNING "short code: %x\n", ir->code); + } else { + u32 rc5 = rc5_decode(ir->code); + + /* two start bits? */ + if (RC5_START(rc5) != 3) { + dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5)); + + /* right address? */ + } else if (RC5_ADDR(rc5) == 0x0) { + u32 toggle = RC5_TOGGLE(rc5); + u32 instr = RC5_INSTR(rc5); + + /* Good code, decide if repeat/repress */ + if (toggle != RC5_TOGGLE(ir->last_rc5) || + instr != RC5_INSTR(ir->last_rc5)) { + dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr, + toggle); + ir_input_nokey(ir->dev, &ir->ir); + ir_input_keydown(ir->dev, &ir->ir, instr, + instr); + } + + /* Set/reset key-up timer */ + timeout = current_jiffies + (500 + rc5_key_timeout + * HZ) / 1000; + mod_timer(&ir->timer_keyup, timeout); + + /* Save code for repeat test */ + ir->last_rc5 = rc5; + } + } +} + +static void bttv_rc5_timer_keyup(unsigned long data) +{ + struct bttv_ir *ir = (struct bttv_ir *)data; + + dprintk(KERN_DEBUG "key released\n"); + ir_input_nokey(ir->dev, &ir->ir); +} + +/* ---------------------------------------------------------------------- */ + +int bttv_input_init(struct bttv *btv) +{ + struct bttv_ir *ir; + IR_KEYTAB_TYPE *ir_codes = NULL; + struct input_dev *input_dev; + int ir_type = IR_TYPE_OTHER; + + if (!btv->has_remote) + return -ENODEV; + + ir = kzalloc(sizeof(*ir),GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) { + kfree(ir); + input_free_device(input_dev); + return -ENOMEM; + } + memset(ir,0,sizeof(*ir)); + + /* detect & configure */ + switch (btv->c.type) { + case BTTV_BOARD_AVERMEDIA: + case BTTV_BOARD_AVPHONE98: + case BTTV_BOARD_AVERMEDIA98: + ir_codes = ir_codes_avermedia; + ir->mask_keycode = 0xf88000; + ir->mask_keydown = 0x010000; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_AVDVBT_761: + case BTTV_BOARD_AVDVBT_771: + ir_codes = ir_codes_avermedia_dvbt; + ir->mask_keycode = 0x0f00c0; + ir->mask_keydown = 0x000020; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_PXELVWPLTVPAK: + ir_codes = ir_codes_pixelview; + ir->mask_keycode = 0x003e00; + ir->mask_keyup = 0x010000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_PV_BT878P_9B: + case BTTV_BOARD_PV_BT878P_PLUS: + ir_codes = ir_codes_pixelview; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_WINFAST2000: + ir_codes = ir_codes_winfast; + ir->mask_keycode = 0x1f8; + break; + case BTTV_BOARD_MAGICTVIEW061: + case BTTV_BOARD_MAGICTVIEW063: + ir_codes = ir_codes_winfast; + ir->mask_keycode = 0x0008e000; + ir->mask_keydown = 0x00200000; + break; + case BTTV_BOARD_APAC_VIEWCOMP: + ir_codes = ir_codes_apac_viewcomp; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: + ir_codes = ir_codes_conceptronic; + ir->mask_keycode = 0x001F00; + ir->mask_keyup = 0x006000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_NEBULA_DIGITV: + ir_codes = ir_codes_nebula; + btv->custom_irq = bttv_rc5_irq; + ir->rc5_gpio = 1; + break; + } + if (NULL == ir_codes) { + dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type); + kfree(ir); + input_free_device(input_dev); + return -ENODEV; + } + + if (ir->rc5_gpio) { + u32 gpio; + /* enable remote irq */ + bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4); + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + bttv_gpio_write(&btv->c, gpio | (1 << 4)); + } else { + /* init hardware-specific stuff */ + bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0); + } + + /* init input device */ + ir->dev = input_dev; + + snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", + btv->c.type); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(btv->c.pci)); + + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; + if (btv->c.pci->subsystem_vendor) { + input_dev->id.vendor = btv->c.pci->subsystem_vendor; + input_dev->id.product = btv->c.pci->subsystem_device; + } else { + input_dev->id.vendor = btv->c.pci->vendor; + input_dev->id.product = btv->c.pci->device; + } + input_dev->cdev.dev = &btv->c.pci->dev; + + btv->remote = ir; + if (ir->polling) { + init_timer(&ir->timer); + ir->timer.function = bttv_input_timer; + ir->timer.data = (unsigned long)btv; + ir->timer.expires = jiffies + HZ; + add_timer(&ir->timer); + } else if (ir->rc5_gpio) { + /* set timer_end for code completion */ + init_timer(&ir->timer_end); + ir->timer_end.function = bttv_rc5_timer_end; + ir->timer_end.data = (unsigned long)ir; + + init_timer(&ir->timer_keyup); + ir->timer_keyup.function = bttv_rc5_timer_keyup; + ir->timer_keyup.data = (unsigned long)ir; + } + + /* all done */ + input_register_device(btv->remote->dev); + printk(DEVNAME ": %s detected at %s\n",ir->dev->name,ir->dev->phys); + + /* the remote isn't as bouncy as a keyboard */ + ir->dev->rep[REP_DELAY] = repeat_delay; + ir->dev->rep[REP_PERIOD] = repeat_period; + + return 0; +} + +void bttv_input_fini(struct bttv *btv) +{ + if (btv->remote == NULL) + return; + + if (btv->remote->polling) { + del_timer_sync(&btv->remote->timer); + flush_scheduled_work(); + } + + + if (btv->remote->rc5_gpio) { + u32 gpio; + + del_timer(&btv->remote->timer_end); + flush_scheduled_work(); + + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + } + + input_unregister_device(btv->remote->dev); + kfree(btv->remote); + btv->remote = NULL; +} + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index a5f172fe9f98..9feaa6bab207 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -16,6 +16,8 @@ #include #include +#include +#include /* ---------------------------------------------------------- */ /* exported by bttv-cards.c */ @@ -211,6 +213,34 @@ struct bttv_core { struct bttv; + +struct bttv_ir { + struct input_dev *dev; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + struct work_struct work; + struct timer_list timer; + + /* RC5 gpio */ + u32 rc5_gpio; + struct timer_list timer_end; /* timer_end for code completion */ + struct timer_list timer_keyup; /* timer_end for key release */ + u32 last_rc5; /* last good rc5 code */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + int active; /* building raw code */ +}; + struct tvcard { char *name; @@ -236,7 +266,6 @@ struct tvcard unsigned int has_dvb:1; unsigned int has_remote:1; unsigned int no_gpioirq:1; - unsigned int any_irq:1; /* other settings */ unsigned int pll; @@ -336,7 +365,6 @@ struct bttv_sub_driver { struct device_driver drv; char wanted[BUS_ID_SIZE]; void (*gpio_irq)(struct bttv_sub_device *sub); - int (*any_irq)(struct bttv_sub_device *sub); }; #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) @@ -364,6 +392,10 @@ extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, unsigned char b2, int both); extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + #endif /* _BTTV_H_ */ /* * Local variables: diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index d04d02385349..55759f698e02 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -209,7 +209,6 @@ extern struct bus_type bttv_sub_bus_type; int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); void bttv_gpio_irq(struct bttv_core *core); -int bttv_any_irq(struct bttv_core *core); /* ---------------------------------------------------------- */ @@ -275,7 +274,8 @@ struct bttv { struct bttv_pll_info pll; int triton1; int gpioirq; - int any_irq; + int (*custom_irq)(struct bttv *btv); + int use_i2c_hw; /* old gpio interface */ @@ -300,7 +300,7 @@ struct bttv { /* infrared remote */ int has_remote; - struct bttv_input *remote; + struct bttv_ir *remote; /* locking */ spinlock_t s_lock; diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c deleted file mode 100644 index 556da9ff128f..000000000000 --- a/drivers/media/video/ir-kbd-gpio.c +++ /dev/null @@ -1,766 +0,0 @@ -/* - * - * Copyright (c) 2003 Gerd Knorr - * Copyright (c) 2003 Pavel Machek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include - -/* ---------------------------------------------------------------------- */ - -static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = { - [ 34 ] = KEY_KP0, - [ 40 ] = KEY_KP1, - [ 24 ] = KEY_KP2, - [ 56 ] = KEY_KP3, - [ 36 ] = KEY_KP4, - [ 20 ] = KEY_KP5, - [ 52 ] = KEY_KP6, - [ 44 ] = KEY_KP7, - [ 28 ] = KEY_KP8, - [ 60 ] = KEY_KP9, - - [ 48 ] = KEY_EJECTCD, // Unmarked on my controller - [ 0 ] = KEY_POWER, - [ 18 ] = BTN_LEFT, // DISPLAY/L - [ 50 ] = BTN_RIGHT, // LOOP/R - [ 10 ] = KEY_MUTE, - [ 38 ] = KEY_RECORD, - [ 22 ] = KEY_PAUSE, - [ 54 ] = KEY_STOP, - [ 30 ] = KEY_VOLUMEDOWN, - [ 62 ] = KEY_VOLUMEUP, - - [ 32 ] = KEY_TUNER, // TV/FM - [ 16 ] = KEY_CD, - [ 8 ] = KEY_VIDEO, - [ 4 ] = KEY_AUDIO, - [ 12 ] = KEY_ZOOM, // full screen - [ 2 ] = KEY_INFO, // preview - [ 42 ] = KEY_SEARCH, // autoscan - [ 26 ] = KEY_STOP, // freeze - [ 58 ] = KEY_RECORD, // capture - [ 6 ] = KEY_PLAY, // unmarked - [ 46 ] = KEY_RED, // unmarked - [ 14 ] = KEY_GREEN, // unmarked - - [ 33 ] = KEY_YELLOW, // unmarked - [ 17 ] = KEY_CHANNELDOWN, - [ 49 ] = KEY_CHANNELUP, - [ 1 ] = KEY_BLUE, // unmarked -}; - -/* Matt Jesson >' - [ 0x3a ] = KEY_RECORD, // 'capture' - [ 0x0a ] = KEY_MUTE, // 'mute' - [ 0x2c ] = KEY_RECORD, // 'record' - [ 0x1c ] = KEY_PAUSE, // 'pause' - [ 0x3c ] = KEY_STOP, // 'stop' - [ 0x0c ] = KEY_PLAY, // 'play' - [ 0x2e ] = KEY_RED, // 'red' - [ 0x01 ] = KEY_BLUE, // 'blue' / 'cancel' - [ 0x0e ] = KEY_YELLOW, // 'yellow' / 'ok' - [ 0x21 ] = KEY_GREEN, // 'green' - [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -' - [ 0x31 ] = KEY_CHANNELUP, // 'channel +' - [ 0x1e ] = KEY_VOLUMEDOWN, // 'volume -' - [ 0x3e ] = KEY_VOLUMEUP, // 'volume +' -}; - -/* Attila Kondoros */ -static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = { - - [ 1 ] = KEY_KP1, - [ 2 ] = KEY_KP2, - [ 3 ] = KEY_KP3, - [ 4 ] = KEY_KP4, - [ 5 ] = KEY_KP5, - [ 6 ] = KEY_KP6, - [ 7 ] = KEY_KP7, - [ 8 ] = KEY_KP8, - [ 9 ] = KEY_KP9, - [ 0 ] = KEY_KP0, - [ 23 ] = KEY_LAST, // +100 - [ 10 ] = KEY_LIST, // recall - - - [ 28 ] = KEY_TUNER, // TV/FM - [ 21 ] = KEY_SEARCH, // scan - [ 18 ] = KEY_POWER, // power - [ 31 ] = KEY_VOLUMEDOWN, // vol up - [ 27 ] = KEY_VOLUMEUP, // vol down - [ 30 ] = KEY_CHANNELDOWN, // chn up - [ 26 ] = KEY_CHANNELUP, // chn down - - [ 17 ] = KEY_VIDEO, // video - [ 15 ] = KEY_ZOOM, // full screen - [ 19 ] = KEY_MUTE, // mute/unmute - [ 16 ] = KEY_TEXT, // min - - [ 13 ] = KEY_STOP, // freeze - [ 14 ] = KEY_RECORD, // record - [ 29 ] = KEY_PLAYPAUSE, // stop - [ 25 ] = KEY_PLAY, // play - - [ 22 ] = KEY_GOTO, // osd - [ 20 ] = KEY_REFRESH, // default - [ 12 ] = KEY_KPPLUS, // fine tune >>>> - [ 24 ] = KEY_KPMINUS // fine tune <<<< -}; - -/* ---------------------------------------------------------------------- */ - -/* Ricardo Cerqueira */ -/* Weird matching, since the remote has "uncommon" keys */ - -static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = { - - [ 30 ] = KEY_POWER, // power - [ 7 ] = KEY_MEDIA, // source - [ 28 ] = KEY_SEARCH, // scan - -/* FIXME: duplicate keycodes? - * - * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>> - * The GPIO values are - * 6397fb for both "Scan <" and "CH -", - * 639ffb for "Scan >" and "CH+", - * 6384fb for "Tune <" and "<<<", - * 638cfb for "Tune >" and ">>>", regardless of the mask. - * - * [ 23 ] = KEY_BACK, // fm scan << - * [ 31 ] = KEY_FORWARD, // fm scan >> - * - * [ 4 ] = KEY_LEFT, // fm tuning < - * [ 12 ] = KEY_RIGHT, // fm tuning > - * - * For now, these four keys are disabled. Pressing them will generate - * the CH+/CH-/<<>> events - */ - - [ 3 ] = KEY_TUNER, // TV/FM - - [ 0 ] = KEY_RECORD, - [ 8 ] = KEY_STOP, - [ 17 ] = KEY_PLAY, - - [ 26 ] = KEY_PLAYPAUSE, // freeze - [ 25 ] = KEY_ZOOM, // zoom - [ 15 ] = KEY_TEXT, // min - - [ 1 ] = KEY_KP1, - [ 11 ] = KEY_KP2, - [ 27 ] = KEY_KP3, - [ 5 ] = KEY_KP4, - [ 9 ] = KEY_KP5, - [ 21 ] = KEY_KP6, - [ 6 ] = KEY_KP7, - [ 10 ] = KEY_KP8, - [ 18 ] = KEY_KP9, - [ 2 ] = KEY_KP0, - [ 16 ] = KEY_LAST, // +100 - [ 19 ] = KEY_LIST, // recall - - [ 31 ] = KEY_CHANNELUP, // chn down - [ 23 ] = KEY_CHANNELDOWN, // chn up - [ 22 ] = KEY_VOLUMEUP, // vol down - [ 20 ] = KEY_VOLUMEDOWN, // vol up - - [ 4 ] = KEY_KPMINUS, // <<< - [ 14 ] = KEY_SETUP, // function - [ 12 ] = KEY_KPPLUS, // >>> - - [ 13 ] = KEY_GOTO, // mts - [ 29 ] = KEY_REFRESH, // reset - [ 24 ] = KEY_MUTE // mute/unmute -}; - -static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = { - [0x00] = KEY_KP0, - [0x01] = KEY_KP1, - [0x02] = KEY_KP2, - [0x03] = KEY_KP3, - [0x04] = KEY_KP4, - [0x05] = KEY_KP5, - [0x06] = KEY_KP6, - [0x07] = KEY_KP7, - [0x08] = KEY_KP8, - [0x09] = KEY_KP9, - [0x0a] = KEY_TV, - [0x0b] = KEY_AUX, - [0x0c] = KEY_DVD, - [0x0d] = KEY_POWER, - [0x0e] = KEY_MHP, /* labelled 'Picture' */ - [0x0f] = KEY_AUDIO, - [0x10] = KEY_INFO, - [0x11] = KEY_F13, /* 16:9 */ - [0x12] = KEY_F14, /* 14:9 */ - [0x13] = KEY_EPG, - [0x14] = KEY_EXIT, - [0x15] = KEY_MENU, - [0x16] = KEY_UP, - [0x17] = KEY_DOWN, - [0x18] = KEY_LEFT, - [0x19] = KEY_RIGHT, - [0x1a] = KEY_ENTER, - [0x1b] = KEY_CHANNELUP, - [0x1c] = KEY_CHANNELDOWN, - [0x1d] = KEY_VOLUMEUP, - [0x1e] = KEY_VOLUMEDOWN, - [0x1f] = KEY_RED, - [0x20] = KEY_GREEN, - [0x21] = KEY_YELLOW, - [0x22] = KEY_BLUE, - [0x23] = KEY_SUBTITLE, - [0x24] = KEY_F15, /* AD */ - [0x25] = KEY_TEXT, - [0x26] = KEY_MUTE, - [0x27] = KEY_REWIND, - [0x28] = KEY_STOP, - [0x29] = KEY_PLAY, - [0x2a] = KEY_FASTFORWARD, - [0x2b] = KEY_F16, /* chapter */ - [0x2c] = KEY_PAUSE, - [0x2d] = KEY_PLAY, - [0x2e] = KEY_RECORD, - [0x2f] = KEY_F17, /* picture in picture */ - [0x30] = KEY_KPPLUS, /* zoom in */ - [0x31] = KEY_KPMINUS, /* zoom out */ - [0x32] = KEY_F18, /* capture */ - [0x33] = KEY_F19, /* web */ - [0x34] = KEY_EMAIL, - [0x35] = KEY_PHONE, - [0x36] = KEY_PC -}; - -struct IR { - struct bttv_sub_device *sub; - struct input_dev *input; - struct ir_input_state ir; - char name[32]; - char phys[32]; - - /* Usual gpio signalling */ - - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; - u32 polling; - u32 last_gpio; - struct work_struct work; - struct timer_list timer; - - /* RC5 gpio */ - u32 rc5_gpio; - struct timer_list timer_end; /* timer_end for code completion */ - struct timer_list timer_keyup; /* timer_end for key release */ - u32 last_rc5; /* last good rc5 code */ - u32 last_bit; /* last raw bit seen */ - u32 code; /* raw code under construction */ - struct timeval base_time; /* time of last seen code */ - int active; /* building raw code */ -}; - -static int debug; -module_param(debug, int, 0644); /* debug level (0,1,2) */ -static int repeat_delay = 500; -module_param(repeat_delay, int, 0644); -static int repeat_period = 33; -module_param(repeat_period, int, 0644); - -#define DEVNAME "ir-kbd-gpio" -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG DEVNAME ": " fmt , ## arg) - -static void ir_irq(struct bttv_sub_device *sub); -static int ir_probe(struct device *dev); -static int ir_remove(struct device *dev); - -static struct bttv_sub_driver driver = { - .drv = { - .name = DEVNAME, - .probe = ir_probe, - .remove = ir_remove, - }, - .gpio_irq = ir_irq, -}; - -/* ---------------------------------------------------------------------- */ - -static void ir_handle_key(struct IR *ir) -{ - u32 gpio,data; - - /* read gpio value */ - gpio = bttv_gpio_read(ir->sub->core); - if (ir->polling) { - if (ir->last_gpio == gpio) - return; - ir->last_gpio = gpio; - } - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk(DEVNAME ": irq gpio=0x%x code=%d | %s%s%s\n", - gpio, data, - ir->polling ? "poll" : "irq", - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); - - if (ir->mask_keydown) { - /* bit set on keydown */ - if (gpio & ir->mask_keydown) { - ir_input_keydown(ir->input, &ir->ir, data, data); - } else { - ir_input_nokey(ir->input, &ir->ir); - } - - } else if (ir->mask_keyup) { - /* bit cleared on keydown */ - if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(ir->input, &ir->ir, data, data); - } else { - ir_input_nokey(ir->input, &ir->ir); - } - - } else { - /* can't disturgissh keydown/up :-/ */ - ir_input_keydown(ir->input, &ir->ir, data, data); - ir_input_nokey(ir->input, &ir->ir); - } -} - -static void ir_irq(struct bttv_sub_device *sub) -{ - struct IR *ir = dev_get_drvdata(&sub->dev); - - if (!ir->polling) - ir_handle_key(ir); -} - -static void ir_timer(unsigned long data) -{ - struct IR *ir = (struct IR*)data; - - schedule_work(&ir->work); -} - -static void ir_work(void *data) -{ - struct IR *ir = data; - unsigned long timeout; - - ir_handle_key(ir); - timeout = jiffies + (ir->polling * HZ / 1000); - mod_timer(&ir->timer, timeout); -} - -/* ---------------------------------------------------------------*/ - -static int rc5_remote_gap = 885; -module_param(rc5_remote_gap, int, 0644); -static int rc5_key_timeout = 200; -module_param(rc5_key_timeout, int, 0644); - -#define RC5_START(x) (((x)>>12)&3) -#define RC5_TOGGLE(x) (((x)>>11)&1) -#define RC5_ADDR(x) (((x)>>6)&31) -#define RC5_INSTR(x) ((x)&63) - -/* decode raw bit pattern to RC5 code */ -static u32 rc5_decode(unsigned int code) -{ - unsigned int org_code = code; - unsigned int pair; - unsigned int rc5 = 0; - int i; - - code = (code << 1) | 1; - for (i = 0; i < 14; ++i) { - pair = code & 0x3; - code >>= 2; - - rc5 <<= 1; - switch (pair) { - case 0: - case 2: - break; - case 1: - rc5 |= 1; - break; - case 3: - dprintk("bad code: %x\n", org_code); - return 0; - } - } - dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " - "instr=%x\n", rc5, org_code, RC5_START(rc5), - RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); - return rc5; -} - -static int ir_rc5_irq(struct bttv_sub_device *sub) -{ - struct IR *ir = dev_get_drvdata(&sub->dev); - struct timeval tv; - u32 gpio; - u32 gap; - unsigned long current_jiffies, timeout; - - /* read gpio port */ - gpio = bttv_gpio_read(ir->sub->core); - - /* remote IRQ? */ - if (!(gpio & 0x20)) - return 0; - - /* get time of bit */ - current_jiffies = jiffies; - do_gettimeofday(&tv); - - /* avoid overflow with gap >1s */ - if (tv.tv_sec - ir->base_time.tv_sec > 1) { - gap = 200000; - } else { - gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + - tv.tv_usec - ir->base_time.tv_usec; - } - - /* active code => add bit */ - if (ir->active) { - /* only if in the code (otherwise spurious IRQ or timer - late) */ - if (ir->last_bit < 28) { - ir->last_bit = (gap - rc5_remote_gap / 2) / - rc5_remote_gap; - ir->code |= 1 << ir->last_bit; - } - /* starting new code */ - } else { - ir->active = 1; - ir->code = 0; - ir->base_time = tv; - ir->last_bit = 0; - - timeout = current_jiffies + (500 + 30 * HZ) / 1000; - mod_timer(&ir->timer_end, timeout); - } - - /* toggle GPIO pin 4 to reset the irq */ - bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4)); - bttv_gpio_write(ir->sub->core, gpio | (1 << 4)); - return 1; -} - -static void ir_rc5_timer_end(unsigned long data) -{ - struct IR *ir = (struct IR *)data; - struct timeval tv; - unsigned long current_jiffies, timeout; - u32 gap; - - /* get time */ - current_jiffies = jiffies; - do_gettimeofday(&tv); - - /* avoid overflow with gap >1s */ - if (tv.tv_sec - ir->base_time.tv_sec > 1) { - gap = 200000; - } else { - gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + - tv.tv_usec - ir->base_time.tv_usec; - } - - /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */ - if (gap < 28000) { - dprintk("spurious timer_end\n"); - return; - } - - ir->active = 0; - if (ir->last_bit < 20) { - /* ignore spurious codes (caused by light/other remotes) */ - dprintk("short code: %x\n", ir->code); - } else { - u32 rc5 = rc5_decode(ir->code); - - /* two start bits? */ - if (RC5_START(rc5) != 3) { - dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5)); - - /* right address? */ - } else if (RC5_ADDR(rc5) == 0x0) { - u32 toggle = RC5_TOGGLE(rc5); - u32 instr = RC5_INSTR(rc5); - - /* Good code, decide if repeat/repress */ - if (toggle != RC5_TOGGLE(ir->last_rc5) || - instr != RC5_INSTR(ir->last_rc5)) { - dprintk("instruction %x, toggle %x\n", instr, - toggle); - ir_input_nokey(ir->input, &ir->ir); - ir_input_keydown(ir->input, &ir->ir, instr, - instr); - } - - /* Set/reset key-up timer */ - timeout = current_jiffies + (500 + rc5_key_timeout - * HZ) / 1000; - mod_timer(&ir->timer_keyup, timeout); - - /* Save code for repeat test */ - ir->last_rc5 = rc5; - } - } -} - -static void ir_rc5_timer_keyup(unsigned long data) -{ - struct IR *ir = (struct IR *)data; - - dprintk("key released\n"); - ir_input_nokey(ir->input, &ir->ir); -} - -/* ---------------------------------------------------------------------- */ - -static int ir_probe(struct device *dev) -{ - struct bttv_sub_device *sub = to_bttv_sub_dev(dev); - struct IR *ir; - struct input_dev *input_dev; - IR_KEYTAB_TYPE *ir_codes = NULL; - int ir_type = IR_TYPE_OTHER; - - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ir || !input_dev) { - kfree(ir); - input_free_device(input_dev); - return -ENOMEM; - } - - /* detect & configure */ - switch (sub->core->type) { - case BTTV_BOARD_AVERMEDIA: - case BTTV_BOARD_AVPHONE98: - case BTTV_BOARD_AVERMEDIA98: - ir_codes = ir_codes_avermedia; - ir->mask_keycode = 0xf88000; - ir->mask_keydown = 0x010000; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_AVDVBT_761: - case BTTV_BOARD_AVDVBT_771: - ir_codes = ir_codes_avermedia_dvbt; - ir->mask_keycode = 0x0f00c0; - ir->mask_keydown = 0x000020; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_PXELVWPLTVPAK: - ir_codes = ir_codes_pixelview; - ir->mask_keycode = 0x003e00; - ir->mask_keyup = 0x010000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_PV_BT878P_9B: - case BTTV_BOARD_PV_BT878P_PLUS: - ir_codes = ir_codes_pixelview; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x008000; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_WINFAST2000: - ir_codes = ir_codes_winfast; - ir->mask_keycode = 0x1f8; - break; - case BTTV_BOARD_MAGICTVIEW061: - case BTTV_BOARD_MAGICTVIEW063: - ir_codes = ir_codes_winfast; - ir->mask_keycode = 0x0008e000; - ir->mask_keydown = 0x00200000; - break; - case BTTV_BOARD_APAC_VIEWCOMP: - ir_codes = ir_codes_apac_viewcomp; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x008000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: - ir_codes = ir_codes_conceptronic; - ir->mask_keycode = 0x001F00; - ir->mask_keyup = 0x006000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_NEBULA_DIGITV: - ir_codes = ir_codes_nebula; - driver.any_irq = ir_rc5_irq; - driver.gpio_irq = NULL; - ir->rc5_gpio = 1; - break; - } - if (NULL == ir_codes) { - kfree(ir); - input_free_device(input_dev); - return -ENODEV; - } - - if (ir->rc5_gpio) { - u32 gpio; - /* enable remote irq */ - bttv_gpio_inout(sub->core, (1 << 4), 1 << 4); - gpio = bttv_gpio_read(sub->core); - bttv_gpio_write(sub->core, gpio & ~(1 << 4)); - bttv_gpio_write(sub->core, gpio | (1 << 4)); - } else { - /* init hardware-specific stuff */ - bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0); - } - - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", - sub->core->type); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", - pci_name(sub->core->pci)); - - ir->input = input_dev; - ir->sub = sub; - ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); - input_dev->name = ir->name; - input_dev->phys = ir->phys; - input_dev->id.bustype = BUS_PCI; - input_dev->id.version = 1; - if (sub->core->pci->subsystem_vendor) { - input_dev->id.vendor = sub->core->pci->subsystem_vendor; - input_dev->id.product = sub->core->pci->subsystem_device; - } else { - input_dev->id.vendor = sub->core->pci->vendor; - input_dev->id.product = sub->core->pci->device; - } - input_dev->cdev.dev = &sub->core->pci->dev; - - if (ir->polling) { - INIT_WORK(&ir->work, ir_work, ir); - init_timer(&ir->timer); - ir->timer.function = ir_timer; - ir->timer.data = (unsigned long)ir; - schedule_work(&ir->work); - } else if (ir->rc5_gpio) { - /* set timer_end for code completion */ - init_timer(&ir->timer_end); - ir->timer_end.function = ir_rc5_timer_end; - ir->timer_end.data = (unsigned long)ir; - - init_timer(&ir->timer_keyup); - ir->timer_keyup.function = ir_rc5_timer_keyup; - ir->timer_keyup.data = (unsigned long)ir; - } - - /* all done */ - dev_set_drvdata(dev, ir); - input_register_device(ir->input); - - /* the remote isn't as bouncy as a keyboard */ - ir->input->rep[REP_DELAY] = repeat_delay; - ir->input->rep[REP_PERIOD] = repeat_period; - - return 0; -} - -static int ir_remove(struct device *dev) -{ - struct IR *ir = dev_get_drvdata(dev); - - if (ir->polling) { - del_timer(&ir->timer); - flush_scheduled_work(); - } - - if (ir->rc5_gpio) { - u32 gpio; - - del_timer(&ir->timer_end); - flush_scheduled_work(); - - gpio = bttv_gpio_read(ir->sub->core); - bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4)); - } - - input_unregister_device(ir->input); - kfree(ir); - return 0; -} - -/* ---------------------------------------------------------------------- */ - -MODULE_AUTHOR("Gerd Knorr, Pavel Machek"); -MODULE_DESCRIPTION("input driver for bt8x8 gpio IR remote controls"); -MODULE_LICENSE("GPL"); - -static int ir_init(void) -{ - return bttv_sub_register(&driver, "remote"); -} - -static void ir_fini(void) -{ - bttv_sub_unregister(&driver); -} - -module_init(ir_init); -module_exit(ir_fini); - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.3 From 5ea892f156310132a1bd37c45c3ca09663cfb9fb Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:26 -0200 Subject: V4L/DVB (3166): "Philips 1236D ATSC/NTSC dual in" - fix typo. - "Philips 1236D ATSC/NTSC dual in" - fix typo. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 2 +- drivers/media/video/tuner-simple.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 9d6544ea9f41..1d658a388b80 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3) tuner=39 - LG NTSC (newer TAPC series) tuner=40 - HITACHI V7-J180AT tuner=41 - Philips PAL_MK (FI1216 MK) -tuner=42 - Philips 1236D ATSC/NTSC daul in +tuner=42 - Philips 1236D ATSC/NTSC dual in tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F) tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant) tuner=45 - Microtune 4049 FM5 diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 95818bfcb5c0..cabb02a610df 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -481,7 +481,7 @@ static struct tunertype tuners[] = { .config = 0x8e, }, [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */ - .name = "Philips 1236D ATSC/NTSC daul in", + .name = "Philips 1236D ATSC/NTSC dual in", .thresh1= 16 * 157.25 /*MHz*/, .thresh2= 16 * 454.00 /*MHz*/, .VHF_L = 0xa0, -- cgit v1.2.3 From 70f00044a2107a2c7d654bf1d3e0494f77777f47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:26 -0200 Subject: V4L/DVB (3162): Some fixes at cx88 controls - Now, default control values at cx88_cx8800_ctls are honored - default value for contrast/saturation were changed to be in line with available documentation for the chipset; - Removed some bad coding at set_control; - U/V Saturation now changes proportionally Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 85 ++++++++++++++++------------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index bc025c46aedf..b76abb9b8961 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -240,7 +240,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0xff, .step = 1, - .default_value = 0, + .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 0, @@ -271,7 +271,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0xff, .step = 1, - .default_value = 0, + .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 0, @@ -285,6 +285,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .name = "Mute", .minimum = 0, .maximum = 1, + .default_value = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, }, .reg = AUD_VOL_CTL, @@ -298,7 +299,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0x3f, .step = 1, - .default_value = 0, + .default_value = 0x1f, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = AUD_VOL_CTL, @@ -917,6 +918,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; break; } + printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctl->id, c->reg, ctl->value, + c->mask, c->sreg ? " [shadowed]" : ""); return 0; } @@ -925,13 +929,13 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) { /* struct cx88_core *core = dev->core; */ struct cx88_ctrl *c = NULL; - u32 v_sat_value; - u32 value; + u32 value,mask; int i; - - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == ctl->id) + for (i = 0; i < CX8800_CTLS; i++) { + if (cx8800_ctls[i].v.id == ctl->id) { c = &cx8800_ctls[i]; + } + } if (NULL == c) return -EINVAL; @@ -939,6 +943,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = c->v.minimum; if (ctl->value > c->v.maximum) ctl->value = c->v.maximum; + mask=c->mask; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value; @@ -948,56 +953,44 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) break; case V4L2_CID_SATURATION: /* special v_sat handling */ - v_sat_value = ctl->value - (0x7f - 0x5a); - if (v_sat_value > 0xff) - v_sat_value = 0xff; - if (v_sat_value < 0x00) - v_sat_value = 0x00; - cx_andor(MO_UV_SATURATION, 0xff00, v_sat_value << 8); - /* fall through to default route for u_sat */ + + value = ((ctl->value - c->off) << c->shift) & c->mask; + + if (core->tvnorm->id & V4L2_STD_SECAM) { + /* For SECAM, both U and V sat should be equal */ + value=value<<8|value; + } else { + /* Keeps U Saturation proportional to V Sat */ + value=(value*0x5a)/0x7f<<8|value; + } + mask=0xffff; + break; default: value = ((ctl->value - c->off) << c->shift) & c->mask; break; } - dprintk(1,"set_control id=0x%X reg=0x%x val=0x%x%s\n", - ctl->id, c->reg, value, c->sreg ? " [shadowed]" : ""); + printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctl->id, c->reg, value, + mask, c->sreg ? " [shadowed]" : ""); if (c->sreg) { - cx_sandor(c->sreg, c->reg, c->mask, value); + cx_sandor(c->sreg, c->reg, mask, value); } else { - cx_andor(c->reg, c->mask, value); + cx_andor(c->reg, mask, value); } return 0; } -/* static void init_controls(struct cx8800_dev *dev) */ static void init_controls(struct cx88_core *core) { - static struct v4l2_control mute = { - .id = V4L2_CID_AUDIO_MUTE, - .value = 1, - }; - static struct v4l2_control volume = { - .id = V4L2_CID_AUDIO_VOLUME, - .value = 0x3f, - }; - static struct v4l2_control hue = { - .id = V4L2_CID_HUE, - .value = 0x80, - }; - static struct v4l2_control contrast = { - .id = V4L2_CID_CONTRAST, - .value = 0x80, - }; - static struct v4l2_control brightness = { - .id = V4L2_CID_BRIGHTNESS, - .value = 0x80, - }; + struct v4l2_control ctrl; + int i; - set_control(core,&mute); - set_control(core,&volume); - set_control(core,&hue); - set_control(core,&contrast); - set_control(core,&brightness); + for (i = 0; i < CX8800_CTLS; i++) { + ctrl.id=cx8800_ctls[i].v.id; + ctrl.value=cx8800_ctls[i].v.default_value + +cx8800_ctls[i].off; + set_control(core, &ctrl); + } } /* ------------------------------------------------------------------ */ @@ -1930,8 +1923,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* initial device configuration */ down(&core->lock); - init_controls(core); cx88_set_tvnorm(core,tvnorms); + init_controls(core); video_mux(core,0); up(&core->lock); -- cgit v1.2.3 From 7e57819169d4f9a1d7af55fb645ece3fb981e2e3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:27 -0200 Subject: V4L/DVB (3167): added ntsc parameter to tuner and more standardized debugs - Debug message changed to be coherent with other modules - added ntsc parameter - parameters moved to the beginning at the file - tuner_status moved to a better position. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-input.c | 2 +- drivers/media/video/tuner-core.c | 124 +++++++++++++++++++++++++-------------- include/media/tuner.h | 10 ++-- 3 files changed, 85 insertions(+), 51 deletions(-) diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c index 5027e10537cf..fa6ccbc6f26d 100644 --- a/drivers/media/video/bttv-input.c +++ b/drivers/media/video/bttv-input.c @@ -645,7 +645,7 @@ int bttv_input_init(struct bttv *btv) /* all done */ input_register_device(btv->remote->dev); - printk(DEVNAME ": %s detected at %s\n",ir->dev->name,ir->dev->phys); + printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys); /* the remote isn't as bouncy as a keyboard */ ir->dev->rep[REP_DELAY] = repeat_delay; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index c8ff849e8903..df994311251e 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -38,21 +38,27 @@ I2C_CLIENT_INSMOD; /* insmod options used at init time => read/only */ static unsigned int addr = 0; -module_param(addr, int, 0444); - static unsigned int no_autodetect = 0; -module_param(no_autodetect, int, 0444); - static unsigned int show_i2c = 0; -module_param(show_i2c, int, 0444); /* insmod options used at runtime => read/write */ unsigned int tuner_debug = 0; -module_param(tuner_debug, int, 0644); static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +module_param(addr, int, 0444); +module_param(no_autodetect, int, 0444); +module_param(show_i2c, int, 0444); +module_param(tuner_debug, int, 0644); + +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); module_param_array(tv_range, int, NULL, 0644); module_param_array(radio_range, int, NULL, 0644); @@ -249,11 +255,6 @@ static inline int check_mode(struct tuner *t, char *cmd) return 0; } -static char pal[] = "-"; -module_param_string(pal, pal, sizeof(pal), 0644); -static char secam[] = "--"; -module_param_string(secam, secam, sizeof(secam), 0644); - /* get more precise norm info from insmod option */ static int tuner_fixup_std(struct tuner *t) { @@ -285,8 +286,13 @@ static int tuner_fixup_std(struct tuner *t) break; case 'N': case 'n': - tuner_dbg ("insmod fixup: PAL => PAL-N\n"); - t->std = V4L2_STD_PAL_N; + if (pal[1] == 'c' || pal[1] == 'C') { + tuner_dbg("insmod fixup: PAL => PAL-Nc\n"); + t->std = V4L2_STD_PAL_Nc; + } else { + tuner_dbg ("insmod fixup: PAL => PAL-N\n"); + t->std = V4L2_STD_PAL_N; + } break; case '-': /* default parameter, do nothing */ @@ -298,6 +304,15 @@ static int tuner_fixup_std(struct tuner *t) } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n"); + t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + break; case 'd': case 'D': case 'k': @@ -324,9 +339,60 @@ static int tuner_fixup_std(struct tuner *t) } } + if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + switch (ntsc[0]) { + case 'm': + case 'M': + tuner_dbg("insmod fixup: NTSC => NTSC-M\n"); + t->std = V4L2_STD_NTSC_M; + break; + case 'j': + case 'J': + tuner_dbg("insmod fixup: NTSC => NTSC_M_JP\n"); + t->std = V4L2_STD_NTSC_M_JP; + break; + case '-': + /* default parameter, do nothing */ + break; + default: + tuner_info("ntsc= argument not recognised\n"); + break; + } + } return 0; } +static void tuner_status(struct i2c_client *client) +{ + struct tuner *t = i2c_get_clientdata(client); + unsigned long freq, freq_fraction; + const char *p; + + switch (t->mode) { + case V4L2_TUNER_RADIO: p = "radio"; break; + case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break; + case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break; + default: p = "undefined"; break; + } + if (t->mode == V4L2_TUNER_RADIO) { + freq = t->freq / 16000; + freq_fraction = (t->freq % 16000) * 100 / 16000; + } else { + freq = t->freq / 16; + freq_fraction = (t->freq % 16) * 100 / 16; + } + tuner_info("Tuner mode: %s\n", p); + tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); + tuner_info("Standard: 0x%08llx\n", t->std); + if (t->mode == V4L2_TUNER_RADIO) { + if (t->has_signal) { + tuner_info("Signal strength: %d\n", t->has_signal(client)); + } + if (t->is_stereo) { + tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); + } + } +} /* ---------------------------------------------------------------------- */ /* static var Used only in tuner_attach and tuner_probe */ @@ -475,38 +541,6 @@ static inline int check_v4l2(struct tuner *t) return 0; } -static void tuner_status(struct i2c_client *client) -{ - struct tuner *t = i2c_get_clientdata(client); - unsigned long freq, freq_fraction; - const char *p; - - switch (t->mode) { - case V4L2_TUNER_RADIO: p = "radio"; break; - case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break; - case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break; - default: p = "undefined"; break; - } - if (t->mode == V4L2_TUNER_RADIO) { - freq = t->freq / 16000; - freq_fraction = (t->freq % 16000) * 100 / 16000; - } else { - freq = t->freq / 16; - freq_fraction = (t->freq % 16) * 100 / 16; - } - tuner_info("Tuner mode: %s\n", p); - tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); - tuner_info("Standard: 0x%08llx\n", t->std); - if (t->mode == V4L2_TUNER_RADIO) { - if (t->has_signal) { - tuner_info("Signal strength: %d\n", t->has_signal(client)); - } - if (t->is_stereo) { - tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); - } - } -} - static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); diff --git a/include/media/tuner.h b/include/media/tuner.h index 567f05549e3a..b39e908cd068 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -202,15 +202,15 @@ extern int tea5767_autodetection(struct i2c_client *c); #define tuner_warn(fmt, arg...) do {\ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0) + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + #define tuner_info(fmt, arg...) do {\ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0) + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) #define tuner_dbg(fmt, arg...) do {\ if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, \ - t->i2c.driver->driver.name, \ - t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0) + printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) #endif /* __KERNEL__ */ -- cgit v1.2.3 From 67f1570a0659abba5efbf55cc986187af61bdd52 Mon Sep 17 00:00:00 2001 From: "Michael H. Schimek" Date: Mon, 9 Jan 2006 15:25:27 -0200 Subject: V4L/DVB (3178): bttv VBI fixes - V4L2_(G|S|TRY)_FMT returned incorrect VBI start lines for PAL-M, NTSC-JP, and PAL-60. They also returned an inaccurate VBI offset. - V4L2_(G|S)_FMT and V4L2_TRY_FMT disagreed about the start of VBI capturing in PAL and SECAM second field. Note the start line fixes may break applications using VIDIOCSVBIFMT because this ioctl fails when the driver does not support exactly the requested parameters. - V4L2_TRY_FMT did not clear the reserved field in struct v4l2_vbi_format. - V4L2_(S|TRY)_FMT did not expect very large or small VBI start or count values, returning wrong (but safe) counts due to an overflow. - VIDIOCGVBIFMT confused V4L and V4L2 VBI flags. However this had no effect because the flags have the same value and bttv never sets them. - In v4l_compat_translate_ioctl() the VIDIOC(G|S)VBIFMT code did not expect V4L2 drivers supporting VBI formats besides V4L2_PIX_FMT_GREY. Signed-off-by: Michael H. Schimek Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-driver.c | 18 ++++++++++--- drivers/media/video/bttv-vbi.c | 57 +++++++++++++++------------------------ drivers/media/video/bttvp.h | 5 ++++ drivers/media/video/v4l1-compat.c | 11 +++++++- 4 files changed, 51 insertions(+), 40 deletions(-) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 8bee7d5796dd..4e25c92ac8c4 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -210,6 +210,9 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x20, .vbipack = 255, .sram = 0, + /* ITU-R frame line number of the first VBI line + we can capture, of the first and second field. */ + .vbistart = { 7,320 }, },{ .v4l2_id = V4L2_STD_NTSC_M, .name = "NTSC", @@ -226,6 +229,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x1a, .vbipack = 144, .sram = 1, + .vbistart = { 10, 273 }, },{ .v4l2_id = V4L2_STD_SECAM, .name = "SECAM", @@ -242,6 +246,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x20, .vbipack = 255, .sram = 0, /* like PAL, correct? */ + .vbistart = { 7, 320 }, },{ .v4l2_id = V4L2_STD_PAL_Nc, .name = "PAL-Nc", @@ -258,6 +263,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x1a, .vbipack = 144, .sram = -1, + .vbistart = { 7, 320 }, },{ .v4l2_id = V4L2_STD_PAL_M, .name = "PAL-M", @@ -274,6 +280,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x1a, .vbipack = 144, .sram = -1, + .vbistart = { 10, 273 }, },{ .v4l2_id = V4L2_STD_PAL_N, .name = "PAL-N", @@ -290,6 +297,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x20, .vbipack = 144, .sram = -1, + .vbistart = { 7, 320}, },{ .v4l2_id = V4L2_STD_NTSC_M_JP, .name = "NTSC-JP", @@ -306,6 +314,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vdelay = 0x16, .vbipack = 144, .sram = -1, + .vbistart = {10, 273}, },{ /* that one hopefully works with the strange timing * which video recorders produce when playing a NTSC @@ -326,6 +335,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = { .vbipack = 255, .vtotal = 524, .sram = -1, + .vbistart = { 10, 273 }, } }; static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); @@ -2570,10 +2580,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, fmt->count[0] = fmt2.fmt.vbi.count[0]; fmt->start[1] = fmt2.fmt.vbi.start[1]; fmt->count[1] = fmt2.fmt.vbi.count[1]; - if (fmt2.fmt.vbi.flags & VBI_UNSYNC) - fmt->flags |= V4L2_VBI_UNSYNC; - if (fmt2.fmt.vbi.flags & VBI_INTERLACED) - fmt->flags |= V4L2_VBI_INTERLACED; + if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC) + fmt->flags |= VBI_UNSYNC; + if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED) + fmt->flags |= VBI_INTERLACED; return 0; } case VIDIOCSVBIFMT: diff --git a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c index f4f58c60f152..72afdd64b882 100644 --- a/drivers/media/video/bttv-vbi.c +++ b/drivers/media/video/bttv-vbi.c @@ -31,6 +31,12 @@ #include #include "bttvp.h" +/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate: + bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC + HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge + of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */ +#define VBI_OFFSET ((64 + 0) * 2) + #define VBI_DEFLINES 16 #define VBI_MAXLINES 32 @@ -163,40 +169,30 @@ void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines) void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f) { const struct bttv_tvnorm *tvnorm; - u32 start0,start1; - s32 count0,count1,count; + s64 count0,count1,count; tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; f->type = V4L2_BUF_TYPE_VBI_CAPTURE; f->fmt.vbi.sampling_rate = tvnorm->Fsc; f->fmt.vbi.samples_per_line = 2048; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 244; + f->fmt.vbi.offset = VBI_OFFSET; f->fmt.vbi.flags = 0; - switch (fh->btv->tvnorm) { - case 1: /* NTSC */ - start0 = 10; - start1 = 273; - break; - case 0: /* PAL */ - case 2: /* SECAM */ - default: - start0 = 7; - start1 = 320; - } - count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0; - count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1; - count = max(count0,count1); - if (count > VBI_MAXLINES) - count = VBI_MAXLINES; - if (count < 1) - count = 1; + /* s64 to prevent overflow. */ + count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0] + - tvnorm->vbistart[0]; + count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1] + - tvnorm->vbistart[1]; + count = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES); - f->fmt.vbi.start[0] = start0; - f->fmt.vbi.start[1] = start1; + f->fmt.vbi.start[0] = tvnorm->vbistart[0]; + f->fmt.vbi.start[1] = tvnorm->vbistart[1]; f->fmt.vbi.count[0] = count; f->fmt.vbi.count[1] = count; + + f->fmt.vbi.reserved[0] = 0; + f->fmt.vbi.reserved[1] = 0; } void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f) @@ -209,21 +205,12 @@ void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f) f->fmt.vbi.sampling_rate = tvnorm->Fsc; f->fmt.vbi.samples_per_line = 2048; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 244; + f->fmt.vbi.offset = VBI_OFFSET; + f->fmt.vbi.start[0] = tvnorm->vbistart[0]; + f->fmt.vbi.start[1] = tvnorm->vbistart[1]; f->fmt.vbi.count[0] = fh->lines; f->fmt.vbi.count[1] = fh->lines; f->fmt.vbi.flags = 0; - switch (fh->btv->tvnorm) { - case 1: /* NTSC */ - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 273; - break; - case 0: /* PAL */ - case 2: /* SECAM */ - default: - f->fmt.vbi.start[0] = 7; - f->fmt.vbi.start[1] = 319; - } } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 55759f698e02..dd00c20ab95e 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -73,6 +73,8 @@ #define UNSET (-1U) +#define clamp(x, low, high) min (max (low, x), high) + /* ---------------------------------------------------------- */ struct bttv_tvnorm { @@ -88,6 +90,9 @@ struct bttv_tvnorm { u8 vbipack; u16 vtotal; int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. */ + u16 vbistart[2]; }; extern const struct bttv_tvnorm bttv_tvnorms[]; diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 4134549d11a8..2ab5b4093800 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -951,6 +951,10 @@ v4l_compat_translate_ioctl(struct inode *inode, dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err); break; } + if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) { + err = -EINVAL; + break; + } memset(fmt, 0, sizeof(*fmt)); fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line; fmt->sampling_rate = fmt2->fmt.vbi.sampling_rate; @@ -966,6 +970,11 @@ v4l_compat_translate_ioctl(struct inode *inode, { struct vbi_format *fmt = arg; + if (VIDEO_PALETTE_RAW != fmt->sample_format) { + err = -EINVAL; + break; + } + fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL); memset(fmt2, 0, sizeof(*fmt2)); @@ -986,7 +995,7 @@ v4l_compat_translate_ioctl(struct inode *inode, if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line || fmt2->fmt.vbi.sampling_rate != fmt->sampling_rate || - VIDEO_PALETTE_RAW != fmt->sample_format || + fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY || fmt2->fmt.vbi.start[0] != fmt->start[0] || fmt2->fmt.vbi.count[0] != fmt->count[0] || fmt2->fmt.vbi.start[1] != fmt->start[1] || -- cgit v1.2.3 From e18828e43a52fb9a792938840cc32cbb2a9e1a5c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:28 -0200 Subject: V4L/DVB (3179): Fix 64-bit compile warnings - Fix 64-bit compile warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_hlp.c | 2 +- drivers/media/dvb/dvb-core/dvb_frontend.c | 8 ++++---- drivers/media/dvb/dvb-core/dvb_net.c | 4 ++-- drivers/media/dvb/frontends/bcm3510.c | 4 ++-- drivers/media/dvb/frontends/or51211.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index ec52dff8cb69..be34ec430470 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -562,7 +562,7 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int int b_depth = vv->ov_fmt->depth; int b_bpl = vv->ov_fb.fmt.bytesperline; - u32 base = (u32)vv->ov_fb.base; + u32 base = (u32)(unsigned long)vv->ov_fb.base; struct saa7146_video_dma vdma1; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 9b5fa540e1e7..a53e95f35a53 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -788,7 +788,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops->dishnetwork_send_legacy_command) { - err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); + err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } else if (fe->ops->set_voltage) { @@ -808,7 +808,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned int cmd = ((unsigned int) parg) << 1; + unsigned int cmd = ((unsigned long) parg) << 1; struct timeval nexttime; struct timeval tv[10]; int i; @@ -855,7 +855,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_ENABLE_HIGH_LNB_VOLTAGE: if (fe->ops->enable_high_lnb_voltage) - err = fe->ops->enable_high_lnb_voltage(fe, (int) parg); + err = fe->ops->enable_high_lnb_voltage(fe, (long) parg); break; case FE_SET_FRONTEND: { @@ -934,7 +934,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; case FE_SET_FRONTEND_TUNE_MODE: - fepriv->tune_mode_flags = (unsigned int) parg; + fepriv->tune_mode_flags = (unsigned long) parg; break; }; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 86bba81e851e..95d991febea6 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1296,9 +1296,9 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if ((unsigned int) parg >= DVB_NET_DEVICES_MAX) + if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) return -EINVAL; - ret = dvb_net_remove_if(dvbnet, (unsigned int) parg); + ret = dvb_net_remove_if(dvbnet, (unsigned long) parg); if (!ret) module_put(dvbdev->adapter->module); return ret; diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index 8ceb9a33c7af..e9b363625c50 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -623,13 +623,13 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe) err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); return ret; } - deb_info("got firmware: %d\n",fw->size); + deb_info("got firmware: %zd\n",fw->size); b = fw->data; for (i = 0; i < fw->size;) { addr = le16_to_cpu( *( (u16 *)&b[i] ) ); len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); - deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size); + deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size); if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { err("firmware download failed: %d\n",ret); return ret; diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 531f76246e5f..8d631ca7aaf0 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -112,7 +112,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe, u8 tudata[585]; int i; - dprintk("Firmware is %d bytes\n",fw->size); + dprintk("Firmware is %zd bytes\n",fw->size); /* Get eprom data */ tudata[0] = 17; -- cgit v1.2.3 From 889aee805a0c286e33965cc678ea16672d6c5666 Mon Sep 17 00:00:00 2001 From: Christopher Pascoe Date: Mon, 9 Jan 2006 15:25:28 -0200 Subject: V4L/DVB (3192): Fix bttv sub-device unregister - Fixes sub-device release for BTTV. Without this, DVB modules can't be reloaded Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-driver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 4e25c92ac8c4..69a147b85f1a 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -4075,8 +4075,6 @@ static int __devinit bttv_probe(struct pci_dev *dev, } /* add subdevices */ - if (btv->has_remote) - bttv_sub_add_device(&btv->c, "remote"); if (bttv_tvcards[btv->c.type].has_dvb) bttv_sub_add_device(&btv->c, "dvb"); @@ -4117,7 +4115,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev) btv->shutdown=1; wake_up(&btv->gpioq); bttv_input_fini(btv); - //bttv_sub_del_devices(&btv->c); + bttv_sub_del_devices(&btv->c); /* unregister i2c_bus + input */ fini_bttv_i2c(btv); -- cgit v1.2.3 From bc61b0102a53ee0ced3a8747cd4afe656a453756 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 9 Jan 2006 15:25:28 -0200 Subject: V4L/DVB (3193): Replace del_timer with del_timer_sync - Replace del_timer with del_timer_sync Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c index fa6ccbc6f26d..12197f1b2757 100644 --- a/drivers/media/video/bttv-input.c +++ b/drivers/media/video/bttv-input.c @@ -668,7 +668,7 @@ void bttv_input_fini(struct bttv *btv) if (btv->remote->rc5_gpio) { u32 gpio; - del_timer(&btv->remote->timer_end); + del_timer_sync(&btv->remote->timer_end); flush_scheduled_work(); gpio = bttv_gpio_read(&btv->c); -- cgit v1.2.3 From 83ac8722be6d34b9bbcaabfff825d5847ce3a9d4 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:29 -0200 Subject: V4L/DVB (3196): correct Thomson DTT 761x frequency ranges - Corrected Thomson DTT 7611 tuner programming, based on spec sheet - renamed to Thomson DTT 761x - applies to DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A (DTT 7610 is similar, but slightly different programming) - corrected frequency ranges for analog and digital modes Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 4 ++-- drivers/media/dvb/frontends/dvb-pll.c | 15 ++++++++------- drivers/media/dvb/frontends/dvb-pll.h | 2 +- drivers/media/video/cx88/cx88-cards.c | 2 +- drivers/media/video/cx88/cx88-dvb.c | 2 +- drivers/media/video/tuner-simple.c | 11 ++++++----- include/media/tuner.h | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index 1d658a388b80..0bf3d5bf9ef8 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -50,7 +50,7 @@ tuner=48 - Tenna TNF 8831 BGFF) tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in tuner=50 - TCL 2002N tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3) -tuner=52 - Thomson DDT 7610 (ATSC/NTSC) +tuner=52 - Thomson DTT 7610 (ATSC/NTSC) tuner=53 - Philips FQ1286 tuner=54 - tda8290+75 tuner=55 - TCL 2002MB @@ -58,7 +58,7 @@ tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4) tuner=57 - Philips FQ1236A MK4 tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF tuner=59 - Ymec TVision TVF-5533MF -tuner=60 - Thomson DDT 7611 (ATSC/NTSC) +tuner=60 - Thomson DTT 761X (ATSC/NTSC) tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF tuner=62 - Philips TEA5767HN FM Radio tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index f857b869616c..a3d57ce9dd12 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { }; EXPORT_SYMBOL(dvb_pll_microtune_4042); -struct dvb_pll_desc dvb_pll_thomson_dtt7611 = { - .name = "Thomson dtt7611", - .min = 44000000, - .max = 958000000, +struct dvb_pll_desc dvb_pll_thomson_dtt761x = { + /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + .name = "Thomson dtt761x", + .min = 57000000, + .max = 863000000, .count = 3, .entries = { - { 157250000, 44000000, 62500, 0x8e, 0x39 }, - { 454000000, 44000000, 62500, 0x8e, 0x3a }, + { 147000000, 44000000, 62500, 0x8e, 0x39 }, + { 417000000, 44000000, 62500, 0x8e, 0x3a }, { 999999999, 44000000, 62500, 0x8e, 0x3c }, }, }; -EXPORT_SYMBOL(dvb_pll_thomson_dtt7611); +EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 497d31dcf41e..24d4d2e9acd8 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -25,7 +25,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; extern struct dvb_pll_desc dvb_pll_lg_z201; extern struct dvb_pll_desc dvb_pll_microtune_4042; -extern struct dvb_pll_desc dvb_pll_thomson_dtt7611; +extern struct dvb_pll_desc dvb_pll_thomson_dtt761x; extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index c20c07117537..85798e1fa047 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -708,7 +708,7 @@ struct cx88_board cx88_boards[] = { }, [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = { .name = "DViCO FusionHDTV 3 Gold-T", - .tuner_type = TUNER_THOMSON_DTT7611, + .tuner_type = TUNER_THOMSON_DTT761X, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c4551d996119..ed5cfe5f5c0e 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -441,7 +441,7 @@ static int dvb_register(struct cx8802_dev *dev) cx_set(MO_GP0_IO, 9); mdelay(200); dev->core->pll_addr = 0x61; - dev->core->pll_desc = &dvb_pll_thomson_dtt7611; + dev->core->pll_desc = &dvb_pll_thomson_dtt761x; dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold, &dev->core->i2c_adap); } diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index cabb02a610df..985464f4b7c2 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -573,7 +573,7 @@ static struct tunertype tuners[] = { .config = 0x8e, }, [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ - .name = "Thomson DDT 7610 (ATSC/NTSC)", + .name = "Thomson DTT 7610 (ATSC/NTSC)", .thresh1= 16 * 157.25 /*MHz*/, .thresh2= 16 * 454.00 /*MHz*/, .VHF_L = 0x39, @@ -640,10 +640,11 @@ static struct tunertype tuners[] = { }, /* 60-69 */ - [TUNER_THOMSON_DTT7611] = { /* THOMSON ATSC */ - .name = "Thomson DDT 7611 (ATSC/NTSC)", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, + [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ + /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + .name = "Thomson DTT 761X (ATSC/NTSC)", + .thresh1= 16 * 145.25 /*MHz*/, + .thresh2= 16 * 415.25 /*MHz*/, .VHF_L = 0x39, .VHF_H = 0x3a, .UHF = 0x3c, diff --git a/include/media/tuner.h b/include/media/tuner.h index b39e908cd068..aa91ce35915b 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -102,7 +102,7 @@ #define TUNER_YMEC_TVF_8531MF 58 #define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */ -#define TUNER_THOMSON_DTT7611 60 /* DViCO FusionHDTV 3 Gold-T */ +#define TUNER_THOMSON_DTT761X 60 /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ #define TUNER_TENA_9533_DI 61 #define TUNER_TEA5767 62 /* Only FM Radio Tuner */ #define TUNER_PHILIPS_FMD1216ME_MK3 63 -- cgit v1.2.3 From 210e207c1d98348f5993e6f580cd20cf20086d7d Mon Sep 17 00:00:00 2001 From: Tyler Trafford Date: Mon, 9 Jan 2006 15:25:29 -0200 Subject: V4L/DVB (3198): make cx25840 recover from some firmware load failures - In the rare event that a 333MHz i2c firmware load fails after writing some data, this fix makes the driver reset the DL_ADDR registers to the proper values before continuing on with 100MHz transfers. Signed-off-by: Tyler Trafford Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-firmware.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index df9d50a75542..f43024f2aaef 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -15,7 +15,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - #include #include #include @@ -94,13 +93,23 @@ static inline int check_fw_load(struct i2c_client *client, int size) static inline int fw_write(struct i2c_client *client, u8 * data, int size) { - if (i2c_master_send(client, data, size) < size) { + int sent; + + if ((sent = i2c_master_send(client, data, size)) < size) { if (fastfw) { cx25840_err("333MHz i2c firmware load failed\n"); fastfw = 0; set_i2c_delay(client, 10); + if (sent > 2) { + u16 dl_addr = cx25840_read(client, 0x801) << 8; + dl_addr |= cx25840_read(client, 0x800); + dl_addr -= sent - 2; + cx25840_write(client, 0x801, dl_addr >> 8); + cx25840_write(client, 0x800, dl_addr & 0xff); + } + if (i2c_master_send(client, data, size) < size) { cx25840_err ("100MHz i2c firmware load failed\n"); -- cgit v1.2.3 From 610d1407b2d7a8fbb9f8e5757b2d078b9988299c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:30 -0200 Subject: V4L/DVB (3199): Removed some unneeded #ifdef's - Removed some unneeded #ifdef's Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 77977e9c013e..9cac4e795950 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) struct dst_state* state = NULL; switch(type) { -#ifdef BTTV_BOARD_DVICO_DVBT_LITE case BTTV_BOARD_DVICO_DVBT_LITE: card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); if (card->fe != NULL) { @@ -608,16 +607,13 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) card->fe->ops->info.frequency_max = 862000000; } break; -#endif -#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: lgdt330x_reset(card); card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter); if (card->fe != NULL) dprintk ("dvb_bt8xx: lgdt330x detected\n"); break; -#endif #ifdef BTTV_BOARD_TWINHAN_VP3021 case BTTV_BOARD_TWINHAN_VP3021: @@ -812,9 +808,7 @@ static int dvb_bt8xx_probe(struct device *dev) card->irq_err_ignore = 0; break; -#ifdef BTTV_BOARD_DVICO_DVBT_LITE case BTTV_BOARD_DVICO_DVBT_LITE: -#endif card->gpio_mode = 0x0400C060; card->op_sync_orin = 0; card->irq_err_ignore = 0; @@ -823,9 +817,7 @@ static int dvb_bt8xx_probe(struct device *dev) * DA_APP(parallel) */ break; -#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: -#endif card->gpio_mode = 0x0400c060; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; -- cgit v1.2.3 From 6fe66ba63fdd27cfc01ffb2e1835a2a475074a63 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:32 -0200 Subject: V4L/DVB (3201): Remove #ifdef BTTV_BOARD_TWINHAN_VP3021 - As far back as the video4linux cvs repository goes, there is no mention of BTTV_TWINHAN_VP3021. It seems that this was done for the sake of backwards compatability with some older v4l, but this can no longer be necessary due to the v4l/dvb cvs merger, nor should this have ever existed in the upstream kernel. Signed-off-by: Michael Krufky Acked-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 9cac4e795950..01b4e0aac049 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -615,11 +615,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) dprintk ("dvb_bt8xx: lgdt330x detected\n"); break; -#ifdef BTTV_BOARD_TWINHAN_VP3021 - case BTTV_BOARD_TWINHAN_VP3021: -#else case BTTV_BOARD_NEBULA_DIGITV: -#endif /* * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); * this would be a cleaner solution than trying each frontend in turn. @@ -823,11 +819,7 @@ static int dvb_bt8xx_probe(struct device *dev) card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; break; -#ifdef BTTV_BOARD_TWINHAN_VP3021 - case BTTV_BOARD_TWINHAN_VP3021: -#else case BTTV_BOARD_NEBULA_DIGITV: -#endif case BTTV_BOARD_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; -- cgit v1.2.3 From 6ff5ef28bad0403fbc24cdee127d094449a10ab6 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 9 Jan 2006 15:25:33 -0200 Subject: V4L/DVB (3202): Initialize the dvb-usb-device-pointer to NULL - Initialize the the dvb-usb-device-pointer in the -init function to NULL, to be sure that a dvb-usb-device was really initialized. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 2f9c3638adcf..2e23060cbbca 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -138,6 +138,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties int ret = -ENOMEM,cold=0; + if (du != NULL) + *du = NULL; + if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) { deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); return -ENODEV; -- cgit v1.2.3 From 2a9a9a84f2ac6e4481f564c42a9268477465c359 Mon Sep 17 00:00:00 2001 From: "Nickolay V. Shmyrev" Date: Mon, 9 Jan 2006 15:25:33 -0200 Subject: V4L/DVB (3213): Add remote for Compro Videomate Gold+ Pal version. - Add remote. Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 1 + drivers/media/video/saa7134/saa7134-input.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 66ff6862468e..ae019104d997 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3124,6 +3124,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_GO_007_FM: /* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ case SAA7134_BOARD_VIDEOMATE_TV_PVR: + case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_VIDEOMATE_DVBT_200: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index ab75ca5ac356..7175abbd2f8c 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -686,6 +686,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) polling = 50; // ms break; case SAA7134_BOARD_VIDEOMATE_TV_PVR: + case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: ir_codes = videomate_tv_pvr_codes; mask_keycode = 0x00003F; -- cgit v1.2.3 From 41d70c26c615da5a42aea4655232c68c53b9e084 Mon Sep 17 00:00:00 2001 From: Ricardo Cerqueira Date: Mon, 9 Jan 2006 15:25:34 -0200 Subject: V4L/DVB (3216): saa7134 card #58 has a newer revision with a new subsystem ID - Added new ID for different revision of card #58. It's the same card, but with a tda8275a instead of a tda8275 Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 0fb6c4a29f5b..4573e52c1ced 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -56,7 +56,7 @@ 55 -> LifeView FlyDVB-T DUO [5168:0502,5168:0306] 56 -> Avermedia AVerTV 307 [1461:a70a] 57 -> Avermedia AVerTV GO 007 FM [1461:f31f] - 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0370,1421:1370] + 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370] 59 -> Kworld/Tevion V-Stream Xpert TV PVR7134 60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502] 61 -> Philips TOUGH DVB-T reference design [1131:2004] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index ae019104d997..73f2525bc764 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2919,6 +2919,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1421, .subdevice = 0x0350, /* PCI version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1421, + .subdevice = 0x0351, /* PCI version, new revision */ + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, -- cgit v1.2.3 From 50c25fff5385c6baf3114f7c369b0f75a29ac1e8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:34 -0200 Subject: V4L/DVB (3218): Whitespace cleanups - minor whitespace cleanups Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/dvb/get_dvb_firmware | 2 +- drivers/media/common/saa7146_fops.c | 1 + drivers/media/common/saa7146_vbi.c | 6 +++--- drivers/media/common/saa7146_video.c | 9 ++------ drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 2 +- drivers/media/dvb/bt8xx/dst_ca.c | 3 ++- drivers/media/dvb/cinergyT2/Kconfig | 20 +++++++++--------- drivers/media/dvb/dvb-core/Kconfig | 2 +- drivers/media/dvb/dvb-core/Makefile | 2 +- drivers/media/dvb/dvb-core/dvb_filter.c | 16 +++++++-------- drivers/media/dvb/dvb-core/dvb_ringbuffer.c | 32 ++++++++++++++--------------- drivers/media/dvb/dvb-core/dvb_ringbuffer.h | 8 ++++---- drivers/media/dvb/dvb-core/dvbdev.c | 22 ++++++++++---------- drivers/media/dvb/dvb-core/dvbdev.h | 2 +- drivers/media/dvb/dvb-usb/vp702x-fe.c | 2 +- drivers/media/dvb/frontends/Kconfig | 20 +++++++++--------- drivers/media/dvb/frontends/cx24110.c | 22 ++++++++++---------- drivers/media/dvb/frontends/nxt6000.c | 10 ++++----- drivers/media/dvb/frontends/s5h1420.c | 4 ++-- drivers/media/dvb/frontends/sp887x.c | 2 +- drivers/media/dvb/frontends/tda10021.c | 4 ++-- drivers/media/dvb/frontends/tda1004x.c | 12 +++++------ drivers/media/dvb/pluto2/Kconfig | 2 +- drivers/media/dvb/ttpci/Kconfig | 6 +++--- drivers/media/dvb/ttpci/Makefile | 2 +- drivers/media/dvb/ttpci/av7110.c | 6 +++--- drivers/media/dvb/ttpci/av7110_hw.c | 4 ++-- drivers/media/dvb/ttpci/budget-av.c | 2 +- drivers/media/dvb/ttpci/ttpci-eeprom.c | 2 +- drivers/media/dvb/ttusb-budget/Kconfig | 2 +- drivers/media/dvb/ttusb-dec/Kconfig | 12 +++++------ drivers/media/dvb/ttusb-dec/ttusb_dec.c | 5 ++--- drivers/media/video/videodev.c | 6 +++--- drivers/media/video/wm8775.c | 1 - 34 files changed, 124 insertions(+), 129 deletions(-) diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index be6eb4c75991..08e96ff55720 100644 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -243,7 +243,7 @@ sub nxt2002 { my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); checkstandard(); - + wgetfile($sourcefile, $url); unzip($sourcefile, $tmpdir); verify("$tmpdir/SkyNETU.sys", $hash); diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 09ec964dec5c..a9ff5b5af1cf 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -332,6 +332,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma) BUG(); return 0; } + return videobuf_mmap_mapper(q,vma); } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 063986ec16b5..468d3c959075 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -500,9 +500,9 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff } struct saa7146_use_ops saa7146_vbi_uops = { - .init = vbi_init, - .open = vbi_open, + .init = vbi_init, + .open = vbi_open, .release = vbi_close, .irq_done = vbi_irq_done, - .read = vbi_read, + .read = vbi_read, }; diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 1d961023b837..7ebac7949df3 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -151,8 +151,8 @@ static int try_win(struct saa7146_dev *dev, struct v4l2_window *win) if (V4L2_FIELD_ANY == field) { field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; } switch (field) { case V4L2_FIELD_TOP: @@ -1114,10 +1114,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int return 0; } case VIDIOC_OVERLAY: - - - - { int on = *(int *)arg; int err = 0; @@ -1359,7 +1355,6 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) saa7146_buffer_queue(fh->dev,&vv->video_q,buf); } - static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct file *file = q->priv_data; diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index fa7058108bf4..0b940e152b79 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -298,7 +298,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir } static int lgdt3303_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) + struct dvb_frontend_parameters* params) { struct flexcop_device *fc = fe->dvb->priv; u8 buf[4]; diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 2239651969c8..c650b4bf7f5f 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -283,16 +283,17 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, hw_buffer->msg[4] = 0x03; hw_buffer->msg[5] = length & 0xff; hw_buffer->msg[6] = 0x00; + /* * Need to compute length for EN50221 section 8.3.2, for the time being * assuming 8.3.2 is not applicable */ memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); } + return 0; } - static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) { if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig index 7cf4c4a888ec..6018fcdba1e6 100644 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ b/drivers/media/dvb/cinergyT2/Kconfig @@ -21,35 +21,35 @@ config DVB_CINERGYT2_TUNING config DVB_CINERGYT2_STREAM_URB_COUNT int "Number of queued USB Request Blocks for Highspeed Stream Transfers" depends on DVB_CINERGYT2_TUNING - default "32" + default "32" help USB Request Blocks for Highspeed Stream transfers are scheduled in a queue for the Host Controller. Usually the default value is a safe choice. - You may increase this number if you are using this device in a - Server Environment with many high-traffic USB Highspeed devices + You may increase this number if you are using this device in a + Server Environment with many high-traffic USB Highspeed devices sharing the same USB bus. config DVB_CINERGYT2_STREAM_BUF_SIZE int "Size of URB Stream Buffers for Highspeed Transfers" depends on DVB_CINERGYT2_TUNING - default "512" + default "512" help Should be a multiple of native buffer size of 512 bytes. Default value is a safe choice. - You may increase this number if you are using this device in a - Server Environment with many high-traffic USB Highspeed devices + You may increase this number if you are using this device in a + Server Environment with many high-traffic USB Highspeed devices sharing the same USB bus. config DVB_CINERGYT2_QUERY_INTERVAL int "Status update interval [milliseconds]" depends on DVB_CINERGYT2_TUNING - default "250" + default "250" help This is the interval for status readouts from the demodulator. You may try lower values if you need more responsive signal quality @@ -64,9 +64,9 @@ config DVB_CINERGYT2_QUERY_INTERVAL config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE bool "Register the onboard IR Remote Control Receiver as Input Device" depends on DVB_CINERGYT2_TUNING - default "yes" + default "yes" help - Enable this option if you want to use the onboard Infrared Remote + Enable this option if you want to use the onboard Infrared Remote Control Receiver as Linux-Input device. Right now only the keycode table for the default Remote Control @@ -77,7 +77,7 @@ config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE config DVB_CINERGYT2_RC_QUERY_INTERVAL int "Infrared Remote Controller update interval [milliseconds]" depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE - default "50" + default "50" help If you have a very fast-repeating remote control you can try lower values, for normal consumer receivers the default value should be diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig index a9a7b3421048..12ee912a5705 100644 --- a/drivers/media/dvb/dvb-core/Kconfig +++ b/drivers/media/dvb/dvb-core/Kconfig @@ -5,7 +5,7 @@ config DVB_CORE help DVB core utility functions for device handling, software fallbacks etc. Say Y when you have a DVB card and want to use it. Say Y if your want - to build your drivers outside the kernel, but need the DVB core. All + to build your drivers outside the kernel, but need the DVB core. All in-kernel drivers will select this automatically if needed. If unsure say N. diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile index c6baac20f529..7adb50c1e8eb 100644 --- a/drivers/media/dvb/dvb-core/Makefile +++ b/drivers/media/dvb/dvb-core/Makefile @@ -3,7 +3,7 @@ # dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ - dvb_ca_en50221.o dvb_frontend.o \ + dvb_ca_en50221.o dvb_frontend.o \ dvb_net.o dvb_ringbuffer.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c index c49fd0bd7181..772003fb1821 100644 --- a/drivers/media/dvb/dvb-core/dvb_filter.c +++ b/drivers/media/dvb/dvb-core/dvb_filter.c @@ -409,16 +409,16 @@ static u8 *skip_pes_header(u8 **bufp) if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ if (buf[7] & PTS_ONLY) - pts = buf+9; + pts = buf+9; else pts = NULL; buf = inbuf + 9 + inbuf[8]; } else { /* mpeg1 */ for (buf = inbuf + 6; *buf == 0xff; buf++) - if (buf == inbuf + 6 + 16) { - break; - } + if (buf == inbuf + 6 + 16) { + break; + } if ((*buf & 0xc0) == 0x40) - buf += 2; + buf += 2; skip = mpeg1_skip_table [*buf >> 4]; if (skip == 5 || skip == 10) pts = buf; else pts = NULL; @@ -529,9 +529,9 @@ static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_t pic->picture_header = 0; pic->sequence_header_data = ( INIT_HORIZONTAL_SIZE << 20 ) - | ( INIT_VERTICAL_SIZE << 8 ) - | ( INIT_ASPECT_RATIO << 4 ) - | ( INIT_FRAME_RATE ); + | ( INIT_VERTICAL_SIZE << 8 ) + | ( INIT_ASPECT_RATIO << 4 ) + | ( INIT_FRAME_RATE ); pic->mpeg1_flag = 0; pic->vinfo.horizontal_size = INIT_DISP_HORIZONTAL_SIZE; diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 283c6e9339a4..77ad2410f4d3 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -112,10 +112,10 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; if (split > 0) { if (!usermem) - memcpy(buf, rbuf->data+rbuf->pread, split); + memcpy(buf, rbuf->data+rbuf->pread, split); else - if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) + return -EFAULT; buf += split; todo -= split; rbuf->pread = 0; @@ -124,7 +124,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in memcpy(buf, rbuf->data+rbuf->pread, todo); else if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) - return -EFAULT; + return -EFAULT; rbuf->pread = (rbuf->pread + todo) % rbuf->size; @@ -167,7 +167,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le } ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem) + int offset, u8* buf, size_t len, int usermem) { size_t todo; size_t split; @@ -183,10 +183,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; if (split > 0) { if (!usermem) - memcpy(buf, rbuf->data+idx, split); + memcpy(buf, rbuf->data+idx, split); else - if (copy_to_user(buf, rbuf->data+idx, split)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+idx, split)) + return -EFAULT; buf += split; todo -= split; idx = 0; @@ -195,7 +195,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, memcpy(buf, rbuf->data+idx, todo); else if (copy_to_user(buf, rbuf->data+idx, todo)) - return -EFAULT; + return -EFAULT; return len; } @@ -209,12 +209,12 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) // clean up disposed packets while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { - pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; - pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); - DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); + pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; + pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); + DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); } else { - // first packet is not disposed, so we stop cleaning now - break; + // first packet is not disposed, so we stop cleaning now + break; } } } @@ -242,8 +242,8 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* curpktstatus = rbuf->data[(idx + 2) % rbuf->size]; if (curpktstatus == PKT_READY) { - *pktlen = curpktlen; - return idx; + *pktlen = curpktlen; + return idx; } consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h index fa476f662f82..6d2560972771 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h @@ -106,7 +106,7 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); ** returns number of bytes transferred or -EFAULT */ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, - size_t len, int usermem); + size_t len, int usermem); /* write routines & macros */ @@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, ** returns number of bytes transferred or -EFAULT */ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, - size_t len); + size_t len); /** @@ -133,7 +133,7 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. */ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, - size_t len); + size_t len); /** * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this @@ -149,7 +149,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, * returns Number of bytes read, or -EFAULT. */ extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem); + int offset, u8* buf, size_t len, int usermem); /** * Dispose of a packet in the ring buffer. diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index a4aee8665854..06b696e9acbd 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -92,10 +92,10 @@ static int dvb_device_open(struct inode *inode, struct file *file) old_fops = file->f_op; file->f_op = fops_get(dvbdev->fops); if(file->f_op->open) - err = file->f_op->open(inode,file); + err = file->f_op->open(inode,file); if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); + fops_put(file->f_op); + file->f_op = fops_get(old_fops); } fops_put(old_fops); return err; @@ -356,18 +356,18 @@ int dvb_usercopy(struct inode *inode, struct file *file, case _IOC_WRITE: case (_IOC_WRITE | _IOC_READ): if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; + parg = sbuf; } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; } err = -EFAULT; if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) - goto out; + goto out; break; } @@ -384,7 +384,7 @@ int dvb_usercopy(struct inode *inode, struct file *file, case _IOC_READ: case (_IOC_WRITE | _IOC_READ): if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; + err = -EFAULT; break; } diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 0cc6e4a0e27c..74ed5853f0fb 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -97,7 +97,7 @@ we simply define out own dvb_usercopy(), which will hopefully become generic_usercopy() someday... */ extern int dvb_usercopy(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, + unsigned int cmd, unsigned long arg, int (*func)(struct inode *inode, struct file *file, unsigned int cmd, void *arg)); diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index 104b5d016c7b..0885d9fb2bf2 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -190,7 +190,7 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe, } static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) + struct dvb_diseqc_master_cmd *m) { struct vp702x_fe_state *st = fe->demodulator_priv; u8 cmd[8],ibuf[10]; diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 17f90ef9ab68..3a3bcf6a2c98 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -56,18 +56,18 @@ comment "DVB-T (terrestrial) frontends" depends on DVB_CORE config DVB_SP8870 - tristate "Spase sp8870 based" + tristate "Spase sp8870 based" depends on DVB_CORE select FW_LOADER help - A DVB-T tuner module. Say Y when you want to support this frontend. + A DVB-T tuner module. Say Y when you want to support this frontend. This driver needs external firmware. Please use the command "/Documentation/dvb/get_dvb_firmware sp8870" to download/extract it, and then copy it to /usr/lib/hotplug/firmware. config DVB_SP887X - tristate "Spase sp887x based" + tristate "Spase sp887x based" depends on DVB_CORE select FW_LOADER help @@ -84,10 +84,10 @@ config DVB_CX22700 A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_CX22702 - tristate "Conexant cx22702 demodulator (OFDM)" - depends on DVB_CORE - help - A DVB-T tuner module. Say Y when you want to support this frontend. + tristate "Conexant cx22702 demodulator (OFDM)" + depends on DVB_CORE + help + A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_L64781 tristate "LSI L64781" @@ -104,7 +104,7 @@ config DVB_TDA1004X This driver needs external firmware. Please use the commands "/Documentation/dvb/get_dvb_firmware tda10045", - "/Documentation/dvb/get_dvb_firmware tda10046" to + "/Documentation/dvb/get_dvb_firmware tda10046" to download/extract them, and then copy them to /usr/lib/hotplug/firmware. config DVB_NXT6000 @@ -146,13 +146,13 @@ config DVB_VES1820 tristate "VLSI VES1820 based" depends on DVB_CORE help - A DVB-C tuner module. Say Y when you want to support this frontend. + A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_TDA10021 tristate "Philips TDA10021 based" depends on DVB_CORE help - A DVB-C tuner module. Say Y when you want to support this frontend. + A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_STV0297 tristate "ST STV0297 based" diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index ecd056e951f1..d15d32c51dc5 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -55,7 +55,7 @@ static int debug; static struct {u8 reg; u8 data;} cx24110_regdata[]= /* Comments beginning with @ denote this value should - be the default */ + be the default */ {{0x09,0x01}, /* SoftResetAll */ {0x09,0x00}, /* release reset */ {0x01,0xe8}, /* MSB of code rate 27.5MS/s */ @@ -66,26 +66,26 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]= {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */ {0x0a,0x00}, /* @ partial chip disables, do not set */ {0x0b,0x01}, /* set output clock in gapped mode, start signal low - active for first byte */ + active for first byte */ {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */ {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */ {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1 - to avoid starting the BER counter. Reset the - CRC test bit. Finite counting selected */ + to avoid starting the BER counter. Reset the + CRC test bit. Finite counting selected */ {0x15,0xff}, /* @ size of the limited time window for RS BER - estimation. It is *256 RS blocks, this - gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ + estimation. It is *256 RS blocks, this + gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ {0x16,0x00}, /* @ enable all RS output ports */ {0x17,0x04}, /* @ time window allowed for the RS to sync */ {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned - for automatically */ + for automatically */ /* leave the current code rate and normalization - registers as they are after reset... */ + registers as they are after reset... */ {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting - only once */ + only once */ {0x23,0x18}, /* @ size of the limited time window for Viterbi BER - estimation. It is *65536 channel bits, i.e. - approx. 38ms at 27.5MS/s, rate 3/4 */ + estimation. It is *65536 channel bits, i.e. + approx. 38ms at 27.5MS/s, rate 3/4 */ {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */ /* leave front-end AGC parameters at default values */ /* leave decimation AGC parameters at default values */ diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index a458a3bfff70..a16eeba0020d 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -574,11 +574,11 @@ static struct dvb_frontend_ops nxt6000_ops = { .symbol_rate_max = 9360000, /* FIXME */ .symbol_rate_tolerance = 4000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, }, .release = nxt6000_release, diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 18715091aed8..d69477596921 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -521,8 +521,8 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state, case FEC_3_4: s5h1420_writereg(state, 0x30, 0x04); - s5h1420_writereg(state, 0x31, 0x12 | inversion); - break; + s5h1420_writereg(state, 0x31, 0x12 | inversion); + break; case FEC_5_6: s5h1420_writereg(state, 0x30, 0x08); diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index e3b665782243..b3ae7dccc33c 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -581,7 +581,7 @@ static struct dvb_frontend_ops sp887x_ops = { .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_RECOVER + FE_CAN_RECOVER }, .release = sp887x_release, diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 425cd19136fe..21255cac9793 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -95,7 +95,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) u8 b0 [] = { reg }; u8 b1 [] = { 0 }; struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; int ret; ret = i2c_transfer (state->i2c, msg, 2); @@ -434,7 +434,7 @@ static struct dvb_frontend_ops tda10021_ops = { .frequency_max = 858000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ - #if 0 +#if 0 .frequency_tolerance = ???, .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ #endif diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index c6ae5bfae5b1..6c237fb2b82a 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -289,10 +289,10 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, case BANDWIDTH_6_MHZ: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, - sizeof(bandwidth_6mhz_53M)); + sizeof(bandwidth_6mhz_53M)); else tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M, - sizeof(bandwidth_6mhz_48M)); + sizeof(bandwidth_6mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab); @@ -302,10 +302,10 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, case BANDWIDTH_7_MHZ: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, - sizeof(bandwidth_7mhz_53M)); + sizeof(bandwidth_7mhz_53M)); else tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M, - sizeof(bandwidth_7mhz_48M)); + sizeof(bandwidth_7mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); @@ -315,10 +315,10 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, case BANDWIDTH_8_MHZ: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, - sizeof(bandwidth_8mhz_53M)); + sizeof(bandwidth_8mhz_53M)); else tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M, - sizeof(bandwidth_8mhz_48M)); + sizeof(bandwidth_8mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55); diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig index f02842be0d60..84f8f9f52869 100644 --- a/drivers/media/dvb/pluto2/Kconfig +++ b/drivers/media/dvb/pluto2/Kconfig @@ -8,7 +8,7 @@ config DVB_PLUTO2 Support for PCI cards based on the Pluto2 FPGA like the Satelco Easywatch Mobile Terrestrial DVB-T Receiver. - Since these cards have no MPEG decoder onboard, they transmit + Since these cards have no MPEG decoder onboard, they transmit only compressed MPEG data over the PCI bus, so you need an external software decoder to watch TV on your computer. diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index fa5034a9ecf5..fa7e38944716 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -18,9 +18,9 @@ config DVB_AV7110 This driver only supports the fullfeatured cards with onboard MPEG2 decoder. - This driver needs an external firmware. Please use the script - "/Documentation/dvb/get_dvb_firmware av7110" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + This driver needs an external firmware. Please use the script + "/Documentation/dvb/get_dvb_firmware av7110" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware. Say Y if you own such a card and want to use it. diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 825ab1c38a4f..a690730ac39d 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -16,7 +16,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ hostprogs-y := fdump ifdef CONFIG_DVB_AV7110_FIRMWARE -$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h +$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h $(obj)/av7110_firm.h: $(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@ diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8fa487fb507b..0bef1edf0018 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2259,7 +2259,7 @@ static int frontend_init(struct av7110 *av7110) } // Try the grundig 29504-451 - av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); + av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; @@ -2285,12 +2285,12 @@ static int frontend_init(struct av7110 *av7110) case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X // ALPS TDLB7 - av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap); + av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap); break; case 0x0002: // Hauppauge/TT DVB-C premium rev2.X - av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); break; case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 87106e8bf35b..54279aaa4828 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -1206,9 +1206,9 @@ int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) switch (cap->cmd) { case OSD_CAP_MEMSIZE: if (FW_4M_SDRAM(av7110->arm_app)) - cap->val = 1000000; + cap->val = 1000000; else - cap->val = 92000; + cap->val = 92000; return 0; default: return -EINVAL; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9a33f6d5d923..f9d00452e639 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -275,7 +275,7 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open // that is unreliable however, so try and read from IO memory if (!cam_present) { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) { cam_present = 1; diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c index 18aa22b5478d..1f31e91195b0 100644 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c @@ -13,7 +13,7 @@ Holger Waechtler Convergence Copyright (C) 2002-2003 Ralph Metzler - Metzler Brothers Systementwicklung GbR + Metzler Brothers Systementwicklung GbR This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig index c6c1d41a2efb..914587d52b57 100644 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ b/drivers/media/dvb/ttusb-budget/Kconfig @@ -10,7 +10,7 @@ config DVB_TTUSB_BUDGET Support for external USB adapters designed by Technotrend and produced by Hauppauge, shipped under the brand name 'Nova-USB'. - These devices don't have a MPEG decoder built in, so you need + These devices don't have a MPEG decoder built in, so you need an external software decoder to watch TV. Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig index c334526af66f..e97244bd232e 100644 --- a/drivers/media/dvb/ttusb-dec/Kconfig +++ b/drivers/media/dvb/ttusb-dec/Kconfig @@ -8,14 +8,14 @@ config DVB_TTUSB_DEC produced by Hauppauge, shipped under the brand name 'DEC2000-t' and 'DEC3000-s'. - Even if these devices have a MPEG decoder built in, they transmit + Even if these devices have a MPEG decoder built in, they transmit only compressed MPEG data over the USB bus, so you need an external software decoder to watch TV on your computer. - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware dec2000t", - "/Documentation/dvb/get_dvb_firmware dec2540t", - "/Documentation/dvb/get_dvb_firmware dec3000s", - download/extract them, and then copy them to /usr/lib/hotplug/firmware. + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware dec2000t", + "/Documentation/dvb/get_dvb_firmware dec2540t", + "/Documentation/dvb/get_dvb_firmware dec3000s", + download/extract them, and then copy them to /usr/lib/hotplug/firmware. Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 36bc9838cf17..d8966d1d25ee 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1182,7 +1182,7 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) (unsigned long)dec); } -static int ttusb_init_rc(struct ttusb_dec *dec) +static int ttusb_init_rc( struct ttusb_dec *dec) { struct input_dev *input_dev; u8 b[] = { 0x00, 0x01 }; @@ -1203,13 +1203,12 @@ static int ttusb_init_rc(struct ttusb_dec *dec) input_dev->keycode = rc_keys; for (i = 0; i < ARRAY_SIZE(rc_keys); i++) - set_bit(rc_keys[i], input_dev->keybit); + set_bit(rc_keys[i], input_dev->keybit); input_register_device(input_dev); if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) printk("%s: usb_submit_urb failed\n",__FUNCTION__); - /* enable irq pipe */ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 7df6a55dd59e..9a9902c56ae7 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -69,7 +69,7 @@ static void video_release(struct class_device *cd) struct video_device *vfd = container_of(cd, struct video_device, class_dev); #if 1 - /* needed until all drivers are fixed */ + /* needed until all drivers are fixed */ if (!vfd->release) return; #endif @@ -339,11 +339,11 @@ int video_register_device(struct video_device *vfd, int type, int nr) if (vfd->dev) vfd->class_dev.dev = vfd->dev; vfd->class_dev.class = &video_class; - vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); + vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE); class_device_register(&vfd->class_dev); class_device_create_file(&vfd->class_dev, - &class_device_attr_name); + &class_device_attr_name); #if 1 /* needed until all drivers are fixed */ diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 3472f08e41fd..1933cd25b610 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -25,7 +25,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include #include #include -- cgit v1.2.3 From fc40b261db15d010455ad0a4e2ac59da2ced730f Mon Sep 17 00:00:00 2001 From: Chris Pascoe Date: Mon, 9 Jan 2006 15:25:35 -0200 Subject: V4L/DVB (3220): Add support for VP-3054 HDTV board - Added support for VP-3054 (aka DigitalNow DNTV Live! DVB-T Pro!). - This board has a secondary I2C bus and remote control. - Added a new module to handle secondary I2C bus on this board. Signed-off-by: Chris Pascoe Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 1 + drivers/media/video/cx88/Makefile | 3 +- drivers/media/video/cx88/cx88-cards.c | 34 ++++++ drivers/media/video/cx88/cx88-dvb.c | 92 ++++++++++++++- drivers/media/video/cx88/cx88-input.c | 78 ++++++++++++- drivers/media/video/cx88/cx88-vp3054-i2c.c | 173 +++++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-vp3054-i2c.h | 35 ++++++ drivers/media/video/cx88/cx88.h | 3 + 8 files changed, 411 insertions(+), 8 deletions(-) create mode 100644 drivers/media/video/cx88/cx88-vp3054-i2c.c create mode 100644 drivers/media/video/cx88/cx88-vp3054-i2c.h diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index bb93a0a1871c..956cf833e931 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -40,3 +40,4 @@ 39 -> KWorld DVB-S 100 [17de:08b2] 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402] 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802] + 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025] diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 90a7ace55f64..e4b2134fe567 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -4,7 +4,7 @@ cx8800-objs := cx88-video.o cx88-vbi.o cx8802-objs := cx88-mpeg.o obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o -obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o +obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o cx88-vp3054-i2c.o EXTRA_CFLAGS += -I$(src)/.. EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core @@ -17,5 +17,6 @@ extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1 extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1 extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1 extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1 +extra-cflags-$(CONFIG_VIDEO_CX88_DVB)+= -DHAVE_VP3054_I2C=1 EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 85798e1fa047..6b17d1e1e520 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -982,6 +982,33 @@ struct cx88_board cx88_boards[] = { /* fixme: Add radio support */ .dvb = 1, }, + [CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = { + .name = "digitalnow DNTV Live! DVB-T Pro", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xf80808, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xf80808, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xf80808, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xf80808, + }, + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1165,6 +1192,10 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x9001, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, + },{ + .subvendor = 0x1822, + .subdevice = 0x0025, + .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1362,6 +1393,9 @@ void cx88_card_setup(struct cx88_core *core) cx_clear(MO_GP0_IO, 0x00000007); cx_set(MO_GP2_IO, 0x00000101); break; + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: + cx_write(MO_GP0_IO, 0x00080808); + break; case CX88_BOARD_ATI_HDTVWONDER: if (0 == core->i2c_rc) { /* enable tuner */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index ed5cfe5f5c0e..201050478711 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -3,7 +3,7 @@ * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines * - * (c) 2004 Chris Pascoe + * (c) 2004, 2005 Chris Pascoe * (c) 2004 Gerd Knorr [SuSE Labs] * * This program is free software; you can redistribute it and/or modify @@ -35,6 +35,9 @@ #ifdef HAVE_MT352 # include "mt352.h" # include "mt352_priv.h" +# ifdef HAVE_VP3054_I2C +# include "cx88-vp3054-i2c.h" +# endif #endif #ifdef HAVE_CX22702 # include "cx22702.h" @@ -108,7 +111,7 @@ static struct videobuf_queue_ops dvb_qops = { /* ------------------------------------------------------------------ */ #ifdef HAVE_MT352 -static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) +static int generic_mt352_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; static u8 reset [] = { RESET, 0x80 }; @@ -166,7 +169,7 @@ static int mt352_pll_set(struct dvb_frontend* fe, static struct mt352_config dvico_fusionhdtv = { .demod_address = 0x0F, - .demod_init = dvico_fusionhdtv_demod_init, + .demod_init = generic_mt352_demod_init, .pll_set = mt352_pll_set, }; @@ -175,6 +178,69 @@ static struct mt352_config dntv_live_dvbt_config = { .demod_init = dntv_live_dvbt_demod_init, .pll_set = mt352_pll_set, }; + +#ifdef HAVE_VP3054_I2C +static int philips_fmd1216_pll_init(struct dvb_frontend *fe) +{ + struct cx8802_dev *dev= fe->dvb->priv; + + /* this message is to set up ATC and ALC */ + static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; + struct i2c_msg msg = + { .addr = dev->core->pll_addr, .flags = 0, + .buf = fmd1216_init, .len = sizeof(fmd1216_init) }; + int err; + + if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + u8* pllbuf) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct i2c_msg msg = + { .addr = dev->core->pll_addr, .flags = 0, + .buf = pllbuf+1, .len = 4 }; + int err; + + /* Switch PLL to DVB mode */ + err = philips_fmd1216_pll_init(fe); + if (err) + return err; + + /* Tune PLL */ + pllbuf[0] = dev->core->pll_addr << 1; + dvb_pll_configure(dev->core->pll_desc, pllbuf+1, + params->frequency, + params->u.ofdm.bandwidth); + if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { + printk(KERN_WARNING "cx88-dvb: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, pllbuf[0], pllbuf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static struct mt352_config dntv_live_dvbt_pro_config = { + .demod_address = 0x0f, + .no_tuner = 1, + .demod_init = generic_mt352_demod_init, + .pll_set = dntv_live_dvbt_pro_pll_set, +}; +#endif #endif #ifdef HAVE_CX22702 @@ -403,6 +469,16 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config, &dev->core->i2c_adap); break; + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: +#ifdef HAVE_VP3054_I2C + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_fmd1216me; + dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config, + &((struct vp3054_i2c_state *)dev->card_priv)->adap); +#else + printk("%s: built without vp3054 support\n", dev->core->name); +#endif + break; #endif #ifdef HAVE_OR51132 case CX88_BOARD_PCHDTV_HD3000: @@ -532,6 +608,12 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, if (0 != err) goto fail_free; +#ifdef HAVE_VP3054_I2C + err = vp3054_i2c_probe(dev); + if (0 != err) + goto fail_free; +#endif + /* dvb stuff */ printk("%s/2: cx2388x based dvb card\n", core->name); videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops, @@ -567,6 +649,10 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev) /* dvb */ videobuf_dvb_unregister(&dev->dvb); +#ifdef HAVE_VP3054_I2C + vp3054_i2c_remove(dev); +#endif + /* common */ cx8802_fini_common(dev); cx88_core_put(dev->core,dev->pci); diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 649bbf7bcc29..f40f97026b84 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -5,7 +5,7 @@ * * Copyright (c) 2003 Pavel Machek * Copyright (c) 2004 Gerd Knorr - * Copyright (c) 2004 Chris Pascoe + * Copyright (c) 2004, 2005 Chris Pascoe * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -305,6 +305,66 @@ static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = { /* ---------------------------------------------------------------------- */ +/* DigitalNow DNTV Live! DVB-T Pro Remote */ +static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = { + [ 0x16 ] = KEY_POWER, + [ 0x5b ] = KEY_HOME, + + [ 0x55 ] = KEY_TV, /* live tv */ + [ 0x58 ] = KEY_TUNER, /* digital Radio */ + [ 0x5a ] = KEY_RADIO, /* FM radio */ + [ 0x59 ] = KEY_DVD, /* dvd menu */ + [ 0x03 ] = KEY_1, + [ 0x01 ] = KEY_2, + [ 0x06 ] = KEY_3, + [ 0x09 ] = KEY_4, + [ 0x1d ] = KEY_5, + [ 0x1f ] = KEY_6, + [ 0x0d ] = KEY_7, + [ 0x19 ] = KEY_8, + [ 0x1b ] = KEY_9, + [ 0x0c ] = KEY_CANCEL, + [ 0x15 ] = KEY_0, + [ 0x4a ] = KEY_CLEAR, + [ 0x13 ] = KEY_BACK, + [ 0x00 ] = KEY_TAB, + [ 0x4b ] = KEY_UP, + [ 0x4e ] = KEY_LEFT, + [ 0x4f ] = KEY_OK, + [ 0x52 ] = KEY_RIGHT, + [ 0x51 ] = KEY_DOWN, + [ 0x1e ] = KEY_VOLUMEUP, + [ 0x0a ] = KEY_VOLUMEDOWN, + [ 0x02 ] = KEY_CHANNELDOWN, + [ 0x05 ] = KEY_CHANNELUP, + [ 0x11 ] = KEY_RECORD, + [ 0x14 ] = KEY_PLAY, + [ 0x4c ] = KEY_PAUSE, + [ 0x1a ] = KEY_STOP, + [ 0x40 ] = KEY_REWIND, + [ 0x12 ] = KEY_FASTFORWARD, + [ 0x41 ] = KEY_PREVIOUSSONG, /* replay |< */ + [ 0x42 ] = KEY_NEXTSONG, /* skip >| */ + [ 0x54 ] = KEY_CAMERA, /* capture */ + [ 0x50 ] = KEY_LANGUAGE, /* sap */ + [ 0x47 ] = KEY_TV2, /* pip */ + [ 0x4d ] = KEY_SCREEN, + [ 0x43 ] = KEY_SUBTITLE, + [ 0x10 ] = KEY_MUTE, + [ 0x49 ] = KEY_AUDIO, /* l/r */ + [ 0x07 ] = KEY_SLEEP, + [ 0x08 ] = KEY_VIDEO, /* a/v */ + [ 0x0e ] = KEY_PREVIOUS, /* recall */ + [ 0x45 ] = KEY_ZOOM, /* zoom + */ + [ 0x46 ] = KEY_ANGLE, /* zoom - */ + [ 0x56 ] = KEY_RED, + [ 0x57 ] = KEY_GREEN, + [ 0x5c ] = KEY_YELLOW, + [ 0x5d ] = KEY_BLUE, +}; + +/* ---------------------------------------------------------------------- */ + struct cx88_IR { struct cx88_core *core; struct input_dev *input; @@ -313,7 +373,7 @@ struct cx88_IR { char phys[32]; /* sample from gpio pin 16 */ - int sampling; + u32 sampling; u32 samples[16]; int scount; unsigned long release; @@ -431,7 +491,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: ir_codes = ir_codes_cinergy_1400; ir_type = IR_TYPE_PD; - ir->sampling = 1; + ir->sampling = 0xeb04; /* address */ break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: @@ -484,6 +544,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keydown = 0x02; ir->polling = 50; /* ms */ break; + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: + ir_codes = ir_codes_dntv_live_dvbt_pro; + ir_type = IR_TYPE_PD; + ir->sampling = 0xff00; /* address */ + break; } if (NULL == ir_codes) { @@ -541,6 +606,10 @@ int cx88_ir_fini(struct cx88_core *core) if (NULL == ir) return 0; + if (ir->sampling) { + cx_write(MO_DDSCFG_IO, 0x0); + core->pci_irqmask &= ~(1 << 18); + } if (ir->polling) { del_timer(&ir->timer); flush_scheduled_work(); @@ -592,6 +661,7 @@ void cx88_ir_irq(struct cx88_core *core) /* decode it */ switch (core->board) { case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4); if (ircode == 0xffffffff) { /* decoding error */ @@ -607,7 +677,7 @@ void cx88_ir_irq(struct cx88_core *core) break; } - if ((ircode & 0xffff) != 0xeb04) { /* wrong address */ + if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */ ir_dprintk("pulse distance decoded wrong address\n"); break; } diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c new file mode 100644 index 000000000000..372cd29cedbd --- /dev/null +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -0,0 +1,173 @@ +/* + + cx88-vp3054-i2c.c -- support for the secondary I2C bus of the + DNTV Live! DVB-T Pro (VP-3054), wired as: + GPIO[0] -> SCL, GPIO[1] -> SDA + + (c) 2005 Chris Pascoe + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include + +#include + +#include "cx88.h" +#include "cx88-vp3054-i2c.h" + + +/* ----------------------------------------------------------------------- */ + +static void vp3054_bit_setscl(void *data, int state) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + struct vp3054_i2c_state *vp3054_i2c = dev->card_priv; + + if (state) { + vp3054_i2c->state |= 0x0001; /* SCL high */ + vp3054_i2c->state &= ~0x0100; /* external pullup */ + } else { + vp3054_i2c->state &= ~0x0001; /* SCL low */ + vp3054_i2c->state |= 0x0100; /* drive pin */ + } + cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state); + cx_read(MO_GP0_IO); +} + +static void vp3054_bit_setsda(void *data, int state) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + struct vp3054_i2c_state *vp3054_i2c = dev->card_priv; + + if (state) { + vp3054_i2c->state |= 0x0002; /* SDA high */ + vp3054_i2c->state &= ~0x0200; /* tristate pin */ + } else { + vp3054_i2c->state &= ~0x0002; /* SDA low */ + vp3054_i2c->state |= 0x0200; /* drive pin */ + } + cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state); + cx_read(MO_GP0_IO); +} + +static int vp3054_bit_getscl(void *data) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + u32 state; + + state = cx_read(MO_GP0_IO); + return (state & 0x01) ? 1 : 0; +} + +static int vp3054_bit_getsda(void *data) +{ + struct cx8802_dev *dev = data; + struct cx88_core *core = dev->core; + u32 state; + + state = cx_read(MO_GP0_IO); + return (state & 0x02) ? 1 : 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_algo_bit_data vp3054_i2c_algo_template = { + .setsda = vp3054_bit_setsda, + .setscl = vp3054_bit_setscl, + .getsda = vp3054_bit_getsda, + .getscl = vp3054_bit_getscl, + .udelay = 16, + .mdelay = 10, + .timeout = 200, +}; + +/* ----------------------------------------------------------------------- */ + +static struct i2c_adapter vp3054_i2c_adap_template = { + .name = "cx2388x", + .owner = THIS_MODULE, + .id = I2C_HW_B_CX2388x, +}; + +static struct i2c_client vp3054_i2c_client_template = { + .name = "VP-3054", +}; + +int vp3054_i2c_probe(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + struct vp3054_i2c_state *vp3054_i2c; + int rc; + + if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + return 0; + + dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); + if (dev->card_priv == NULL) + return -ENOMEM; + vp3054_i2c = dev->card_priv; + + memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template, + sizeof(vp3054_i2c->adap)); + memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template, + sizeof(vp3054_i2c->algo)); + memcpy(&vp3054_i2c->client, &vp3054_i2c_client_template, + sizeof(vp3054_i2c->client)); + + vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL; + + vp3054_i2c->adap.dev.parent = &dev->pci->dev; + strlcpy(vp3054_i2c->adap.name, core->name, + sizeof(vp3054_i2c->adap.name)); + vp3054_i2c->algo.data = dev; + i2c_set_adapdata(&vp3054_i2c->adap, dev); + vp3054_i2c->adap.algo_data = &vp3054_i2c->algo; + vp3054_i2c->client.adapter = &vp3054_i2c->adap; + + vp3054_bit_setscl(dev,1); + vp3054_bit_setsda(dev,1); + + rc = i2c_bit_add_bus(&vp3054_i2c->adap); + if (0 != rc) { + printk("%s: vp3054_i2c register FAILED\n", core->name); + + kfree(dev->card_priv); + dev->card_priv = NULL; + } + + return rc; +} + +void vp3054_i2c_remove(struct cx8802_dev *dev) +{ + struct vp3054_i2c_state *vp3054_i2c = dev->card_priv; + + if (vp3054_i2c == NULL || + dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) + return; + + i2c_bit_del_bus(&vp3054_i2c->adap); + kfree(vp3054_i2c); +} + +EXPORT_SYMBOL(vp3054_i2c_probe); +EXPORT_SYMBOL(vp3054_i2c_remove); diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h new file mode 100644 index 000000000000..b7a0a04d2423 --- /dev/null +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h @@ -0,0 +1,35 @@ +/* + + cx88-vp3054-i2c.h -- support for the secondary I2C bus of the + DNTV Live! DVB-T Pro (VP-3054), wired as: + GPIO[0] -> SCL, GPIO[1] -> SDA + + (c) 2005 Chris Pascoe + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/* ----------------------------------------------------------------------- */ +struct vp3054_i2c_state { + struct i2c_adapter adap; + struct i2c_algo_bit_data algo; + struct i2c_client client; + u32 state; +}; + +/* ----------------------------------------------------------------------- */ +int vp3054_i2c_probe(struct cx8802_dev *dev); +void vp3054_i2c_remove(struct cx8802_dev *dev); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0bbf68b325c4..6d370d1b333f 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -184,6 +184,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_KWORLD_DVBS_100 39 #define CX88_BOARD_HAUPPAUGE_HVR1100 40 #define CX88_BOARD_HAUPPAUGE_HVR1100LP 41 +#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -422,6 +423,8 @@ struct cx8802_dev { struct videobuf_dvb dvb; void* fe_handle; int (*fe_release)(void *handle); + + void *card_priv; /* for switching modulation types */ unsigned char ts_gen_cntrl; -- cgit v1.2.3 From e1bc80adaf801bf75ca176b9c1b60b3cceee1e03 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:36 -0200 Subject: V4L/DVB (3232): Several improvements at tvp5150 driver - Now reset do init tvp5150 registers to its default. - Debug messages improved. - Implemented video standard selection function. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp5150.c | 423 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 362 insertions(+), 61 deletions(-) diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index d62b2302af49..9ed839d688eb 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "tvp5150_reg.h" @@ -28,10 +29,14 @@ static int debug = 0; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -#define dprintk(num, format, args...) \ +#define tvp5150_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->name, \ + i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0) +#define tvp5150_dbg(num, fmt, arg...) \ do { \ if (debug >= num) \ - printk(format, ##args); \ + printk(KERN_DEBUG "%s debug %d-%04x: " fmt, c->driver->name, \ + i2c_adapter_id(c->adapter), c->addr , ## arg); \ } while (0) /* supported controls */ @@ -94,12 +99,14 @@ static inline int tvp5150_read(struct i2c_client *c, unsigned char addr) buffer[0] = addr; if (1 != (rc = i2c_master_send(c, buffer, 1))) - dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc); + tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc); msleep(10); if (1 != (rc = i2c_master_recv(c, buffer, 1))) - dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc); + tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc); + + tvp5150_dbg(2, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]); return (buffer[0]); } @@ -109,13 +116,12 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr, { unsigned char buffer[2]; int rc; -/* struct tvp5150 *core = i2c_get_clientdata(c); */ buffer[0] = addr; buffer[1] = value; - dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]); + tvp5150_dbg(2, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]); if (2 != (rc = i2c_master_send(c, buffer, 2))) - dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc); + tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc); } static void dump_reg(struct i2c_client *c) @@ -458,40 +464,325 @@ static inline void tvp5150_selmux(struct i2c_client *c, tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input); }; -static inline void tvp5150_reset(struct i2c_client *c) +struct i2c_reg_value { + unsigned char reg; + unsigned char value; +}; + +/* Default values as sugested at TVP5150AM1 datasheet */ +static const struct i2c_reg_value tvp5150_init_default[] = { + { /* 0x00 */ + TVP5150_VD_IN_SRC_SEL_1,0x00 + }, + { /* 0x01 */ + TVP5150_ANAL_CHL_CTL,0x15 + }, + { /* 0x02 */ + TVP5150_OP_MODE_CTL,0x00 + }, + { /* 0x03 */ + TVP5150_MISC_CTL,0x01 + }, + { /* 0x06 */ + TVP5150_COLOR_KIL_THSH_CTL,0x10 + }, + { /* 0x07 */ + TVP5150_LUMA_PROC_CTL_1,0x60 + }, + { /* 0x08 */ + TVP5150_LUMA_PROC_CTL_2,0x00 + }, + { /* 0x09 */ + TVP5150_BRIGHT_CTL,0x80 + }, + { /* 0x0a */ + TVP5150_SATURATION_CTL,0x80 + }, + { /* 0x0b */ + TVP5150_HUE_CTL,0x00 + }, + { /* 0x0c */ + TVP5150_CONTRAST_CTL,0x80 + }, + { /* 0x0d */ + TVP5150_DATA_RATE_SEL,0x47 + }, + { /* 0x0e */ + TVP5150_LUMA_PROC_CTL_3,0x00 + }, + { /* 0x0f */ + TVP5150_CONF_SHARED_PIN,0x08 + }, + { /* 0x11 */ + TVP5150_ACT_VD_CROP_ST_MSB,0x00 + }, + { /* 0x12 */ + TVP5150_ACT_VD_CROP_ST_LSB,0x00 + }, + { /* 0x13 */ + TVP5150_ACT_VD_CROP_STP_MSB,0x00 + }, + { /* 0x14 */ + TVP5150_ACT_VD_CROP_STP_LSB,0x00 + }, + { /* 0x15 */ + TVP5150_GENLOCK,0x01 + }, + { /* 0x16 */ + TVP5150_HORIZ_SYNC_START,0x80 + }, + { /* 0x18 */ + TVP5150_VERT_BLANKING_START,0x00 + }, + { /* 0x19 */ + TVP5150_VERT_BLANKING_STOP,0x00 + }, + { /* 0x1a */ + TVP5150_CHROMA_PROC_CTL_1,0x0c + }, + { /* 0x1b */ + TVP5150_CHROMA_PROC_CTL_2,0x14 + }, + { /* 0x1c */ + TVP5150_INT_RESET_REG_B,0x00 + }, + { /* 0x1d */ + TVP5150_INT_ENABLE_REG_B,0x00 + }, + { /* 0x1e */ + TVP5150_INTT_CONFIG_REG_B,0x00 + }, + { /* 0x28 */ + TVP5150_VIDEO_STD,0x00 + }, + { /* 0x2e */ + TVP5150_MACROVISION_ON_CTR,0x0f + }, + { /* 0x2f */ + TVP5150_MACROVISION_OFF_CTR,0x01 + }, + { /* 0xbb */ + TVP5150_TELETEXT_FIL_ENA,0x00 + }, + { /* 0xc0 */ + TVP5150_INT_STATUS_REG_A,0x00 + }, + { /* 0xc1 */ + TVP5150_INT_ENABLE_REG_A,0x00 + }, + { /* 0xc2 */ + TVP5150_INT_CONF,0x04 + }, + { /* 0xc8 */ + TVP5150_FIFO_INT_THRESHOLD,0x80 + }, + { /* 0xc9 */ + TVP5150_FIFO_RESET,0x00 + }, + { /* 0xca */ + TVP5150_LINE_NUMBER_INT,0x00 + }, + { /* 0xcb */ + TVP5150_PIX_ALIGN_REG_LOW,0x4e + }, + { /* 0xcc */ + TVP5150_PIX_ALIGN_REG_HIGH,0x00 + }, + { /* 0xcd */ + TVP5150_FIFO_OUT_CTRL,0x01 + }, + { /* 0xcf */ + TVP5150_FULL_FIELD_ENA_1,0x00 + }, + { /* 0xd0 */ + TVP5150_FULL_FIELD_ENA_2,0x00 + }, + { /* 0xfc */ + TVP5150_FULL_FIELD_MODE_REG,0x7f + }, + { /* end of data */ + 0xff,0xff + } +}; + +/* Default values as sugested at TVP5150AM1 datasheet */ +static const struct i2c_reg_value tvp5150_init_enable[] = { + { + TVP5150_CONF_SHARED_PIN, 2 + },{ /* Automatic offset and AGC enabled */ + TVP5150_ANAL_CHL_CTL, 0x15 + },{ /* Activate YCrCb output 0x9 or 0xd ? */ + TVP5150_MISC_CTL, 0x6f + },{ /* Activates video std autodetection for all standards */ + TVP5150_AUTOSW_MSK, 0x0 + },{ /* Default format: 0x47. For 4:2:2: 0x40 */ + TVP5150_DATA_RATE_SEL, 0x47 + },{ + TVP5150_CHROMA_PROC_CTL_1, 0x0c + },{ + TVP5150_CHROMA_PROC_CTL_2, 0x54 + },{ /* Non documented, but initialized on WinTV USB2 */ + 0x27, 0x20 + },{ + 0xff,0xff + } +}; + +struct i2c_vbi_ram_value { + u16 reg; + unsigned char values[26]; +}; + +struct i2c_vbi_ram_value vbi_ram_default[] = { - struct tvp5150 *decoder = i2c_get_clientdata(c); + {0x010, /* WST SECAM 6 */ + { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 } + }, + {0x030, /* WST PAL B 6 */ + { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 } + }, + {0x050, /* WST PAL C 6 */ + { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 } + }, + {0x070, /* WST NTSC 6 */ + { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 } + }, + {0x090, /* NABTS, NTSC 6 */ + { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 } + }, + {0x0b0, /* NABTS, NTSC-J 6 */ + { 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 } + }, + {0x0d0, /* CC, PAL/SECAM 6 */ + { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 } + }, + {0x0f0, /* CC, NTSC 6 */ + { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 } + }, + {0x110, /* WSS, PAL/SECAM 6 */ + { 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 } + }, + {0x130, /* WSS, NTSC C */ + { 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 } + }, + {0x150, /* VITC, PAL/SECAM 6 */ + { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 } + }, + {0x170, /* VITC, NTSC 6 */ + { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 } + }, + { (u16)-1 } +}; - tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2); +static int tvp5150_write_inittab(struct i2c_client *c, + const struct i2c_reg_value *regs) +{ + while (regs->reg != 0xff) { + tvp5150_write(c, regs->reg, regs->value); + regs++; + } + return 0; +} - /* Automatic offset and AGC enabled */ - tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15); +static int tvp5150_vdp_init(struct i2c_client *c, + const struct i2c_vbi_ram_value *regs) +{ + unsigned int i; - /* Normal Operation */ -// tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00); + /* Disable Full Field */ + tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0); - /* Activate YCrCb output 0x9 or 0xd ? */ - tvp5150_write(c, TVP5150_MISC_CTL, 0x6f); + /* Before programming, Line mode should be at 0xff */ + for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++) + tvp5150_write(c, i, 0xff); - /* Activates video std autodetection for all standards */ - tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0); + /* Load Ram Table */ + while (regs->reg != (u16)-1 ) { + tvp5150_write(c, TVP5150_CONF_RAM_ADDR_HIGH,regs->reg>>8); + tvp5150_write(c, TVP5150_CONF_RAM_ADDR_LOW,regs->reg); - /* Default format: 0x47, 4:2:2: 0x40 */ - tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47); + for (i=0;i<16;i++) + tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]); - tvp5150_selmux(c, decoder->input); + regs++; + } + return 0; +} - tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c); - tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54); +static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std) +{ + struct tvp5150 *decoder = i2c_get_clientdata(c); + int fmt=0; + + decoder->norm=std; + + /* First tests should be against specific std */ + + if (std == V4L2_STD_ALL) { + fmt=0; /* Autodetect mode */ + } else if (std & V4L2_STD_NTSC_443) { + fmt=0xa; + } else if (std & V4L2_STD_PAL_M) { + fmt=0x6; + } else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) { + fmt=0x8; + } else { + /* Then, test against generic ones */ + if (std & V4L2_STD_NTSC) { + fmt=0x2; + } else if (std & V4L2_STD_PAL) { + fmt=0x4; + } else if (std & V4L2_STD_SECAM) { + fmt=0xc; + } + } - tvp5150_write(c, 0x27, 0x20); /* ?????????? */ + tvp5150_dbg(1,"Set video std register to %d.\n",fmt); + tvp5150_write(c, TVP5150_VIDEO_STD, fmt); - tvp5150_write(c, TVP5150_VIDEO_STD, 0x0); /* Auto switch */ + return 0; +} + +static inline void tvp5150_reset(struct i2c_client *c) +{ + u8 type, ver_656, msb_id, lsb_id, msb_rom, lsb_rom; + struct tvp5150 *decoder = i2c_get_clientdata(c); + + type=tvp5150_read(c,TVP5150_AUTOSW_MSK); + msb_id=tvp5150_read(c,TVP5150_MSB_DEV_ID); + lsb_id=tvp5150_read(c,TVP5150_LSB_DEV_ID); + msb_rom=tvp5150_read(c,TVP5150_ROM_MAJOR_VER); + lsb_rom=tvp5150_read(c,TVP5150_ROM_MINOR_VER); + + if (type==0xdc) { + ver_656=tvp5150_read(c,TVP5150_REV_SELECT); + tvp5150_info("tvp%02x%02xam1 detected 656 version is %d.\n",msb_id, lsb_id,ver_656); + } else if (type==0xfc) { + tvp5150_info("tvp%02x%02xa detected.\n",msb_id, lsb_id); + } else { + tvp5150_info("unknown tvp%02x%02x chip detected(%d).\n",msb_id,lsb_id,type); + } + tvp5150_info("Rom ver is %d.%d\n",msb_rom,lsb_rom); + /* Initializes TVP5150 to its default values */ + tvp5150_write_inittab(c, tvp5150_init_default); + + /* Initializes VDP registers */ + tvp5150_vdp_init(c, vbi_ram_default); + + /* Selects decoder input */ + tvp5150_selmux(c, decoder->input); + + /* Initializes TVP5150 to stream enabled values */ + tvp5150_write_inittab(c, tvp5150_init_enable); + + /* Initialize image preferences */ tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8); tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8); tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8); tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8); + + tvp5150_set_std(c, decoder->norm); }; static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) @@ -539,20 +830,28 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) /**************************************************************************** I2C Command ****************************************************************************/ -static int tvp5150_command(struct i2c_client *client, +static int tvp5150_command(struct i2c_client *c, unsigned int cmd, void *arg) { - struct tvp5150 *decoder = i2c_get_clientdata(client); + struct tvp5150 *decoder = i2c_get_clientdata(c); switch (cmd) { case 0: + case VIDIOC_INT_RESET: case DECODER_INIT: - tvp5150_reset(client); + tvp5150_reset(c); + break; + case VIDIOC_S_STD: + if (decoder->norm == *(v4l2_std_id *)arg) + break; + return tvp5150_set_std(c, *(v4l2_std_id *)arg); + case VIDIOC_G_STD: + *(v4l2_std_id *)arg = decoder->norm; break; case DECODER_DUMP: - dump_reg(client); + dump_reg(c); break; case DECODER_GET_CAPABILITIES: @@ -611,7 +910,7 @@ static int tvp5150_command(struct i2c_client *client, } decoder->input = *iarg; - tvp5150_selmux(client, decoder->input); + tvp5150_selmux(c, decoder->input); break; } @@ -631,7 +930,7 @@ static int tvp5150_command(struct i2c_client *client, decoder->enable = (*iarg != 0); - tvp5150_selmux(client, decoder->input); + tvp5150_selmux(c, decoder->input); break; } @@ -640,7 +939,7 @@ static int tvp5150_command(struct i2c_client *client, struct v4l2_queryctrl *qc = arg; int i; - dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL"); + tvp5150_dbg(1, "VIDIOC_QUERYCTRL called\n"); for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++) if (qc->id && qc->id == tvp5150_qctrl[i].id) { @@ -654,15 +953,14 @@ static int tvp5150_command(struct i2c_client *client, case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; - dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL"); + tvp5150_dbg(1, "VIDIOC_G_CTRL called\n"); - return tvp5150_get_ctrl(client, ctrl); + return tvp5150_get_ctrl(c, ctrl); } case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; u8 i, n; - dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL"); n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]); for (i = 0; i < n; i++) if (ctrl->id == tvp5150_qctrl[i].id) { @@ -671,11 +969,10 @@ static int tvp5150_command(struct i2c_client *client, || ctrl->value > tvp5150_qctrl[i].maximum) return -ERANGE; - dprintk(1, - KERN_DEBUG - "VIDIOC_S_CTRL: id=%d, value=%d", + tvp5150_dbg(1, + "VIDIOC_S_CTRL: id=%d, value=%d\n", ctrl->id, ctrl->value); - return tvp5150_set_ctrl(client, ctrl); + return tvp5150_set_ctrl(c, ctrl); } return -EINVAL; } @@ -686,25 +983,25 @@ static int tvp5150_command(struct i2c_client *client, if (decoder->bright != pic->brightness) { /* We want 0 to 255 we get 0-65535 */ decoder->bright = pic->brightness; - tvp5150_write(client, TVP5150_BRIGHT_CTL, + tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8); } if (decoder->contrast != pic->contrast) { /* We want 0 to 255 we get 0-65535 */ decoder->contrast = pic->contrast; - tvp5150_write(client, TVP5150_CONTRAST_CTL, + tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8); } if (decoder->sat != pic->colour) { /* We want 0 to 255 we get 0-65535 */ decoder->sat = pic->colour; - tvp5150_write(client, TVP5150_SATURATION_CTL, + tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8); } if (decoder->hue != pic->hue) { /* We want -128 to 127 we get 0-65535 */ decoder->hue = pic->hue; - tvp5150_write(client, TVP5150_HUE_CTL, + tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8); } break; @@ -729,12 +1026,12 @@ static struct i2c_client client_template = { static int tvp5150_detect_client(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *client; + struct i2c_client *c; struct tvp5150 *core; int rv; - dprintk(1, - KERN_INFO + if (debug) + printk( KERN_INFO "tvp5150.c: detecting tvp5150 client on address 0x%x\n", address << 1); @@ -747,22 +1044,22 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter, I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return 0; - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (c == 0) return -ENOMEM; - memcpy(client, &client_template, sizeof(struct i2c_client)); + memcpy(c, &client_template, sizeof(struct i2c_client)); core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL); if (core == 0) { - kfree(client); + kfree(c); return -ENOMEM; } memset(core, 0, sizeof(struct tvp5150)); - i2c_set_clientdata(client, core); + i2c_set_clientdata(c, core); - rv = i2c_attach_client(client); + rv = i2c_attach_client(c); - core->norm = VIDEO_MODE_AUTO; + core->norm = V4L2_STD_ALL; core->input = 2; core->enable = 1; core->bright = 32768; @@ -771,37 +1068,41 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter, core->sat = 32768; if (rv) { - kfree(client); + kfree(c); kfree(core); return rv; } if (debug > 1) - dump_reg(client); + dump_reg(c); return 0; } static int tvp5150_attach_adapter(struct i2c_adapter *adapter) { - dprintk(1, - KERN_INFO + if (debug) + printk( KERN_INFO "tvp5150.c: starting probe for adapter %s (0x%x)\n", adapter->name, adapter->id); return i2c_probe(adapter, &addr_data, &tvp5150_detect_client); } -static int tvp5150_detach_client(struct i2c_client *client) +static int tvp5150_detach_client(struct i2c_client *c) { - struct tvp5150 *decoder = i2c_get_clientdata(client); + struct tvp5150 *decoder = i2c_get_clientdata(c); int err; - err = i2c_detach_client(client); + tvp5150_dbg(1, + "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", + c->addr << 1); + + err = i2c_detach_client(c); if (err) { return err; } kfree(decoder); - kfree(client); + kfree(c); return 0; } -- cgit v1.2.3 From 9bb13a6dc3a6f68c990264838ff0493d900c48d7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:37 -0200 Subject: V4L/DVB (3233): Fixed API to set I2S speed control - Created a new ioctl to control I2S speed. Old calls to an inadequate V4L2 API replaced. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 8 ++------ drivers/media/video/em28xx/em28xx-video.c | 2 ++ drivers/media/video/em28xx/em28xx.h | 2 ++ drivers/media/video/msp3400.c | 30 ++++++++++++++++++++++-------- include/linux/videodev2.h | 1 - include/media/v4l2-common.h | 7 +++++++ 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 57779e63f35d..58f7b4194a0d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "msp3400.h" #include "em28xx.h" @@ -261,7 +262,6 @@ void em28xx_card_setup(struct em28xx *dev) /* request some modules */ if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) { struct tveeprom tv; - struct v4l2_audioout ao; #ifdef CONFIG_MODULES request_module("tveeprom"); request_module("ir-kbd-i2c"); @@ -274,12 +274,8 @@ void em28xx_card_setup(struct em28xx *dev) dev->tuner_type= tv.tuner_type; if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed=2048000; dev->has_msp34xx=1; - memset (&ao,0,sizeof(ao)); - - ao.index=2; - ao.mode=V4L2_AUDMODE_32BITS; - em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao); } else dev->has_msp34xx=0; } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 5e831fccf3fd..0b5557c479ae 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -287,6 +287,8 @@ static void video_mux(struct em28xx *dev, int index) em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput); if (dev->has_msp34xx) { + if (dev->i2s_speed) + em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput); ainput = EM28XX_AUDIO_SRC_TUNER; em28xx_audio_source(dev, ainput); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 5c7a41ce69f3..ffa9acc9be37 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -216,6 +216,8 @@ struct em28xx { unsigned int has_msp34xx:1; unsigned int has_tda9887:1; + u32 i2s_speed; /* I2S speed for audio digital stream */ + enum em28xx_decoder decoder; int tuner_type; /* type of the tuner */ diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index fd0589352822..11235c1ac5c6 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -54,6 +54,7 @@ #include #include +#include #include "msp3400.h" /* ---------------------------------------------------------------------- */ @@ -2104,23 +2105,36 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (a->index<0||a->index>2) return -EINVAL; - if (a->index==2) { - if (a->mode == V4L2_AUDMODE_32BITS) - msp->i2s_mode=1; - else - msp->i2s_mode=0; - } - msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",a->index,msp->i2s_mode); + msp3400_dbg("Setting audio out on msp34xx to input %i\n",a->index); msp3400c_set_scart(client,msp->in_scart,a->index+1); break; } + case VIDIOC_INT_I2S_CLOCK_FREQ: + { + u32 *a=(u32 *)arg; + + msp3400_dbg("Setting I2S speed to %d\n",*a); + + switch (*a) { + case 1024000: + msp->i2s_mode=0; + break; + case 2048000: + msp->i2s_mode=1; + break; + default: + return -EINVAL; + } + break; + } + case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; int i; - msp3400_dbg("VIDIOC_QUERYCTRL"); + msp3400_dbg("VIDIOC_QUERYCTRL\n"); for (i = 0; i < ARRAY_SIZE(msp34xx_qctrl); i++) if (qc->id && qc->id == msp34xx_qctrl[i].id) { diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index b2f5e864b397..6ac7c1f7902f 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -895,7 +895,6 @@ struct v4l2_audio /* Flags for the 'mode' field */ #define V4L2_AUDMODE_AVL 0x00001 -#define V4L2_AUDMODE_32BITS 0x00002 struct v4l2_audioout { diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index d3fd48157eb8..2f2402996409 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -107,4 +107,11 @@ enum v4l2_chip_ident { be made. */ #define VIDIOC_INT_G_CHIP_IDENT _IOR ('d', 107, enum v4l2_chip_ident *) +/* Sets I2S speed in bps. This is used to provide a standard way to select I2S + clock used by driving digital audio streams at some board designs. + Usual values for the frequency are 1024000 and 2048000. + If the frequency is not supported, then -EINVAL is returned. */ +#define VIDIOC_INT_I2S_CLOCK_FREQ _IOW ('d', 108, u32) + + #endif /* V4L2_COMMON_H_ */ -- cgit v1.2.3 From 21dcd8ccd76e80118f524b1a730c35ab1c46c09e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:25:37 -0200 Subject: V4L/DVB (3234): Included advanced debug option to tvp5150.c - Included advanced debug option to tvp5150.c - Now, advanced debug info is the first item at V4L menu. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 16 +++++++++------- drivers/media/video/tvp5150.c | 24 ++++++++++++++++++++++++ include/linux/i2c-id.h | 1 + 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c89cc0a922ee..2fe260fff85d 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -7,6 +7,15 @@ menu "Video For Linux" comment "Video Adapters" +config VIDEO_ADV_DEBUG + bool "Enable advanced debug functionality" + depends on VIDEO_DEV + default n + ---help--- + Say Y here to enable advanced debugging functionality on some + V4L devices. + In doubt, say N. + config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C @@ -344,11 +353,4 @@ config VIDEO_DECODER Say Y here to compile drivers for SAA7115, SAA7127 and CX25840 video decoders. -config VIDEO_ADV_DEBUG - bool "Enable advanced debug functionality" - depends on VIDEO_DEV && VIDEO_DECODER && EXPERIMENTAL - ---help--- - Say Y here to enable advanced debugging functionality in the - SAA7115, SAA7127 and CX25840 video decoders. - endmenu diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 9ed839d688eb..07ad675cd58e 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -850,6 +850,30 @@ static int tvp5150_command(struct i2c_client *c, *(v4l2_std_id *)arg = decoder->norm; break; +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_INT_G_REGISTER: + { + struct v4l2_register *reg = arg; + + if (reg->i2c_id != I2C_DRIVERID_TVP5150) + return -EINVAL; + reg->val = tvp5150_read(c, reg->reg & 0xff); + break; + } + + case VIDIOC_INT_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (reg->i2c_id != I2C_DRIVERID_TVP5150) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff); + break; + } +#endif + case DECODER_DUMP: dump_reg(c); break; diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index fb46f8d56999..6ff2d365895f 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -103,6 +103,7 @@ #define I2C_DRIVERID_SAA711X 73 /* saa711x video encoders */ #define I2C_DRIVERID_AKITAIOEXP 74 /* IO Expander on Sharp SL-C1000 */ #define I2C_DRIVERID_INFRARED 75 /* I2C InfraRed on Video boards */ +#define I2C_DRIVERID_TVP5150 76 /* TVP5150 video decoder */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ -- cgit v1.2.3 From 90200d2b7f526128671a971ab29db38973bf3f51 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:38 -0200 Subject: V4L/DVB (3239): reorganize tuner-simple threshold structure. - Create an array containing frequency threshold and control byte. - allows for an arbitrary amount of frequency ranges to be set, like dvb-pll. - improves code readability. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 768 ++++++++++++++++++++----------------- 1 file changed, 417 insertions(+), 351 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 985464f4b7c2..e5fb74365836 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -79,17 +79,19 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); #define TUNER_PLL_LOCKED 0x40 #define TUNER_STEREO_MK3 0x04 +#define TUNER_MAX_RANGES 3 + /* ---------------------------------------------------------------------- */ struct tunertype { char *name; - unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ - unsigned short thresh2; /* band switch VHF_HI <=> UHF */ - unsigned char VHF_L; - unsigned char VHF_H; - unsigned char UHF; + int count; + struct { + unsigned short thresh; + unsigned char cb; + } ranges[TUNER_MAX_RANGES]; unsigned char config; }; @@ -102,305 +104,336 @@ static struct tunertype tuners[] = { /* 0-9 */ [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ .name = "Temic PAL (4002 FH5)", - .thresh1= 16 * 140.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0x02, - .VHF_H = 0x04, - .UHF = 0x01, + .count = 3, + .ranges = { + { 16 * 140.25 /*MHz*/, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x04, }, + { 16 * 999.99 , 0x01, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ .name = "Philips PAL_I (FI1246 and compatibles)", - .thresh1= 16 * 140.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 140.25 /*MHz*/, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ .name = "Philips NTSC (FI1236,FM1236 and compatibles)", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 451.25 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0xa0, }, + { 16 * 451.25 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", - .thresh1= 16 * 168.25 /*MHz*/, - .thresh2= 16 * 447.25 /*MHz*/, - .VHF_L = 0xa7, - .VHF_H = 0x97, - .UHF = 0x37, + .count = 3, + .ranges = { + { 16 * 168.25 /*MHz*/, 0xa7, }, + { 16 * 447.25 /*MHz*/, 0x97, }, + { 16 * 999.99 , 0x37, }, + }, .config = 0x8e, }, [TUNER_ABSENT] = { /* Tuner Absent */ .name = "NoTuner", - .thresh1= 0 /*MHz*/, - .thresh2= 0 /*MHz*/, - .VHF_L = 0x00, - .VHF_H = 0x00, - .UHF = 0x00, + .count = 1, + .ranges = { + { 0, 0x00, }, + }, .config = 0x00, }, [TUNER_PHILIPS_PAL] = { /* Philips PAL */ .name = "Philips PAL_BG (FI1216 and compatibles)", - .thresh1= 16 * 168.25 /*MHz*/, - .thresh2= 16 * 447.25 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 168.25 /*MHz*/, 0xa0, }, + { 16 * 447.25 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ .name = "Temic NTSC (4032 FY5)", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0x02, - .VHF_H = 0x04, - .UHF = 0x01, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x04, }, + { 16 * 999.99 , 0x01, }, + }, .config = 0x8e, }, [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ .name = "Temic PAL_I (4062 FY5)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0x02, - .VHF_H = 0x04, - .UHF = 0x01, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0x02, }, + { 16 * 450.00 /*MHz*/, 0x04, }, + { 16 * 999.99 , 0x01, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ .name = "Temic NTSC (4036 FY5)", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ .name = "Alps HSBH1", - .thresh1= 16 * 137.25 /*MHz*/, - .thresh2= 16 * 385.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 137.25 /*MHz*/, 0x01, }, + { 16 * 385.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, /* 10-19 */ [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ .name = "Alps TSBE1", - .thresh1= 16 * 137.25 /*MHz*/, - .thresh2= 16 * 385.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 137.25 /*MHz*/, 0x01, }, + { 16 * 385.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ .name = "Alps TSBB5", - .thresh1= 16 * 133.25 /*MHz*/, - .thresh2= 16 * 351.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 133.25 /*MHz*/, 0x01, }, + { 16 * 351.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ .name = "Alps TSBE5", - .thresh1= 16 * 133.25 /*MHz*/, - .thresh2= 16 * 351.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 133.25 /*MHz*/, 0x01, }, + { 16 * 351.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ .name = "Alps TSBC5", - .thresh1= 16 * 133.25 /*MHz*/, - .thresh2= 16 * 351.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 133.25 /*MHz*/, 0x01, }, + { 16 * 351.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ .name = "Temic PAL_BG (4006FH5)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ .name = "Alps TSCH6", - .thresh1= 16 * 137.25 /*MHz*/, - .thresh2= 16 * 385.25 /*MHz*/, - .VHF_L = 0x14, - .VHF_H = 0x12, - .UHF = 0x11, + .count = 3, + .ranges = { + { 16 * 137.25 /*MHz*/, 0x14, }, + { 16 * 385.25 /*MHz*/, 0x12, }, + { 16 * 999.99 , 0x11, }, + }, .config = 0x8e, }, [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ .name = "Temic PAL_DK (4016 FY5)", - .thresh1= 16 * 168.25 /*MHz*/, - .thresh2= 16 * 456.25 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 168.25 /*MHz*/, 0xa0, }, + { 16 * 456.25 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ .name = "Philips NTSC_M (MK2)", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ .name = "Temic PAL_I (4066 FY5)", - .thresh1= 16 * 169.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 169.00 /*MHz*/, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ .name = "Temic PAL* auto (4006 FN5)", - .thresh1= 16 * 169.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 169.00 /*MHz*/, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, /* 20-29 */ [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", - .thresh1= 16 * 141.00 /*MHz*/, - .thresh2= 16 * 464.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 141.00 /*MHz*/, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ .name = "Temic NTSC (4039 FR5)", - .thresh1= 16 * 158.00 /*MHz*/, - .thresh2= 16 * 453.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 158.00 /*MHz*/, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ .name = "Temic PAL/SECAM multi (4046 FM5)", - .thresh1= 16 * 169.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 169.00 /*MHz*/, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ .name = "Philips PAL_DK (FI1256 and compatibles)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ .name = "Philips PAL/SECAM multi (FQ1216ME)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ .name = "LG PAL_I+FM (TAPC-I001D)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ .name = "LG PAL_I (TAPC-I701D)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ .name = "LG NTSC+FM (TPI8NSR01F)", - .thresh1= 16 * 210.00 /*MHz*/, - .thresh2= 16 * 497.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 210.00 /*MHz*/, 0xa0, }, + { 16 * 497.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ .name = "LG PAL_BG+FM (TPI8PSB01D)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ .name = "LG PAL_BG (TPI8PSB11D)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, /* 30-39 */ [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ .name = "Temic PAL* auto + FM (4009 FN5)", - .thresh1= 16 * 141.00 /*MHz*/, - .thresh2= 16 * 464.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 141.00 /*MHz*/, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ .name = "SHARP NTSC_JP (2U5JF5540)", - .thresh1= 16 * 137.25 /*MHz*/, - .thresh2= 16 * 317.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 137.25 /*MHz*/, 0x01, }, + { 16 * 317.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ .name = "Samsung PAL TCPM9091PD27", - .thresh1= 16 * 169 /*MHz*/, - .thresh2= 16 * 464 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 169 /*MHz*/, 0xa0, }, + { 16 * 464 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_MT2032] = { /* Microtune PAL|NTSC */ @@ -408,186 +441,206 @@ static struct tunertype tuners[] = { /* see mt20xx.c for details */ }, [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ .name = "Temic PAL_BG (4106 FH5)", - .thresh1= 16 * 141.00 /*MHz*/, - .thresh2= 16 * 464.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 141.00 /*MHz*/, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ .name = "Temic PAL_DK/SECAM_L (4012 FY5)", - .thresh1= 16 * 140.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0x02, - .VHF_H = 0x04, - .UHF = 0x01, + .count = 3, + .ranges = { + { 16 * 140.25 /*MHz*/, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x04, }, + { 16 * 999.99 , 0x01, }, + }, .config = 0x8e, }, [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ .name = "Temic NTSC (4136 FY5)", - .thresh1= 16 * 158.00 /*MHz*/, - .thresh2= 16 * 453.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 158.00 /*MHz*/, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ .name = "LG PAL (newer TAPC series)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ .name = "Philips PAL/SECAM multi (FM1216ME MK3)", - .thresh1= 16 * 158.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 158.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ .name = "LG NTSC (newer TAPC series)", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, /* 40-49 */ [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ .name = "HITACHI V7-J180AT", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ .name = "Philips PAL_MK (FI1216 MK)", - .thresh1= 16 * 140.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0xc2, - .UHF = 0xcf, + .count = 3, + .ranges = { + { 16 * 140.25 /*MHz*/, 0x01, }, + { 16 * 463.25 /*MHz*/, 0xc2, }, + { 16 * 999.99 , 0xcf, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */ .name = "Philips 1236D ATSC/NTSC dual in", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ .name = "Microtune 4049 FM5", - .thresh1= 16 * 141.00 /*MHz*/, - .thresh2= 16 * 464.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 141.00 /*MHz*/, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ .name = "Panasonic VP27s/ENGE4324D", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0xce, }, [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ .name = "LG NTSC (TAPE series)", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_TNF_8831BGFF] = { /* Philips PAL */ .name = "Tenna TNF 8831 BGFF)", - .thresh1= 16 * 161.25 /*MHz*/, - .thresh2= 16 * 463.25 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 161.25 /*MHz*/, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ .name = "Microtune 4042 FI5 ATSC/NTSC dual in", - .thresh1= 16 * 162.00 /*MHz*/, - .thresh2= 16 * 457.00 /*MHz*/, - .VHF_L = 0xa2, - .VHF_H = 0x94, - .UHF = 0x31, + .count = 3, + .ranges = { + { 16 * 162.00 /*MHz*/, 0xa2, }, + { 16 * 457.00 /*MHz*/, 0x94, }, + { 16 * 999.99 , 0x31, }, + }, .config = 0x8e, }, /* 50-59 */ [TUNER_TCL_2002N] = { /* TCL NTSC */ .name = "TCL 2002N", - .thresh1= 16 * 172.00 /*MHz*/, - .thresh2= 16 * 448.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 172.00 /*MHz*/, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ .name = "Thomson DTT 7610 (ATSC/NTSC)", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0x39, - .VHF_H = 0x3a, - .UHF = 0x3c, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0x39, }, + { 16 * 454.00 /*MHz*/, 0x3a, }, + { 16 * 999.99 , 0x3c, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ .name = "Philips FQ1286", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0x41, - .VHF_H = 0x42, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x41, }, + { 16 * 454.00 /*MHz*/, 0x42, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ @@ -595,47 +648,52 @@ static struct tunertype tuners[] = { /* see tda8290.c for details */ }, [TUNER_TCL_2002MB] = { /* TCL PAL */ .name = "TCL 2002MB", - .thresh1= 16 * 170.00 /*MHz*/, - .thresh2= 16 * 450.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 170.00 /*MHz*/, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0xce, }, [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0xce, }, [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ .name = "Philips FQ1236A MK4", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0xa0, - .VHF_H = 0x90, - .UHF = 0x30, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x90, }, + { 16 * 999.99 , 0x30, }, + }, .config = 0x8e, }, [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ .name = "Ymec TVision TVF-5533MF", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, @@ -643,20 +701,22 @@ static struct tunertype tuners[] = { [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ .name = "Thomson DTT 761X (ATSC/NTSC)", - .thresh1= 16 * 145.25 /*MHz*/, - .thresh2= 16 * 415.25 /*MHz*/, - .VHF_L = 0x39, - .VHF_H = 0x3a, - .UHF = 0x3c, + .count = 3, + .ranges = { + { 16 * 145.25 /*MHz*/, 0x39, }, + { 16 * 415.25 /*MHz*/, 0x3a, }, + { 16 * 999.99 , 0x3c, }, + }, .config = 0x8e, }, [TUNER_TENA_9533_DI] = { /* Philips PAL */ .name = "Tena TNF9533-D/IF/TNF9533-B/DF", - .thresh1= 16 * 160.25 /*MHz*/, - .thresh2= 16 * 464.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.25 /*MHz*/, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, [TUNER_TEA5767] = { /* Philips RADIO */ @@ -664,65 +724,72 @@ static struct tunertype tuners[] = { /* see tea5767.c for details */}, [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ .name = "Philips FMD1216ME MK3 Hybrid Tuner", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0x51, - .VHF_H = 0x52, - .UHF = 0x54, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x51, }, + { 16 * 442.00 /*MHz*/, 0x52, }, + { 16 * 999.99 , 0x54, }, + }, .config = 0x86, }, [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */ .name = "LG TDVS-H062F/TUA6034", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 455.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0x01 }, + { 16 * 455.00 /*MHz*/, 0x02 }, + { 16 * 999.99 , 0x04 }, + }, .config = 0x8e, }, [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ .name = "Ymec TVF66T5-B/DFF", - .thresh1= 16 * 160.25 /*MHz*/, - .thresh2= 16 * 464.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 160.25 /*MHz*/, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */ .name = "LG NTSC (TALN mini series)", - .thresh1= 16 * 137.25 /*MHz*/, - .thresh2= 16 * 373.25 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x08, + .count = 3, + .ranges = { + { 16 * 137.25 /*MHz*/, 0x01, }, + { 16 * 373.25 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x08, }, + }, .config = 0x8e, }, [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ .name = "Philips TD1316 Hybrid Tuner", - .thresh1= 16 * 160.00 /*MHz*/, - .thresh2= 16 * 442.00 /*MHz*/, - .VHF_L = 0xa1, - .VHF_H = 0xa2, - .UHF = 0xa4, + .count = 3, + .ranges = { + { 16 * 160.00 /*MHz*/, 0xa1, }, + { 16 * 442.00 /*MHz*/, 0xa2, }, + { 16 * 999.99 , 0xa4, }, + }, .config = 0xc8, }, [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ .name = "Philips TUV1236D ATSC/NTSC dual in", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0xce, }, [TUNER_TNF_5335MF] = { /* Philips NTSC */ .name = "Tena TNF 5335 MF", - .thresh1= 16 * 157.25 /*MHz*/, - .thresh2= 16 * 454.00 /*MHz*/, - .VHF_L = 0x01, - .VHF_H = 0x02, - .UHF = 0x04, + .count = 3, + .ranges = { + { 16 * 157.25 /*MHz*/, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x02, }, + { 16 * 999.99 , 0x04, }, + }, .config = 0x8e, }, }; @@ -776,20 +843,19 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) u16 div; struct tunertype *tun; unsigned char buffer[4]; - int rc, IFPCoff; + int rc, IFPCoff, i; tun = &tuners[t->type]; - if (freq < tun->thresh1) { - config = tun->VHF_L; - tuner_dbg("tv: VHF lowrange\n"); - } else if (freq < tun->thresh2) { - config = tun->VHF_H; - tuner_dbg("tv: VHF high range\n"); - } else { - config = tun->UHF; - tuner_dbg("tv: UHF range\n"); + for (i = 0; i < tun->count; i++) { + if (freq > tun->ranges[i].thresh) + continue; + break; } - + config = tun->ranges[i].cb; + /* i == 0 -> VHF_LO */ + /* i == 1 -> VHF_HI */ + /* i == 2 -> UHF */ + tuner_dbg("tv: range %d\n",i); /* tv norm specific stuff for multi-norm tuners */ switch (t->type) { -- cgit v1.2.3 From 12e66f6573beda52a434b757df5b7a5a05b9ebd2 Mon Sep 17 00:00:00 2001 From: "Ville Skytt\\ä" Date: Mon, 9 Jan 2006 15:25:38 -0200 Subject: V4L/DVB (3242): make the firmware dir docs consistent in the v4l-dvb tree. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - make the firmware dir documentation and comments consistent in the v4l-dvb tree. Signed-off-by: Ville Skyttä Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/dvb/avermedia.txt | 3 ++- Documentation/dvb/get_dvb_firmware | 6 +++++- Documentation/dvb/ttusb-dec.txt | 3 ++- drivers/media/dvb/frontends/Kconfig | 9 ++++++--- drivers/media/dvb/frontends/nxt2002.c | 3 ++- drivers/media/dvb/frontends/or51211.c | 3 ++- drivers/media/dvb/frontends/sp8870.c | 3 ++- drivers/media/dvb/frontends/sp887x.c | 3 ++- drivers/media/dvb/frontends/tda1004x.c | 3 ++- drivers/media/dvb/ttpci/Kconfig | 3 ++- drivers/media/dvb/ttpci/av7110.c | 6 +++--- drivers/media/dvb/ttusb-dec/Kconfig | 3 ++- 12 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt index 2dc260b2b0a4..068070ff13cd 100644 --- a/Documentation/dvb/avermedia.txt +++ b/Documentation/dvb/avermedia.txt @@ -150,7 +150,8 @@ Getting the card going The frontend module sp887x.o, requires an external firmware. Please use the command "get_dvb_firmware sp887x" to download - it. Then copy it to /usr/lib/hotplug/firmware. + it. Then copy it to /usr/lib/hotplug/firmware or /lib/firmware/ + (depending on configuration of firmware hotplug). Receiving DVB-T in Australia diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 08e96ff55720..4e5e6a979fe7 100644 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -34,7 +34,11 @@ for ($i=0; $i < scalar(@components); $i++) { if ($cid eq $components[$i]) { $outfile = eval($cid); die $@ if $@; - print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n"; + print STDERR </Documentation/dvb/get_dvb_firmware sp8870" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). config DVB_SP887X tristate "Spase sp887x based" @@ -75,7 +76,8 @@ config DVB_SP887X This driver needs external firmware. Please use the command "/Documentation/dvb/get_dvb_firmware sp887x" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). config DVB_CX22700 tristate "Conexant CX22700 based" @@ -105,7 +107,8 @@ config DVB_TDA1004X This driver needs external firmware. Please use the commands "/Documentation/dvb/get_dvb_firmware tda10045", "/Documentation/dvb/get_dvb_firmware tda10046" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware. + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). config DVB_NXT6000 tristate "NxtWave Communications NXT6000 based" diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c index 52c416043a62..4f263e65ba14 100644 --- a/drivers/media/dvb/frontends/nxt2002.c +++ b/drivers/media/dvb/frontends/nxt2002.c @@ -22,7 +22,8 @@ /* * This driver needs external firmware. Please use the command * "/Documentation/dvb/get_dvb_firmware nxt2002" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" #define CRC_CCIT_MASK 0x1021 diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 8d631ca7aaf0..7c3aed1f546b 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -25,7 +25,8 @@ /* * This driver needs external firmware. Please use the command * "/Documentation/dvb/get_dvb_firmware or51211" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index fc06cd6b46c3..73829e647e50 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -22,7 +22,8 @@ /* * This driver needs external firmware. Please use the command * "/Documentation/dvb/get_dvb_firmware alps_tdlb7" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index b3ae7dccc33c..eb8a602198ca 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -5,7 +5,8 @@ /* * This driver needs external firmware. Please use the command * "/Documentation/dvb/get_dvb_firmware sp887x" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw" diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 6c237fb2b82a..c63e9a5084eb 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -23,7 +23,8 @@ * This driver needs external firmware. Please use the commands * "/Documentation/dvb/get_dvb_firmware tda10045", * "/Documentation/dvb/get_dvb_firmware tda10046" to - * download/extract them, and then copy them to /usr/lib/hotplug/firmware. + * download/extract them, and then copy them to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw" diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index fa7e38944716..5b2aadb8385c 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -20,7 +20,8 @@ config DVB_AV7110 This driver needs an external firmware. Please use the script "/Documentation/dvb/get_dvb_firmware av7110" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). Say Y if you own such a card and want to use it. diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 0bef1edf0018..eabd4fcaf246 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1494,9 +1494,9 @@ static int get_firmware(struct av7110* av7110) if (ret == -ENOENT) { printk(KERN_ERR "dvb-ttpci: could not load firmware," " file not found: dvb-ttpci-01.fw\n"); - printk(KERN_ERR "dvb-ttpci: usually this should be in" - " /usr/lib/hotplug/firmware\n"); - printk(KERN_ERR "dvb-ttpci: and can be downloaded here" + printk(KERN_ERR "dvb-ttpci: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + printk(KERN_ERR "dvb-ttpci: and can be downloaded from" " http://www.linuxtv.org/download/dvb/firmware/\n"); } else printk(KERN_ERR "dvb-ttpci: cannot request firmware" diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig index e97244bd232e..83611012ef34 100644 --- a/drivers/media/dvb/ttusb-dec/Kconfig +++ b/drivers/media/dvb/ttusb-dec/Kconfig @@ -16,6 +16,7 @@ config DVB_TTUSB_DEC "/Documentation/dvb/get_dvb_firmware dec2000t", "/Documentation/dvb/get_dvb_firmware dec2540t", "/Documentation/dvb/get_dvb_firmware dec3000s", - download/extract them, and then copy them to /usr/lib/hotplug/firmware. + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). Say Y if you own such a device and want to use it. -- cgit v1.2.3 From 66e33dee9e3062b1045afe23c4b8714c1004668c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:39 -0200 Subject: V4L/DVB (3243): add firmware instructions for nxt2002 and nxt2004 - add firmware instructions for nxt2002 and nxt2004 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index afd6dfbd2842..db3a8b40031e 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -173,6 +173,11 @@ config DVB_NXT2002 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the command + "/Documentation/dvb/get_dvb_firmware nxt2002" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_NXT200X tristate "Nextwave NXT2002/NXT2004 based" depends on DVB_CORE @@ -181,6 +186,12 @@ config DVB_NXT200X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware nxt2002" and + "/Documentation/dvb/get_dvb_firmware nxt2004" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_OR51211 tristate "or51211 based (pcHDTV HD2000 card)" depends on DVB_CORE -- cgit v1.2.3 From a544521ef06ee7b8a3d82fa29627401196fda77a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:39 -0200 Subject: V4L/DVB (3245): Added some comments about multiple tuner support. - Added some comments to make clearer how to use ioctl api to handle multiple tuners at the same board. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/tuner.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/include/media/tuner.h b/include/media/tuner.h index aa91ce35915b..c5f034ecb002 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -150,10 +150,26 @@ enum tuner_mode { T_STANDBY = 1 << 31 }; +/* Older boards only had a single tuner device. Nowadays multiple tuner + devices may be present on a single board. Using TUNER_SET_TYPE_ADDR + to pass the tuner_setup structure it is possible to setup each tuner + device in turn. + + Since multiple devices may be present it is no longer sufficient to + send a command to a single i2c device. Instead you should broadcast + the command to all i2c devices. + + By setting the mode_mask correctly you can select which commands are + accepted by a specific tuner device. For example, set mode_mask to + T_RADIO if the device is a radio-only tuner. That specific tuner will + only accept commands when the tuner is in radio mode and ignore them + when the tuner is set to TV mode. + */ + struct tuner_setup { - unsigned short addr; - unsigned int type; - unsigned int mode_mask; + unsigned short addr; /* I2C address */ + unsigned int type; /* Tuner type */ + unsigned int mode_mask; /* Allowed tuner modes */ }; struct tuner { -- cgit v1.2.3 From 936053516aef6505ab3174c3443f3ba8749d4d98 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:39 -0200 Subject: V4L/DVB (3246): Use VIDIOC_S_AUDIO instead of AUDC_SET_INPUT in cs53l32a - Replace AUDC_SET_INPUT with VIDIOC_S_AUDIO. - Added V4L2_CID_AUDIO_MUTE. - Minimum volume is -96 dB, not -90. - Show volume in VIDIOC_LOG_STATUS. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs53l32a.c | 65 ++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index aa31b6736a7a..7d997aeda63e 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -74,50 +74,59 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg) static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, void *arg) { - int *input = arg; + struct v4l2_audio *input = arg; + struct v4l2_control *ctrl = arg; switch (cmd) { - case AUDC_SET_INPUT: - switch (*input) { - case AUDIO_TUNER: - cs53l32a_write(client, 0x01, 0x01); - break; - case AUDIO_EXTERN: - cs53l32a_write(client, 0x01, 0x21); - break; - case AUDIO_MUTE: - cs53l32a_write(client, 0x03, 0xF0); - break; - case AUDIO_UNMUTE: - cs53l32a_write(client, 0x03, 0x30); - break; - default: - cs53l32a_err("Invalid input %d.\n", *input); + case VIDIOC_S_AUDIO: + /* There are 2 physical inputs, but the second input can be + placed in two modes, the first mode bypasses the PGA (gain), + the second goes through the PGA. Hence there are three + possible inputs to choose from. */ + if (input->index > 2) { + cs53l32a_err("Invalid input %d.\n", input->index); return -EINVAL; } + cs53l32a_write(client, 0x01, 0x01 + (input->index << 4)); + break; + + case VIDIOC_G_AUDIO: + memset(input, 0, sizeof(*input)); + input->index = (cs53l32a_read(client, 0x01) >> 4) & 3; + break; + + case VIDIOC_G_CTRL: + if (ctrl->id == V4L2_CID_AUDIO_MUTE) { + ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0; + break; + } + if (ctrl->id != V4L2_CID_AUDIO_VOLUME) + return -EINVAL; + ctrl->value = (s8)cs53l32a_read(client, 0x04); break; case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - if (ctrl->id != V4L2_CID_AUDIO_VOLUME) - return -EINVAL; - if (ctrl->value > 12 || ctrl->value < -90) - return -EINVAL; - cs53l32a_write(client, 0x04, (u8) ctrl->value); - cs53l32a_write(client, 0x05, (u8) ctrl->value); + if (ctrl->id == V4L2_CID_AUDIO_MUTE) { + cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30); break; } + if (ctrl->id != V4L2_CID_AUDIO_VOLUME) + return -EINVAL; + if (ctrl->value > 12 || ctrl->value < -96) + return -EINVAL; + cs53l32a_write(client, 0x04, (u8) ctrl->value); + cs53l32a_write(client, 0x05, (u8) ctrl->value); + break; case VIDIOC_LOG_STATUS: { u8 v = cs53l32a_read(client, 0x01); u8 m = cs53l32a_read(client, 0x03); + s8 vol = cs53l32a_read(client, 0x04); - cs53l32a_info("Input: %s%s\n", - v == 0x21 ? "external line in" : "tuner", + cs53l32a_info("Input: %d%s\n", (v >> 4) & 3, (m & 0xC0) ? " (muted)" : ""); + cs53l32a_info("Volume: %d dB\n", vol); break; } -- cgit v1.2.3 From fbc46e74fa437f16a3ffe4a5561a97f41680a124 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:40 -0200 Subject: V4L/DVB (3247): Replace AUDC_SET_INPUT with VIDIOC_S_AUDIO in wm8775. - Replace AUDC_SET_INPUT with VIDIOC_S_AUDIO. - Added V4L2_CID_AUDIO_MUTE. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/wm8775.c | 59 +++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 1933cd25b610..a1b6a427ab74 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -87,38 +87,53 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct wm8775_state *state = i2c_get_clientdata(client); - int *input = arg; + struct v4l2_audio *input = arg; + struct v4l2_control *ctrl = arg; switch (cmd) { - case AUDC_SET_INPUT: + case VIDIOC_S_AUDIO: + /* There are 4 inputs and one output. Zero or more inputs + are multiplexed together to the output. Hence there are + 16 combinations. + If only one input is active (the normal case) then the + input values 1, 2, 4 or 8 should be used. */ + if (input->index > 15) { + wm8775_err("Invalid input %d.\n", input->index); + return -EINVAL; + } + state->input = input->index; + if (state->muted) + break; wm8775_write(client, R21, 0x0c0); wm8775_write(client, R14, 0x1d4); wm8775_write(client, R15, 0x1d4); + wm8775_write(client, R21, 0x100 + state->input); + break; - if (*input == AUDIO_RADIO) { - wm8775_write(client, R21, 0x108); - state->input = 8; - state->muted = 0; - break; - } - if (*input == AUDIO_MUTE) { - state->muted = 1; - break; - } - if (*input == AUDIO_UNMUTE) { + case VIDIOC_G_AUDIO: + memset(input, 0, sizeof(*input)); + input->index = state->input; + break; + + case VIDIOC_G_CTRL: + if (ctrl->id != V4L2_CID_AUDIO_MUTE) + return -EINVAL; + ctrl->value = state->muted; + break; + + case VIDIOC_S_CTRL: + if (ctrl->id != V4L2_CID_AUDIO_MUTE) + return -EINVAL; + state->muted = ctrl->value; + wm8775_write(client, R21, 0x0c0); + wm8775_write(client, R14, 0x1d4); + wm8775_write(client, R15, 0x1d4); + if (!state->muted) wm8775_write(client, R21, 0x100 + state->input); - state->muted = 0; - break; - } - /* All other inputs... */ - wm8775_write(client, R21, 0x102); - state->input = 2; - state->muted = 0; break; case VIDIOC_LOG_STATUS: - wm8775_info("Input: %s%s\n", - state->input == 8 ? "radio" : "default", + wm8775_info("Input: %d%s\n", state->input, state->muted ? " (muted)" : ""); break; -- cgit v1.2.3 From 21fa715e67fe57e404d7f5f39b7f18016db9e4b6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:41 -0200 Subject: V4L/DVB (3248): Add selected input to saa7115 VIDIOC_LOG_STATUS output. - Add selected input to VIDIOC_LOG_STATUS output. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 685ca1780c66..b175389d9f43 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -801,6 +801,11 @@ static void saa7115_log_status(struct i2c_client *client) signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80; vcr = !(reg1f & 0x10); + if (state->input >= 6) { + saa7115_info("Input: S-Video %d\n", state->input - 6); + } else { + saa7115_info("Input: Composite %d\n", state->input); + } saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); -- cgit v1.2.3 From 3578d3dd0b1e468a44a76a83efe90476a854625d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:41 -0200 Subject: V4L/DVB (3214): Calculate the saa7115 AMCLK regs instead of using fixed values - Calculate the audio master clock registers from the actual frequencies. This simplifies the code and it also prepares for adding CGC2 support. - VIDIOC_INT_AUDIO_CLOCK_FREQ now receives an u32 instead of an enum. It is more generic and actually easier to implement. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 20 ++-- drivers/media/video/cx25840/cx25840-core.c | 10 +- drivers/media/video/cx25840/cx25840.h | 2 +- drivers/media/video/saa7115.c | 155 +++++++--------------------- include/media/v4l2-common.h | 15 +-- 5 files changed, 55 insertions(+), 147 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 740908f8027d..6c44bd9c1704 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -23,11 +23,13 @@ #include "cx25840.h" -inline static int set_audclk_freq(struct i2c_client *client, - enum v4l2_audio_clock_freq freq) +static int set_audclk_freq(struct i2c_client *client, u32 freq) { struct cx25840_state *state = i2c_get_clientdata(client); + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + /* assert soft reset */ cx25840_and_or(client, 0x810, ~0x1, 0x01); @@ -38,7 +40,7 @@ inline static int set_audclk_freq(struct i2c_client *client, switch (state->audio_input) { case AUDIO_TUNER: switch (freq) { - case V4L2_AUDCLK_32_KHZ: + case 32000: /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x0f040610); @@ -51,7 +53,7 @@ inline static int set_audclk_freq(struct i2c_client *client, cx25840_write4(client, 0x90c, 0x7ff70108); break; - case V4L2_AUDCLK_441_KHZ: + case 44100: /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x0f040910); @@ -64,7 +66,7 @@ inline static int set_audclk_freq(struct i2c_client *client, cx25840_write4(client, 0x90c, 0x596d0108); break; - case V4L2_AUDCLK_48_KHZ: + case 48000: /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x0f040a10); @@ -84,7 +86,7 @@ inline static int set_audclk_freq(struct i2c_client *client, case AUDIO_INTERN: case AUDIO_RADIO: switch (freq) { - case V4L2_AUDCLK_32_KHZ: + case 32000: /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x0f04081e); @@ -103,7 +105,7 @@ inline static int set_audclk_freq(struct i2c_client *client, cx25840_write(client, 0x127, 0x54); break; - case V4L2_AUDCLK_441_KHZ: + case 44100: /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x0f040918); @@ -119,7 +121,7 @@ inline static int set_audclk_freq(struct i2c_client *client, cx25840_write4(client, 0x90c, 0x85730108); break; - case V4L2_AUDCLK_48_KHZ: + case 48000: /* VID_PLL and AUX_PLL */ cx25840_write4(client, 0x108, 0x0f040a18); @@ -317,7 +319,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) case AUDC_SET_INPUT: return set_input(client, *(int *)arg); case VIDIOC_INT_AUDIO_CLOCK_FREQ: - return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg); + return set_audclk_freq(client, *(u32 *)arg); case VIDIOC_G_CTRL: switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 54ffae686dc9..c2c1e856aa60 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -802,7 +802,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_set_clientdata(client, state); memset(state, 0, sizeof(struct cx25840_state)); state->input = CX25840_TUNER; - state->audclk_freq = V4L2_AUDCLK_48_KHZ; + state->audclk_freq = 48000; state->audio_input = AUDIO_TUNER; state->cardtype = CARDTYPE_PVR150; @@ -1008,13 +1008,7 @@ static void log_status(struct i2c_client *client) cx25840_info("Specified audio input: %s\n", state->audio_input == 0 ? "Tuner" : "External"); - switch (state->audclk_freq) { - case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break; - case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break; - case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break; - default: p = "undefined"; - } - cx25840_info("Specified audioclock freq: %s\n", p); + cx25840_info("Specified audioclock freq: %d Hz\n", state->audclk_freq); switch (pref_mode & 0xf) { case 0: p = "mono/language A"; break; diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index 40aa59f9c525..4731a19092a6 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -65,7 +65,7 @@ struct cx25840_state { enum cx25840_cardtype cardtype; enum cx25840_input input; int audio_input; - enum v4l2_audio_clock_freq audclk_freq; + u32 audclk_freq; }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index b175389d9f43..3e4e5584c5d0 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -39,6 +39,7 @@ #include #include #include +#include MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); @@ -78,7 +79,7 @@ struct saa7115_state { int hue; int sat; enum v4l2_chip_ident ident; - enum v4l2_audio_clock_freq audclk_freq; + u32 audclk_freq; }; /* ----------------------------------------------------------------------- */ @@ -469,80 +470,6 @@ static const unsigned char saa7115_init_misc[] = { 0x00, 0x00 }; -/* ============== SAA7715 AUDIO settings ============= */ - -/* 48.0 kHz */ -static const unsigned char saa7115_cfg_48_audio[] = { - 0x34, 0xce, - 0x35, 0xfb, - 0x36, 0x30, - 0x00, 0x00 -}; - -/* 44.1 kHz */ -static const unsigned char saa7115_cfg_441_audio[] = { - 0x34, 0xf2, - 0x35, 0x00, - 0x36, 0x2d, - 0x00, 0x00 -}; - -/* 32.0 kHz */ -static const unsigned char saa7115_cfg_32_audio[] = { - 0x34, 0xdf, - 0x35, 0xa7, - 0x36, 0x20, - 0x00, 0x00 -}; - -/* 48.0 kHz 60hz */ -static const unsigned char saa7115_cfg_60hz_48_audio[] = { - 0x30, 0xcd, - 0x31, 0x20, - 0x32, 0x03, - 0x00, 0x00 -}; - -/* 48.0 kHz 50hz */ -static const unsigned char saa7115_cfg_50hz_48_audio[] = { - 0x30, 0x00, - 0x31, 0xc0, - 0x32, 0x03, - 0x00, 0x00 -}; - -/* 44.1 kHz 60hz */ -static const unsigned char saa7115_cfg_60hz_441_audio[] = { - 0x30, 0xbc, - 0x31, 0xdf, - 0x32, 0x02, - 0x00, 0x00 -}; - -/* 44.1 kHz 50hz */ -static const unsigned char saa7115_cfg_50hz_441_audio[] = { - 0x30, 0x00, - 0x31, 0x72, - 0x32, 0x03, - 0x00, 0x00 -}; - -/* 32.0 kHz 60hz */ -static const unsigned char saa7115_cfg_60hz_32_audio[] = { - 0x30, 0xde, - 0x31, 0x15, - 0x32, 0x02, - 0x00, 0x00 -}; - -/* 32.0 kHz 50hz */ -static const unsigned char saa7115_cfg_50hz_32_audio[] = { - 0x30, 0x00, - 0x31, 0x80, - 0x32, 0x02, - 0x00, 0x00 -}; - static int saa7115_odd_parity(u8 c) { c ^= (c >> 4); @@ -627,40 +554,38 @@ static int saa7115_decode_wss(u8 * p) } -static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq) +static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) { struct saa7115_state *state = i2c_get_clientdata(client); + u32 acpf; + u32 acni; + u32 hz; + u64 f; saa7115_dbg("set audio clock freq: %d\n", freq); - switch (freq) { - case V4L2_AUDCLK_32_KHZ: - saa7115_writeregs(client, saa7115_cfg_32_audio); - if (state->std & V4L2_STD_525_60) { - saa7115_writeregs(client, saa7115_cfg_60hz_32_audio); - } else { - saa7115_writeregs(client, saa7115_cfg_50hz_32_audio); - } - break; - case V4L2_AUDCLK_441_KHZ: - saa7115_writeregs(client, saa7115_cfg_441_audio); - if (state->std & V4L2_STD_525_60) { - saa7115_writeregs(client, saa7115_cfg_60hz_441_audio); - } else { - saa7115_writeregs(client, saa7115_cfg_50hz_441_audio); - } - break; - case V4L2_AUDCLK_48_KHZ: - saa7115_writeregs(client, saa7115_cfg_48_audio); - if (state->std & V4L2_STD_525_60) { - saa7115_writeregs(client, saa7115_cfg_60hz_48_audio); - } else { - saa7115_writeregs(client, saa7115_cfg_50hz_48_audio); - } - break; - default: - saa7115_dbg("invalid audio setting %d\n", freq); - return -EINVAL; - } + + /* sanity check */ + if (freq < 32000 || freq > 48000) + return -EINVAL; + + /* hz is the refresh rate times 100 */ + hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; + /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ + acpf = (25600 * freq) / hz; + /* acni = (256 * freq * 2^23) / crystal_frequency = + (freq * 2^(8+23)) / crystal_frequency = + (freq << 31) / 32.11 MHz */ + f = freq; + f = f << 31; + do_div(f, 32110000); + acni = f; + + saa7115_write(client, 0x30, acpf & 0xff); + saa7115_write(client, 0x31, (acpf >> 8) & 0xff); + saa7115_write(client, 0x32, (acpf >> 16) & 0x03); + saa7115_write(client, 0x34, acni & 0xff); + saa7115_write(client, 0x35, (acni >> 8) & 0xff); + saa7115_write(client, 0x36, (acni >> 16) & 0x3f); state->audclk_freq = freq; return 0; } @@ -773,24 +698,17 @@ static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client) static void saa7115_log_status(struct i2c_client *client) { struct saa7115_state *state = i2c_get_clientdata(client); - char *audfreq = "undefined"; int reg1e, reg1f; int signalOk; int vcr; - switch (state->audclk_freq) { - case V4L2_AUDCLK_32_KHZ: audfreq = "32 kHz"; break; - case V4L2_AUDCLK_441_KHZ: audfreq = "44.1 kHz"; break; - case V4L2_AUDCLK_48_KHZ: audfreq = "48 kHz"; break; - } - - saa7115_info("Audio frequency: %s\n", audfreq); + saa7115_info("Audio frequency: %d Hz\n", state->audclk_freq); if (client->name[6] == '4') { /* status for the saa7114 */ reg1f = saa7115_read(client, 0x1f); signalOk = (reg1f & 0xc1) == 0x81; saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad"); - saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); + saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); return; } @@ -807,7 +725,7 @@ static void saa7115_log_status(struct i2c_client *client) saa7115_info("Input: Composite %d\n", state->input); } saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); - saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); + saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); switch (reg1e & 0x03) { case 1: @@ -1108,7 +1026,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg); case VIDIOC_INT_AUDIO_CLOCK_FREQ: - return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg); + return saa7115_set_audio_clock_freq(client, *(u32 *)arg); case VIDIOC_G_TUNER: { @@ -1307,7 +1225,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) state->hue = 0; state->sat = 64; state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; - state->audclk_freq = V4L2_AUDCLK_48_KHZ; + state->audclk_freq = 48000; saa7115_dbg("writing init values\n"); @@ -1317,8 +1235,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); saa7115_writeregs(client, saa7115_cfg_60hz_video); - saa7115_writeregs(client, saa7115_cfg_48_audio); - saa7115_writeregs(client, saa7115_cfg_60hz_48_audio); + saa7115_set_audio_clock_freq(client, state->audclk_freq); saa7115_writeregs(client, saa7115_cfg_reset_scaler); i2c_attach_client(client); diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 2f2402996409..90248d29ed0a 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -26,13 +26,6 @@ #ifndef V4L2_COMMON_H_ #define V4L2_COMMON_H_ -/* VIDIOC_INT_AUDIO_CLOCK_FREQ */ -enum v4l2_audio_clock_freq { - V4L2_AUDCLK_32_KHZ = 32000, - V4L2_AUDCLK_441_KHZ = 44100, - V4L2_AUDCLK_48_KHZ = 48000, -}; - /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */ struct v4l2_register { u32 i2c_id; /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */ @@ -77,10 +70,12 @@ enum v4l2_chip_ident { /* Reset the I2C chip */ #define VIDIOC_INT_RESET _IO ('d', 102) -/* Set the frequency of the audio clock output. +/* Set the frequency (in Hz) of the audio clock output. Used to slave an audio processor to the video decoder, ensuring that audio - and video remain synchronized. */ -#define VIDIOC_INT_AUDIO_CLOCK_FREQ _IOR ('d', 103, enum v4l2_audio_clock_freq) + and video remain synchronized. + Usual values for the frequency are 48000, 44100 or 32000 Hz. + If the frequency is not supported, then -EINVAL is returned. */ +#define VIDIOC_INT_AUDIO_CLOCK_FREQ _IOW ('d', 103, u32) /* Video decoders that support sliced VBI need to implement this ioctl. Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI -- cgit v1.2.3 From a8bbf12ad8a8ad532cea0b67f0127ad90d336b04 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:42 -0200 Subject: V4L/DVB (3249): Generalized cx25840 video/audio input handling - Added VIDIOC_S_AUDIO to set the audio inputs separately. - Removed AUDC_SET_INPUT. - Made the video inputs much more general. - Removed cardtype CID and replaced with a CID to enable the PVR150 workaround. The cardtype is no longer necessary with the general video input change. - Update VIDIOC_LOG_STATUS output to show the video and audio inputs separately. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 51 +++----- drivers/media/video/cx25840/cx25840-core.c | 180 ++++++++++++++-------------- drivers/media/video/cx25840/cx25840.h | 63 +++++++--- 3 files changed, 153 insertions(+), 141 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 6c44bd9c1704..fe6bc411d71f 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -37,8 +37,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ cx25840_write(client, 0x127, 0x50); - switch (state->audio_input) { - case AUDIO_TUNER: + if (state->aud_input != CX25840_AUDIO_SERIAL) { switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ @@ -79,12 +78,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) cx25840_write4(client, 0x90c, 0xaa4f0108); break; } - break; - - case AUDIO_EXTERN_1: - case AUDIO_EXTERN_2: - case AUDIO_INTERN: - case AUDIO_RADIO: + } else { switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ @@ -137,7 +131,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) cx25840_write4(client, 0x90c, 0x55550108); break; } - break; } /* deassert soft reset */ @@ -148,48 +141,33 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) return 0; } -static int set_input(struct i2c_client *client, int audio_input) +void cx25840_audio_set_path(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); - cx25840_dbg("set audio input (%d)\n", audio_input); - /* stop microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0); /* Mute everything to prevent the PFFT! */ cx25840_write(client, 0x8d3, 0x1f); - switch (audio_input) { - case AUDIO_TUNER: - /* Set Path1 to Analog Demod Main Channel */ - cx25840_write4(client, 0x8d0, 0x7038061f); - - /* When the microcontroller detects the - * audio format, it will unmute the lines */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - break; - - case AUDIO_EXTERN_1: - case AUDIO_EXTERN_2: - case AUDIO_INTERN: - case AUDIO_RADIO: + if (state->aud_input == CX25840_AUDIO_SERIAL) { /* Set Path1 to Serial Audio Input */ cx25840_write4(client, 0x8d0, 0x12100101); /* The microcontroller should not be started for the * non-tuner inputs: autodetection is specific for * TV audio. */ - break; + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx25840_write4(client, 0x8d0, 0x7038061f); - default: - cx25840_dbg("Invalid audio input selection %d\n", audio_input); - return -EINVAL; + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); } - state->audio_input = audio_input; - - return set_audclk_freq(client, state->audclk_freq); + set_audclk_freq(client, state->audclk_freq); } inline static int get_volume(struct i2c_client *client) @@ -292,7 +270,7 @@ inline static void set_mute(struct i2c_client *client, int mute) { struct cx25840_state *state = i2c_get_clientdata(client); - if (state->audio_input == AUDIO_TUNER) { + if (state->aud_input != CX25840_AUDIO_SERIAL) { /* Must turn off microcontroller in order to mute sound. * Not sure if this is the best method, but it does work. * If the microcontroller is running, then it will undo any @@ -316,10 +294,9 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_control *ctrl = arg; switch (cmd) { - case AUDC_SET_INPUT: - return set_input(client, *(int *)arg); case VIDIOC_INT_AUDIO_CLOCK_FREQ: return set_audclk_freq(client, *(u32 *)arg); + case VIDIOC_G_CTRL: switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: @@ -341,6 +318,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) return -EINVAL; } break; + case VIDIOC_S_CTRL: switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: @@ -362,6 +340,7 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) return -EINVAL; } break; + default: return -EINVAL; } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index c2c1e856aa60..a897d6b7d708 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -115,8 +115,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask, /* ----------------------------------------------------------------------- */ -static int set_input(struct i2c_client *, enum cx25840_input); -static void input_change(struct i2c_client *); +static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input); static void log_status(struct i2c_client *client); /* ----------------------------------------------------------------------- */ @@ -195,10 +195,8 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw) /* AC97 shift */ cx25840_write(client, 0x8cf, 0x0f); - /* (re)set video input */ - set_input(client, state->input); - /* (re)set audio input */ - cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input); + /* (re)set input */ + set_input(client, state->vid_input, state->aud_input); /* start microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0x10); @@ -223,7 +221,7 @@ static void input_change(struct i2c_client *client) cx25840_write(client, 0x80b, 0x10); } else if (std & V4L2_STD_NTSC) { /* NTSC */ - if (state->cardtype == CARDTYPE_PVR150_WORKAROUND) { + if (state->pvr150_workaround) { /* Certain Hauppauge PVR150 models have a hardware bug that causes audio to drop out. For these models the audio standard must be set explicitly. @@ -259,72 +257,68 @@ static void input_change(struct i2c_client *client) } } -static int set_input(struct i2c_client *client, enum cx25840_input input) +static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input) { struct cx25840_state *state = i2c_get_clientdata(client); + u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8); + u8 reg; - cx25840_dbg("decoder set input (%d)\n", input); + cx25840_dbg("decoder set video input %d, audio input %d\n", + vid_input, aud_input); - switch (input) { - case CX25840_TUNER: - cx25840_dbg("now setting Tuner input\n"); - - if (state->cardtype == CARDTYPE_PVR150 || - state->cardtype == CARDTYPE_PVR150_WORKAROUND) { - /* CH_SEL_ADC2=1 */ - cx25840_and_or(client, 0x102, ~0x2, 0x02); - } - - /* Video Input Control */ - if (state->cardtype == CARDTYPE_PG600) { - cx25840_write(client, 0x103, 0x11); - } else { - cx25840_write(client, 0x103, 0x46); - } - - /* INPUT_MODE=0 */ - cx25840_and_or(client, 0x401, ~0x6, 0x00); - break; - - case CX25840_COMPOSITE0: - case CX25840_COMPOSITE1: - cx25840_dbg("now setting Composite input\n"); + if (is_composite) { + reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); + } else { + int luma = vid_input & 0xf0; + int chroma = vid_input & 0xf00; - /* Video Input Control */ - if (state->cardtype == CARDTYPE_PG600) { - cx25840_write(client, 0x103, 0x00); - } else { - cx25840_write(client, 0x103, 0x02); + if ((vid_input & ~0xff0) || + luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || + chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { + cx25840_err("0x%04x is not a valid video input!\n", vid_input); + return -EINVAL; } - - /* INPUT_MODE=0 */ - cx25840_and_or(client, 0x401, ~0x6, 0x00); - break; - - case CX25840_SVIDEO0: - case CX25840_SVIDEO1: - cx25840_dbg("now setting S-Video input\n"); - - /* CH_SEL_ADC2=0 */ - cx25840_and_or(client, 0x102, ~0x2, 0x00); - - /* Video Input Control */ - if (state->cardtype == CARDTYPE_PG600) { - cx25840_write(client, 0x103, 0x02); + reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); + if (chroma >= CX25840_SVIDEO_CHROMA7) { + reg &= 0x3f; + reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; } else { - cx25840_write(client, 0x103, 0x10); + reg &= 0xcf; + reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; } + } - /* INPUT_MODE=1 */ - cx25840_and_or(client, 0x401, ~0x6, 0x02); + switch (aud_input) { + case CX25840_AUDIO_SERIAL: + /* do nothing, use serial audio input */ break; + case CX25840_AUDIO4: reg &= ~0x30; break; + case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX25840_AUDIO7: reg &= ~0xc0; break; + case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; default: - cx25840_err("%d is not a valid input!\n", input); + cx25840_err("0x%04x is not a valid audio input!\n", aud_input); return -EINVAL; } - state->input = input; + cx25840_write(client, 0x103, reg); + /* Set INPUT_MODE to Composite (0) or S-Video (1) */ + cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx25840_and_or(client, 0x102, ~0x4, 4); + else + cx25840_and_or(client, 0x102, ~0x4, 0); + + state->vid_input = vid_input; + state->aud_input = aud_input; + cx25840_audio_set_path(client); input_change(client); return 0; } @@ -395,18 +389,9 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) struct cx25840_state *state = i2c_get_clientdata(client); switch (ctrl->id) { - case CX25840_CID_CARDTYPE: - switch (ctrl->value) { - case CARDTYPE_PVR150: - case CARDTYPE_PVR150_WORKAROUND: - case CARDTYPE_PG600: - state->cardtype = ctrl->value; - break; - default: - return -ERANGE; - } - - set_input(client, state->input); + case CX25840_CID_ENABLE_PVR150_WORKAROUND: + state->pvr150_workaround = ctrl->value; + set_input(client, state->vid_input, state->aud_input); break; case V4L2_CID_BRIGHTNESS: @@ -465,8 +450,8 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) struct cx25840_state *state = i2c_get_clientdata(client); switch (ctrl->id) { - case CX25840_CID_CARDTYPE: - ctrl->value = state->cardtype; + case CX25840_CID_ENABLE_PVR150_WORKAROUND: + ctrl->value = state->pvr150_workaround; break; case V4L2_CID_BRIGHTNESS: ctrl->value = cx25840_read(client, 0x414) + 128; @@ -615,7 +600,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, return cx25840_vbi(client, cmd, arg); case VIDIOC_INT_AUDIO_CLOCK_FREQ: - case AUDC_SET_INPUT: result = cx25840_audio(client, cmd, arg); break; @@ -652,13 +636,30 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_G_INPUT: - *(int *)arg = state->input; + *(int *)arg = state->vid_input; break; case VIDIOC_S_INPUT: - result = set_input(client, *(int *)arg); + result = set_input(client, *(enum cx25840_video_input *)arg, state->aud_input); break; + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *input = arg; + + result = set_input(client, state->vid_input, input->index); + break; + } + + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *input = arg; + + memset(input, 0, sizeof(*input)); + input->index = state->aud_input; + break; + } + case VIDIOC_S_FREQUENCY: input_change(client); break; @@ -801,10 +802,10 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_set_clientdata(client, state); memset(state, 0, sizeof(struct cx25840_state)); - state->input = CX25840_TUNER; + state->vid_input = CX25840_COMPOSITE7; + state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; - state->audio_input = AUDIO_TUNER; - state->cardtype = CARDTYPE_PVR150; + state->pvr150_workaround = 0; cx25840_initialize(client, 1); @@ -888,6 +889,8 @@ static void log_status(struct i2c_client *client) u8 pref_mode = cx25840_read(client, 0x809); u8 afc0 = cx25840_read(client, 0x80b); u8 mute_ctl = cx25840_read(client, 0x8d3); + int vid_input = state->vid_input; + int aud_input = state->aud_input; char *p; cx25840_info("Video signal: %spresent\n", @@ -997,16 +1000,19 @@ static void log_status(struct i2c_client *client) cx25840_info("Specified standard: %s\n", vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); - switch (state->input) { - case CX25840_COMPOSITE0: p = "Composite 0"; break; - case CX25840_COMPOSITE1: p = "Composite 1"; break; - case CX25840_SVIDEO0: p = "S-Video 0"; break; - case CX25840_SVIDEO1: p = "S-Video 1"; break; - case CX25840_TUNER: p = "Tuner"; break; + if (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8) { + cx25840_info("Specified video input: Composite %d\n", + vid_input - CX25840_COMPOSITE1 + 1); + } else { + cx25840_info("Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + if (aud_input) { + cx25840_info("Specified audio input: Tuner (In%d)\n", aud_input); + } else { + cx25840_info("Specified audio input: External\n"); } - cx25840_info("Specified input: %s\n", p); - cx25840_info("Specified audio input: %s\n", - state->audio_input == 0 ? "Tuner" : "External"); cx25840_info("Specified audioclock freq: %d Hz\n", state->audclk_freq); diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index 4731a19092a6..3dc67e79c856 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -39,32 +39,58 @@ extern int cx25840_debug; printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0) - -/* The CARDTYPE_PVR150_WORKAROUND cardtype activates a workaround for a - hardware bug that is present in PVR150 (and possible PVR500) cards that - have certain NTSC tuners (tveeprom model numbers 85, 99 and 112). The +/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is + present in Hauppauge PVR-150 (and possibly PVR-500) cards that have + certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The audio autodetect fails on some channels for these models and the workaround is to select the audio standard explicitly. Many thanks to Hauppauge for providing this information. */ -enum cx25840_cardtype { - CARDTYPE_PVR150, - CARDTYPE_PG600, - CARDTYPE_PVR150_WORKAROUND, +#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) + +enum cx25840_video_input { + /* Composite video inputs In1-In8 */ + CX25840_COMPOSITE1 = 1, + CX25840_COMPOSITE2, + CX25840_COMPOSITE3, + CX25840_COMPOSITE4, + CX25840_COMPOSITE5, + CX25840_COMPOSITE6, + CX25840_COMPOSITE7, + CX25840_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX25840_SVIDEO_LUMA1 = 0x10, + CX25840_SVIDEO_LUMA2 = 0x20, + CX25840_SVIDEO_LUMA3 = 0x30, + CX25840_SVIDEO_LUMA4 = 0x40, + CX25840_SVIDEO_CHROMA4 = 0x400, + CX25840_SVIDEO_CHROMA5 = 0x500, + CX25840_SVIDEO_CHROMA6 = 0x600, + CX25840_SVIDEO_CHROMA7 = 0x700, + CX25840_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX25840_SVIDEO1 = 0x510, + CX25840_SVIDEO2 = 0x620, + CX25840_SVIDEO3 = 0x730, + CX25840_SVIDEO4 = 0x840, }; -enum cx25840_input { - CX25840_TUNER, - CX25840_COMPOSITE0, - CX25840_COMPOSITE1, - CX25840_SVIDEO0, - CX25840_SVIDEO1 +enum cx25840_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX25840_AUDIO_SERIAL, + CX25840_AUDIO4 = 4, + CX25840_AUDIO5, + CX25840_AUDIO6, + CX25840_AUDIO7, + CX25840_AUDIO8, }; struct cx25840_state { - enum cx25840_cardtype cardtype; - enum cx25840_input input; - int audio_input; + int pvr150_workaround; + enum cx25840_video_input vid_input; + enum cx25840_audio_input aud_input; u32 audclk_freq; }; @@ -84,6 +110,7 @@ int cx25840_loadfw(struct i2c_client *client); /* ----------------------------------------------------------------------- */ /* cx25850-audio.c */ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg); +void cx25840_audio_set_path(struct i2c_client *client); /* ----------------------------------------------------------------------- */ /* cx25850-vbi.c */ -- cgit v1.2.3 From f9a91f08990b0353fc1251ee72ec42c6ea33bd24 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:42 -0200 Subject: V4L/DVB (3250): tea5767: move signal strength level to the 0-65535 range - Move signal strength level to the 0-65535 range as per V4L2 spec. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tea5767.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index a9375ef05de1..4647db66ba68 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -264,7 +264,7 @@ static int tea5767_signal(struct i2c_client *c) if (5 != (rc = i2c_master_recv(c, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4)); + return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); } static int tea5767_stereo(struct i2c_client *c) -- cgit v1.2.3 From 8a854284d09dd3b3d8660762b43546058da5372f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:43 -0200 Subject: V4L/DVB (3253): Add V4L2 commands to tvaudio - debug messages changed to be like the other modules - Add V4L2 commands VIDIOC_S_TUNER, VIDIOC_G_TUNER, VIDIOC_S_STD and VIDIOC_S_FREQUENCY. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvaudio.c | 107 +++++++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 19625e6410d1..2bdbb39bff0f 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -46,16 +46,18 @@ MODULE_LICENSE("GPL"); #define UNSET (-1U) -#define tvaudio_info(fmt, arg...) do {\ - printk(KERN_INFO "tvaudio %d-%04x: " fmt, \ - chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) -#define tvaudio_warn(fmt, arg...) do {\ - printk(KERN_WARNING "tvaudio %d-%04x: " fmt, \ - chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) -#define tvaudio_dbg(fmt, arg...) do {\ - if (debug) \ - printk(KERN_INFO "tvaudio %d-%04x: " fmt, \ - chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) +#define tvaudio_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, chip->c.driver->name, \ + i2c_adapter_id(chip->c.adapter), chip->c.addr , ## arg); } while (0) +#define tvaudio_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, chip->c.driver->name, \ + i2c_adapter_id(chip->c.adapter), chip->c.addr , ## arg); } while (0) +#define tvaudio_dbg(fmt, arg...) \ + do { \ + if (debug) \ + printk(KERN_INFO "%s debug %d-%04x: " fmt, chip->c.driver->name, \ + i2c_adapter_id(chip->c.adapter), chip->c.addr , ## arg); \ + } while (0) /* ---------------------------------------------------------------------- */ /* our structs */ @@ -131,7 +133,7 @@ struct CHIPSTATE { /* current settings */ __u16 left,right,treble,bass,mode; int prevmode; - int norm; + int radio; /* thread */ pid_t tpid; @@ -142,8 +144,6 @@ struct CHIPSTATE { int watch_stereo; }; -#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ - /* ---------------------------------------------------------------------- */ /* i2c addresses */ @@ -301,7 +301,7 @@ static int chip_thread(void *data) tvaudio_dbg("%s: thread wakeup\n", chip->c.name); /* don't do anything for radio or if mode != auto */ - if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0) + if (chip->radio || chip->mode != 0) continue; /* have a look what's going on */ @@ -1608,7 +1608,7 @@ static int chip_command(struct i2c_client *client, break; case AUDC_SET_RADIO: - chip->norm = VIDEO_MODE_RADIO; + chip->radio = 1; chip->watch_stereo = 0; /* del_timer(&chip->wt); */ break; @@ -1634,7 +1634,7 @@ static int chip_command(struct i2c_client *client, va->bass = chip->bass; va->treble = chip->treble; } - if (chip->norm != VIDEO_MODE_RADIO) { + if (!chip->radio) { if (desc->getmode) va->mode = desc->getmode(chip); else @@ -1669,15 +1669,80 @@ static int chip_command(struct i2c_client *client, } break; } - case VIDIOCSCHAN: + + case VIDIOC_S_TUNER: { - struct video_channel *vc = arg; + struct v4l2_tuner *vt = arg; + int mode = 0; - chip->norm = vc->norm; + switch (vt->audmode) { + case V4L2_TUNER_MODE_MONO: + mode = VIDEO_SOUND_MONO; + break; + case V4L2_TUNER_MODE_STEREO: + mode = VIDEO_SOUND_STEREO; + break; + case V4L2_TUNER_MODE_LANG1: + mode = VIDEO_SOUND_LANG1; + break; + case V4L2_TUNER_MODE_LANG2: + mode = VIDEO_SOUND_LANG2; + break; + default: + break; + } + + if (desc->setmode && mode) { + chip->watch_stereo = 0; + /* del_timer(&chip->wt); */ + chip->mode = mode; + desc->setmode(chip, mode); + } break; } - case VIDIOCSFREQ: + + case VIDIOC_G_TUNER: { + struct v4l2_tuner *vt = arg; + int mode = VIDEO_SOUND_MONO; + + vt->audmode = 0; + vt->rxsubchans = 0; + vt->capability = V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + if (chip->radio) + break; + + if (desc->getmode) + mode = desc->getmode(chip); + + if (mode & VIDEO_SOUND_MONO) + vt->rxsubchans |= V4L2_TUNER_SUB_MONO; + if (mode & VIDEO_SOUND_STEREO) + vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; + if (mode & VIDEO_SOUND_LANG1) + vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + mode = chip->mode; + if (mode & VIDEO_SOUND_MONO) + vt->audmode = V4L2_TUNER_MODE_MONO; + if (mode & VIDEO_SOUND_STEREO) + vt->audmode = V4L2_TUNER_MODE_STEREO; + if (mode & VIDEO_SOUND_LANG1) + vt->audmode = V4L2_TUNER_MODE_LANG1; + if (mode & VIDEO_SOUND_LANG2) + vt->audmode = V4L2_TUNER_MODE_LANG2; + break; + } + + case VIDIOCSCHAN: + case VIDIOC_S_STD: + chip->radio = 0; + break; + + case VIDIOCSFREQ: + case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ if (desc->checkmode) { desc->setmode(chip,VIDEO_SOUND_MONO); @@ -1686,7 +1751,7 @@ static int chip_command(struct i2c_client *client, mod_timer(&chip->wt, jiffies+2*HZ); /* the thread will call checkmode() later */ } - } + break; } return 0; } -- cgit v1.2.3 From 30b54d50f6e2b8f5a4c8b5ade3d25a02612f8f51 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:43 -0200 Subject: V4L/DVB (3254): Don't reprogram the video standard if it is unchanged. - Don't reprogram the video standard if the new standard equals the old standard. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 3e4e5584c5d0..5d33d0922e79 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -668,6 +668,16 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) struct saa7115_state *state = i2c_get_clientdata(client); int taskb = saa7115_read(client, 0x80) & 0x10; + /* Prevent unnecessary standard changes. During a standard + change the I-Port is temporarily disabled. Any devices + reading from that port can get confused. + Note that VIDIOC_S_STD is also used to switch from + radio to TV mode, so if a VIDIOC_S_STD is broadcast to + all I2C devices then you do not want to have an unwanted + side-effect here. */ + if (std == state->std) + return; + // This works for NTSC-M, SECAM-L and the 50Hz PAL variants. if (std & V4L2_STD_525_60) { saa7115_dbg("decoder set standard 60 Hz\n"); -- cgit v1.2.3 From d3900bc42e6bc5e461c29951cc2a50df09e08771 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:44 -0200 Subject: V4L/DVB (3255): When in radio mode don't do anything with VIDIOC_G_TUNER. - When in radio mode don't do anything with VIDIOC_G_TUNER. Allow other devices to fill this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvaudio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 2bdbb39bff0f..ed6a843dd34a 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1706,12 +1706,12 @@ static int chip_command(struct i2c_client *client, struct v4l2_tuner *vt = arg; int mode = VIDEO_SOUND_MONO; + if (chip->radio) + break; vt->audmode = 0; vt->rxsubchans = 0; vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - if (chip->radio) - break; if (desc->getmode) mode = desc->getmode(chip); -- cgit v1.2.3 From 3faeeae48348959c58f3121d2a6a4fb0bc626da0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:44 -0200 Subject: V4L/DVB (3256): When in radio mode ignore VIDIOC_G_TUNER - Detect when AUDC_SET_RADIO is called. - When in radio mode ignore VIDIOC_G_TUNER. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 40 ++++++++++++++---------------- drivers/media/video/cx25840/cx25840.h | 1 + drivers/media/video/saa7115.c | 12 +++++++++ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index a897d6b7d708..07607264bd41 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -440,6 +440,9 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_MUTE: return cx25840_audio(client, VIDIOC_S_CTRL, ctrl); + + default: + return -EINVAL; } return 0; @@ -564,12 +567,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, { struct cx25840_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; - int result = 0; switch (cmd) { - case 0: - break; - #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the * cx25840 registers for testing */ @@ -600,8 +599,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, return cx25840_vbi(client, cmd, arg); case VIDIOC_INT_AUDIO_CLOCK_FREQ: - result = cx25840_audio(client, cmd, arg); - break; + return cx25840_audio(client, cmd, arg); case VIDIOC_STREAMON: cx25840_dbg("enable output\n"); @@ -620,19 +618,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_G_CTRL: - result = get_v4lctrl(client, (struct v4l2_control *)arg); - break; + return get_v4lctrl(client, (struct v4l2_control *)arg); case VIDIOC_S_CTRL: - result = set_v4lctrl(client, (struct v4l2_control *)arg); - break; + return set_v4lctrl(client, (struct v4l2_control *)arg); case VIDIOC_G_STD: *(v4l2_std_id *)arg = cx25840_get_v4lstd(client); break; case VIDIOC_S_STD: - result = set_v4lstd(client, *(v4l2_std_id *)arg); + state->radio = 0; + return set_v4lstd(client, *(v4l2_std_id *)arg); + + case AUDC_SET_RADIO: + state->radio = 1; break; case VIDIOC_G_INPUT: @@ -640,15 +640,13 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_S_INPUT: - result = set_input(client, *(enum cx25840_video_input *)arg, state->aud_input); - break; + return set_input(client, *(enum cx25840_video_input *)arg, state->aud_input); case VIDIOC_S_AUDIO: { struct v4l2_audio *input = arg; - result = set_input(client, state->vid_input, input->index); - break; + return set_input(client, state->vid_input, input->index); } case VIDIOC_G_AUDIO: @@ -671,6 +669,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, u8 vpres = cx25840_read(client, 0x80a) & 0x10; int val = 0; + if (state->radio) + break; + vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; @@ -725,12 +726,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_G_FMT: - result = get_v4lfmt(client, (struct v4l2_format *)arg); - break; + return get_v4lfmt(client, (struct v4l2_format *)arg); case VIDIOC_S_FMT: - result = set_v4lfmt(client, (struct v4l2_format *)arg); - break; + return set_v4lfmt(client, (struct v4l2_format *)arg); case VIDIOC_INT_RESET: cx25840_initialize(client, 0); @@ -742,11 +741,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, break; default: - cx25840_err("invalid ioctl %x\n", cmd); return -EINVAL; } - return result; + return 0; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index 3dc67e79c856..dc58d4292a34 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -89,6 +89,7 @@ enum cx25840_audio_input { struct cx25840_state { int pvr150_workaround; + int radio; enum cx25840_video_input vid_input; enum cx25840_audio_input aud_input; u32 audclk_freq; diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 5d33d0922e79..9f550fd741d1 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -74,6 +74,7 @@ struct saa7115_state { v4l2_std_id std; int input; int enable; + int radio; int bright; int contrast; int hue; @@ -634,6 +635,9 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c state->hue = ctrl->value; saa7115_write(client, 0x0d, state->hue); break; + + default: + return -EINVAL; } return 0; @@ -1043,6 +1047,8 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar struct v4l2_tuner *vt = arg; int status; + if (state->radio) + break; status = saa7115_read(client, 0x1f); saa7115_dbg("status: 0x%02x\n", status); @@ -1065,9 +1071,14 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar break; case VIDIOC_S_STD: + state->radio = 0; saa7115_set_v4lstd(client, *(v4l2_std_id *)arg); break; + case AUDC_SET_RADIO: + state->radio = 1; + break; + case VIDIOC_G_INPUT: *(int *)arg = state->input; break; @@ -1230,6 +1241,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) state->std = V4L2_STD_NTSC; state->input = -1; state->enable = 1; + state->radio = 0; state->bright = 128; state->contrast = 64; state->hue = 0; -- cgit v1.2.3 From c7f3612cdb515c5062135831184c8d577723df25 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:45 -0200 Subject: V4L/DVB (3257): Add missing audiochip.h include. - Add missing audiochip.h include. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 9f550fd741d1..cf530b94cd12 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -39,6 +39,7 @@ #include #include #include +#include #include MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); -- cgit v1.2.3 From 6ce17c57f84731d288107ce29ce468311edd87f4 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 9 Jan 2006 15:25:45 -0200 Subject: V4L/DVB (3260): Using new firmware for the WideView Stick - A new firmware fixes VHF tuning issues. This changes the firmware file name in the driver. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtt200u.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 54c436996512..130ea7f21f5e 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = { .pid_filter_count = 15, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-01.fw", + .firmware = "dvb-usb-wt220u-02.fw", .power_ctrl = dtt200u_power_ctrl, .streaming_ctrl = dtt200u_streaming_ctrl, -- cgit v1.2.3 From af36c82c97ff68e03837ed47991de0494007612b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:25:46 -0200 Subject: V4L/DVB (3261): msp3400.c cleanup (almost all cosmetic) - Step 1 of the msp3400.c cleanup. Most changes are all cosmetic (moved code around, renamed functions and variables). New additions: - VIDIOC_LOG_STATUS for debugging. - More user friendly messages on driver load. - 'simple' renamed to 'autodetect' - 'simpler' renamed to 'autoselect' Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400.c | 1406 +++++++++++++++++++++-------------------- 1 file changed, 709 insertions(+), 697 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 11235c1ac5c6..39058d3b2e61 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -59,21 +59,60 @@ /* ---------------------------------------------------------------------- */ -#define I2C_MSP3400C 0x80 -#define I2C_MSP3400C_ALT 0x88 +MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); -#define I2C_MSP3400C_DEM 0x10 -#define I2C_MSP3400C_DFP 0x12 +#define OPMODE_AUTO -1 +#define OPMODE_MANUAL 0 +#define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ +#define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ -/* Addresses to scan */ -static unsigned short normal_i2c[] = { - I2C_MSP3400C >> 1, - I2C_MSP3400C_ALT >> 1, - I2C_CLIENT_END -}; -I2C_CLIENT_INSMOD; +/* module parameters */ +static int opmode = OPMODE_AUTO; +static int debug = 0; /* debug output */ +static int once = 0; /* no continous stereo monitoring */ +static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), + the autoscan seems work well only with FM... */ +static int standard = 1; /* Override auto detect of audio standard, if needed. */ +static int dolby = 0; + +static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual + (msp34xxg only) 0x00a0-0x03c0 */ -#define msp3400_dbg(fmt, arg...) \ +/* read-only */ +module_param(opmode, int, 0444); + +/* read-write */ +module_param(once, int, 0644); +module_param(debug, int, 0644); +module_param(stereo_threshold, int, 0644); +module_param(standard, int, 0644); +module_param(amsound, int, 0644); +module_param(dolby, int, 0644); + +MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); +MODULE_PARM_DESC(once, "No continuous stereo monitoring"); +MODULE_PARM_DESC(debug, "Enable debug messages"); +MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); +MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); +MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); +MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); + +/* ---------------------------------------------------------------------- */ + +#define msp3400_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) +#define msp3400_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) +#define msp3400_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) + +/* level 1 debug. */ +#define msp_dbg1(fmt, arg...) \ do { \ if (debug) \ printk(KERN_INFO "%s debug %d-%04x: " fmt, \ @@ -81,8 +120,8 @@ I2C_CLIENT_INSMOD; i2c_adapter_id(client->adapter), client->addr , ## arg); \ } while (0) -/* Medium volume debug. */ -#define msp3400_dbg_mediumvol(fmt, arg...) \ +/* level 2 debug. */ +#define msp_dbg2(fmt, arg...) \ do { \ if (debug >= 2) \ printk(KERN_INFO "%s debug %d-%04x: " fmt, \ @@ -90,8 +129,8 @@ I2C_CLIENT_INSMOD; i2c_adapter_id(client->adapter), client->addr , ## arg); \ } while (0) -/* High volume debug. Use with care. */ -#define msp3400_dbg_highvol(fmt, arg...) \ +/* level 3 debug. Use with care. */ +#define msp_dbg3(fmt, arg...) \ do { \ if (debug >= 16) \ printk(KERN_INFO "%s debug %d-%04x: " fmt, \ @@ -99,45 +138,33 @@ I2C_CLIENT_INSMOD; i2c_adapter_id(client->adapter), client->addr , ## arg); \ } while (0) -#define msp3400_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define msp3400_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define msp3400_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) +/* control subaddress */ +#define I2C_MSP_CONTROL 0x00 +/* demodulator unit subaddress */ +#define I2C_MSP_DEM 0x10 +/* DSP unit subaddress */ +#define I2C_MSP_DSP 0x12 + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; +>>>>>>> remote -#define OPMODE_AUTO -1 -#define OPMODE_MANUAL 0 -#define OPMODE_SIMPLE 1 /* use short programming (>= msp3410 only) */ -#define OPMODE_SIMPLER 2 /* use shorter programming (>= msp34xxG) */ -/* insmod parameters */ -static int opmode = OPMODE_AUTO; -static int debug = 0; /* debug output */ -static int once = 0; /* no continous stereo monitoring */ -static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), - the autoscan seems work well only with FM... */ -static int standard = 1; /* Override auto detect of audio standard, if needed. */ -static int dolby = 0; +I2C_CLIENT_INSMOD; -static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual - (msp34xxg only) 0x00a0-0x03c0 */ #define DFP_COUNT 0x41 static const int bl_dfp[] = { 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10 }; -#define IS_MSP34XX_G(msp) ((msp)->opmode==2) +#define HAVE_NICAM(state) (((state->rev2>>8) & 0xff) != 00) +#define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') -struct msp3400c { - int rev1,rev2; +struct msp_state { + int rev1, rev2; int opmode; - int nicam; int mode; int norm; int stereo; @@ -167,49 +194,19 @@ struct msp3400c { int watch_stereo:1; }; -#define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00) -#define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@') -#define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@') -#define HAVE_RADIO(msp) ((msp->rev1 & 0xff) >= 'G'-'@') - #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ -/* ---------------------------------------------------------------------- */ - -/* read-only */ -module_param(opmode, int, 0444); - -/* read-write */ -module_param(once, int, 0644); -module_param(debug, int, 0644); -module_param(stereo_threshold, int, 0644); -module_param(standard, int, 0644); -module_param(amsound, int, 0644); -module_param(dolby, int, 0644); - -MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler"); -MODULE_PARM_DESC(once, "No continuous stereo monitoring"); -MODULE_PARM_DESC(debug, "Enable debug messages"); -MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); -MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); -MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); -MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); - - -MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); /* ----------------------------------------------------------------------- */ /* functions for talking to the MSP3400C Sound processor */ -static int msp3400c_reset(struct i2c_client *client) +static int msp_reset(struct i2c_client *client) { /* reset and read revision code */ - static char reset_off[3] = { 0x00, 0x80, 0x00 }; - static char reset_on[3] = { 0x00, 0x00, 0x00 }; - static char write[3] = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e }; - char read[2]; + static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; + static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; + static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; + u8 read[2]; struct i2c_msg reset[2] = { { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, @@ -219,54 +216,62 @@ static int msp3400c_reset(struct i2c_client *client) { client->addr, I2C_M_RD, 2, read }, }; - msp3400_dbg_highvol("msp3400c_reset\n"); - if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) || - (1 != i2c_transfer(client->adapter,&reset[1],1)) || - (2 != i2c_transfer(client->adapter,test,2)) ) { - msp3400_err("chip reset failed\n"); + msp_dbg3("msp_reset\n"); + if (1 != i2c_transfer(client->adapter, &reset[0], 1) || + 1 != i2c_transfer(client->adapter, &reset[1], 1) || + 2 != i2c_transfer(client->adapter, test, 2)) { + msp_err("chip reset failed\n"); return -1; } return 0; } -static int msp3400c_read(struct i2c_client *client, int dev, int addr) +static int msp_read(struct i2c_client *client, int dev, int addr) { - int err,retval; - - unsigned char write[3]; - unsigned char read[2]; + int err, retval; + u8 write[3]; + u8 read[2]; struct i2c_msg msgs[2] = { { client->addr, 0, 3, write }, { client->addr, I2C_M_RD, 2, read } }; - write[0] = dev+1; + write[0] = dev + 1; write[1] = addr >> 8; write[2] = addr & 0xff; - for (err = 0; err < 3;) { - if (2 == i2c_transfer(client->adapter,msgs,2)) + for (err = 0; err < 3; err++) { + if (2 == i2c_transfer(client->adapter, msgs, 2)) break; - err++; - msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, + msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(msecs_to_jiffies(10)); } if (3 == err) { - msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(client); + msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); + msp_dbg3("msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); return retval; } -static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val) +static inline int msp_read_dem(struct i2c_client *client, int addr) +{ + return msp_read(client, I2C_MSP_DEM, addr); +} + +static inline int msp_read_dsp(struct i2c_client *client, int addr) +{ + return msp_read(client, I2C_MSP_DSP, addr); +} + +static int msp_write(struct i2c_client *client, int dev, int addr, int val) { int err; - unsigned char buffer[5]; + u8 buffer[5]; buffer[0] = dev; buffer[1] = addr >> 8; @@ -274,29 +279,38 @@ static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); - for (err = 0; err < 3;) { + msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); + for (err = 0; err < 3; err++) { if (5 == i2c_master_send(client, buffer, 5)) break; - err++; - msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, + msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(msecs_to_jiffies(10)); } if (3 == err) { - msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(client); + msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + msp_reset(client); return -1; } return 0; } +static inline int msp_write_dem(struct i2c_client *client, int addr, int val) +{ + return msp_write(client, I2C_MSP_DEM, addr, val); +} + +static inline int msp_write_dsp(struct i2c_client *client, int addr, int val) +{ + return msp_write(client, I2C_MSP_DSP, addr, val); +} + /* ------------------------------------------------------------------------ */ /* This macro is allowed for *constants* only, gcc must calculate it at compile time. Remember -- no floats in kernel mode */ -#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) +#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) #define MSP_MODE_AM_DETECT 0 #define MSP_MODE_FM_RADIO 2 @@ -433,41 +447,41 @@ static char *scart_names[] = { "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" }; -static void msp3400c_set_scart(struct i2c_client *client, int in, int out) +static void msp_set_scart(struct i2c_client *client, int in, int out) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); - msp->in_scart=in; + state->in_scart=in; if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { if (-1 == scarts[out][in]) return; - msp->acb &= ~scarts[out][SCART_MASK]; - msp->acb |= scarts[out][in]; + state->acb &= ~scarts[out][SCART_MASK]; + state->acb |= scarts[out][in]; } else - msp->acb = 0xf60; /* Mute Input and SCART 1 Output */ + state->acb = 0xf60; /* Mute Input and SCART 1 Output */ - msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, msp->acb); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb); + msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", + scart_names[in], out, state->acb); + msp_write_dsp(client, 0x13, state->acb); /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode); + msp_write_dem(client, 0x40, state->i2s_mode); } /* ------------------------------------------------------------------------ */ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) { - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + msp_write_dem(client, 0x0093, cdo1 & 0xfff); + msp_write_dem(client, 0x009b, cdo1 >> 12); + msp_write_dem(client, 0x00a3, cdo2 & 0xfff); + msp_write_dem(client, 0x00ab, cdo2 >> 12); + msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ } -static void msp3400c_setvolume(struct i2c_client *client, +static void msp_set_volume(struct i2c_client *client, int muted, int left, int right) { int vol = 0, val = 0, balance = 0; @@ -480,91 +494,91 @@ static void msp3400c_setvolume(struct i2c_client *client, balance = ((right - left) * 127) / vol; } - msp3400_dbg("setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n", + msp_dbg1("setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n", muted ? "on" : "off", left, right, val >> 8, balance); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, + msp_write_dsp(client, 0x0000, val); /* loudspeaker */ + msp_write_dsp(client, 0x0006, val); /* headphones */ + msp_write_dsp(client, 0x0007, muted ? 0x1 : (val | 0x1)); - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8); + msp_write_dsp(client, 0x0001, balance << 8); } -static void msp3400c_setbass(struct i2c_client *client, int bass) +static void msp_set_bass(struct i2c_client *client, int bass) { int val = ((bass-32768) * 0x60 / 65535) << 8; - msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ + msp_dbg1("setbass: %d 0x%02x\n", bass, val >> 8); + msp_write_dsp(client, 0x0002, val); /* loudspeaker */ } -static void msp3400c_settreble(struct i2c_client *client, int treble) +static void msp_set_treble(struct i2c_client *client, int treble) { int val = ((treble-32768) * 0x60 / 65535) << 8; - msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ + msp_dbg1("settreble: %d 0x%02x\n",treble, val>>8); + msp_write_dsp(client, 0x0003, val); /* loudspeaker */ } static void msp3400c_setmode(struct i2c_client *client, int type) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int i; - msp3400_dbg("setmode: %d\n",type); - msp->mode = type; - msp->audmode = V4L2_TUNER_MODE_MONO; - msp->rxsubchans = V4L2_TUNER_SUB_MONO; + msp_dbg1("setmode: %d\n",type); + state->mode = type; + state->audmode = V4L2_TUNER_MODE_MONO; + state->rxsubchans = V4L2_TUNER_SUB_MONO; - msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ + msp_write_dem(client, 0x00bb, /* ad_cv */ msp_init_data[type].ad_cv); for (i = 5; i >= 0; i--) /* fir 1 */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, + msp_write_dem(client, 0x0001, msp_init_data[type].fir1[i]); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); + msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ + msp_write_dem(client, 0x0005, 0x0040); + msp_write_dem(client, 0x0005, 0x0000); for (i = 5; i >= 0; i--) - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, + msp_write_dem(client, 0x0005, msp_init_data[type].fir2[i]); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ + msp_write_dem(client, 0x0083, /* MODE_REG */ msp_init_data[type].mode_reg); msp3400c_setcarrier(client, msp_init_data[type].cdo1, msp_init_data[type].cdo2); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ if (dolby) { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, + msp_write_dsp(client, 0x000b, msp_init_data[type].dfp_src); } else { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + msp_write_dsp(client, 0x0008, msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + msp_write_dsp(client, 0x0009, msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, + msp_write_dsp(client, 0x000b, msp_init_data[type].dfp_src); } - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, + msp_write_dsp(client, 0x000a, msp_init_data[type].dfp_src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, + msp_write_dsp(client, 0x000e, msp_init_data[type].dfp_matrix); - if (HAVE_NICAM(msp)) { + if (HAVE_NICAM(state)) { /* nicam prescale */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */ + msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ } } /* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */ -static int best_video_sound(int rxsubchans) +static int msp3400c_best_video_sound(int rxsubchans) { if (rxsubchans & V4L2_TUNER_SUB_STEREO) return V4L2_TUNER_MODE_STEREO; @@ -581,38 +595,37 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) static char *strmode[] = { "0", "mono", "stereo", "3", "lang1", "5", "6", "7", "lang2" }; - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int nicam = 0; /* channel source: FM/AM or nicam */ int src = 0; - if (IS_MSP34XX_G(msp)) { + if (state->opmode == OPMODE_AUTOSELECT) { /* this method would break everything, let's make sure * it's never called */ - msp3400_dbg - ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n", + msp_dbg1("setstereo called with mode=%d instead of set_source (ignored)\n", mode); return; } /* switch demodulator */ - switch (msp->mode) { + switch (state->mode) { case MSP_MODE_FM_TERRA: - msp3400_dbg("FM setstereo: %s\n", strmode[mode]); - msp3400c_setcarrier(client,msp->second,msp->main); + msp_dbg1("FM setstereo: %s\n", strmode[mode]); + msp3400c_setcarrier(client,state->second,state->main); switch (mode) { case V4L2_TUNER_MODE_STEREO: - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); + msp_write_dsp(client, 0x000e, 0x3001); break; case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: case V4L2_TUNER_MODE_LANG2: - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); + msp_write_dsp(client, 0x000e, 0x3000); break; } break; case MSP_MODE_FM_SAT: - msp3400_dbg("SAT setstereo: %s\n", strmode[mode]); + msp_dbg1("SAT setstereo: %s\n", strmode[mode]); switch (mode) { case V4L2_TUNER_MODE_MONO: msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); @@ -631,38 +644,38 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]); - msp3400c_setcarrier(client,msp->second,msp->main); - if (msp->nicam_on) + msp_dbg1("NICAM setstereo: %s\n",strmode[mode]); + msp3400c_setcarrier(client,state->second,state->main); + if (state->nicam_on) nicam=0x0100; break; case MSP_MODE_BTSC: - msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]); + msp_dbg1("BTSC setstereo: %s\n",strmode[mode]); nicam=0x0300; break; case MSP_MODE_EXTERN: - msp3400_dbg("extern setstereo: %s\n",strmode[mode]); + msp_dbg1("extern setstereo: %s\n",strmode[mode]); nicam = 0x0200; break; case MSP_MODE_FM_RADIO: - msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]); + msp_dbg1("FM-Radio setstereo: %s\n",strmode[mode]); break; default: - msp3400_dbg("mono setstereo\n"); + msp_dbg1("mono setstereo\n"); return; } /* switch audio */ - switch (best_video_sound(mode)) { + switch (msp3400c_best_video_sound(mode)) { case V4L2_TUNER_MODE_STEREO: src = 0x0020 | nicam; break; case V4L2_TUNER_MODE_MONO: - if (msp->mode == MSP_MODE_AM_NICAM) { - msp3400_dbg("switching to AM mono\n"); + if (state->mode == MSP_MODE_AM_NICAM) { + msp_dbg1("switching to AM mono\n"); /* AM mono decoding is handled by tuner, not MSP chip */ /* SCART switching control register */ - msp3400c_set_scart(client,SCART_MONO,0); + msp_set_scart(client,SCART_MONO,0); src = 0x0200; break; } @@ -673,67 +686,67 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) src = 0x0010 | nicam; break; } - msp3400_dbg("setstereo final source/matrix = 0x%x\n", src); + msp_dbg1("setstereo final source/matrix = 0x%x\n", src); if (dolby) { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); + msp_write_dsp(client, 0x0008,0x0520); + msp_write_dsp(client, 0x0009,0x0620); + msp_write_dsp(client, 0x000a,src); + msp_write_dsp(client, 0x000b,src); } else { - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); + msp_write_dsp(client, 0x0008,src); + msp_write_dsp(client, 0x0009,src); + msp_write_dsp(client, 0x000a,src); + msp_write_dsp(client, 0x000b,src); } } static void msp3400c_print_mode(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); - if (msp->main == msp->second) { - msp3400_dbg("mono sound carrier: %d.%03d MHz\n", - msp->main/910000,(msp->main/910)%1000); + if (state->main == state->second) { + msp_dbg1("mono sound carrier: %d.%03d MHz\n", + state->main/910000,(state->main/910)%1000); } else { - msp3400_dbg("main sound carrier: %d.%03d MHz\n", - msp->main/910000,(msp->main/910)%1000); + msp_dbg1("main sound carrier: %d.%03d MHz\n", + state->main/910000,(state->main/910)%1000); } - if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2) - msp3400_dbg("NICAM/FM carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - if (msp->mode == MSP_MODE_AM_NICAM) - msp3400_dbg("NICAM/AM carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); - if (msp->mode == MSP_MODE_FM_TERRA && - msp->main != msp->second) { - msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n", - msp->second/910000,(msp->second/910)%1000); + if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) + msp_dbg1("NICAM/FM carrier : %d.%03d MHz\n", + state->second/910000,(state->second/910)%1000); + if (state->mode == MSP_MODE_AM_NICAM) + msp_dbg1("NICAM/AM carrier : %d.%03d MHz\n", + state->second/910000,(state->second/910)%1000); + if (state->mode == MSP_MODE_FM_TERRA && + state->main != state->second) { + msp_dbg1("FM-stereo carrier : %d.%03d MHz\n", + state->second/910000,(state->second/910)%1000); } } static void msp3400c_restore_dfp(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int i; for (i = 0; i < DFP_COUNT; i++) { - if (-1 == msp->dfp_regs[i]) + if (-1 == state->dfp_regs[i]) continue; - msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]); + msp_write_dsp(client, i, state->dfp_regs[i]); } } /* if the dfp_regs is set, set what's in there. Otherwise, set the default value */ -static int msp3400c_write_dfp_with_default(struct i2c_client *client, +static int msp_write_dfp_with_default(struct i2c_client *client, int addr, int default_value) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int value = default_value; - if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr]) - value = msp->dfp_regs[addr]; - return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value); + if (addr < DFP_COUNT && -1 != state->dfp_regs[addr]) + value = state->dfp_regs[addr]; + return msp_write_dsp(client, addr, value); } /* ----------------------------------------------------------------------- */ @@ -753,18 +766,18 @@ struct REGISTER_DUMP d1[] = { static int autodetect_stereo(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int val; - int rxsubchans = msp->rxsubchans; - int newnicam = msp->nicam_on; + int rxsubchans = state->rxsubchans; + int newnicam = state->nicam_on; int update = 0; - switch (msp->mode) { + switch (state->mode) { case MSP_MODE_FM_TERRA: - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); + val = msp_read_dsp(client, 0x18); if (val > 32767) val -= 65536; - msp3400_dbg("stereo detect register: %d\n",val); + msp_dbg2("stereo detect register: %d\n",val); if (val > 4096) { rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; } else if (val < -4096) { @@ -777,8 +790,8 @@ static int autodetect_stereo(struct i2c_client *client) case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); - msp3400_dbg("nicam sync=%d, mode=%d\n", + val = msp_read_dem(client, 0x23); + msp_dbg2("nicam sync=%d, mode=%d\n", val & 1, (val & 0x1e) >> 1); if (val & 1) { @@ -810,8 +823,8 @@ static int autodetect_stereo(struct i2c_client *client) } break; case MSP_MODE_BTSC: - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); - msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n", + val = msp_read_dem(client, 0x200); + msp_dbg2("status=0x%x (pri=%s, sec=%s, %s%s%s)\n", val, (val & 0x0002) ? "no" : "yes", (val & 0x0004) ? "no" : "yes", @@ -823,17 +836,17 @@ static int autodetect_stereo(struct i2c_client *client) if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; break; } - if (rxsubchans != msp->rxsubchans) { + if (rxsubchans != state->rxsubchans) { update = 1; - msp3400_dbg("watch: rxsubchans %d => %d\n", - msp->rxsubchans,rxsubchans); - msp->rxsubchans = rxsubchans; + msp_dbg1("watch: rxsubchans %d => %d\n", + state->rxsubchans,rxsubchans); + state->rxsubchans = rxsubchans; } - if (newnicam != msp->nicam_on) { + if (newnicam != state->nicam_on) { update = 1; - msp3400_dbg("watch: nicam %d => %d\n", - msp->nicam_on,newnicam); - msp->nicam_on = newnicam; + msp_dbg1("watch: nicam %d => %d\n", + state->nicam_on,newnicam); + state->nicam_on = newnicam; } return update; } @@ -843,11 +856,11 @@ static int autodetect_stereo(struct i2c_client *client) * in the ioctl while doing the sound carrier & stereo detect */ -static int msp34xx_sleep(struct msp3400c *msp, int timeout) +static int msp_sleep(struct msp_state *state, int timeout) { DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&msp->wq, &wait); + add_wait_queue(&state->wq, &wait); if (!kthread_should_stop()) { if (timeout < 0) { set_current_state(TASK_INTERRUPTIBLE); @@ -858,90 +871,90 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) } } - remove_wait_queue(&msp->wq, &wait); + remove_wait_queue(&state->wq, &wait); try_to_freeze(); - return msp->restart; + return state->restart; } /* stereo/multilang monitoring */ static void watch_stereo(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); if (autodetect_stereo(client)) { - if (msp->stereo & V4L2_TUNER_MODE_STEREO) + if (state->stereo & V4L2_TUNER_MODE_STEREO) msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO); - else if (msp->stereo & VIDEO_SOUND_LANG1) + else if (state->stereo & VIDEO_SOUND_LANG1) msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1); else msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); } if (once) - msp->watch_stereo = 0; + state->watch_stereo = 0; } static int msp3400c_thread(void *data) { struct i2c_client *client = data; - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; - msp3400_info("msp3400 daemon started\n"); + msp_info("msp3400 daemon started\n"); for (;;) { - msp3400_dbg_mediumvol("msp3400 thread: sleep\n"); - msp34xx_sleep(msp,-1); - msp3400_dbg_mediumvol("msp3400 thread: wakeup\n"); + msp_dbg2("msp3400 thread: sleep\n"); + msp_sleep(state, -1); + msp_dbg2("msp3400 thread: wakeup\n"); restart: - msp3400_dbg("thread: restart scan\n"); - msp->restart = 0; + msp_dbg1("thread: restart scan\n"); + state->restart = 0; if (kthread_should_stop()) break; - if (VIDEO_MODE_RADIO == msp->norm || - MSP_MODE_EXTERN == msp->mode) { + if (VIDEO_MODE_RADIO == state->norm || + MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ - msp3400_info("thread: no carrier scan\n"); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_info("thread: no carrier scan\n"); + msp_set_volume(client, state->muted, state->left, state->right); continue; } /* mute */ - msp3400c_setvolume(client, msp->muted, 0, 0); + msp_set_volume(client, state->muted, 0, 0); msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; - msp->watch_stereo = 0; + state->watch_stereo = 0; /* some time for the tuner to sync */ - if (msp34xx_sleep(msp,200)) + if (msp_sleep(state,200)) goto restart; /* carrier detect pass #1 -- main carrier */ cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); - if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { + if (amsound && (state->norm == VIDEO_MODE_SECAM)) { /* autodetect doesn't work well with AM ... */ max1 = 3; count = 0; - msp3400_dbg("AM sound override\n"); + msp_dbg1("AM sound override\n"); } for (this = 0; this < count; this++) { msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - if (msp34xx_sleep(msp,100)) + if (msp_sleep(state,100)) goto restart; - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val1 < val) val1 = val, max1 = this; - msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name); + msp_dbg1("carrier1 val: %5d / %s\n", val,cd[this].name); } /* carrier detect pass #2 -- second (stereo) carrier */ @@ -962,7 +975,7 @@ static int msp3400c_thread(void *data) break; } - if (amsound && (msp->norm == VIDEO_MODE_SECAM)) { + if (amsound && (state->norm == VIDEO_MODE_SECAM)) { /* autodetect doesn't work well with AM ... */ cd = NULL; count = 0; @@ -970,72 +983,72 @@ static int msp3400c_thread(void *data) } for (this = 0; this < count; this++) { msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - if (msp34xx_sleep(msp,100)) + if (msp_sleep(state,100)) goto restart; - val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val2 < val) val2 = val, max2 = this; - msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name); + msp_dbg1("carrier2 val: %5d / %s\n", val,cd[this].name); } - /* programm the msp3400 according to the results */ - msp->main = carrier_detect_main[max1].cdo; + /* program the msp3400 according to the results */ + state->main = carrier_detect_main[max1].cdo; switch (max1) { case 1: /* 5.5 */ if (max2 == 0) { /* B/G FM-stereo */ - msp->second = carrier_detect_55[max2].cdo; + state->second = carrier_detect_55[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; + state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - msp->watch_stereo = 1; - } else if (max2 == 1 && HAVE_NICAM(msp)) { + state->watch_stereo = 1; + } else if (max2 == 1 && HAVE_NICAM(state)) { /* B/G NICAM */ - msp->second = carrier_detect_55[max2].cdo; + state->second = carrier_detect_55[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; + state->nicam_on = 1; + msp3400c_setcarrier(client, state->second, state->main); + state->watch_stereo = 1; } else { goto no_second; } break; case 2: /* 6.0 */ /* PAL I NICAM */ - msp->second = MSP_CARRIER(6.552); + state->second = MSP_CARRIER(6.552); msp3400c_setmode(client, MSP_MODE_FM_NICAM2); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; + state->nicam_on = 1; + msp3400c_setcarrier(client, state->second, state->main); + state->watch_stereo = 1; break; case 3: /* 6.5 */ if (max2 == 1 || max2 == 2) { /* D/K FM-stereo */ - msp->second = carrier_detect_65[max2].cdo; + state->second = carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; + state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - msp->watch_stereo = 1; + state->watch_stereo = 1; } else if (max2 == 0 && - msp->norm == VIDEO_MODE_SECAM) { + state->norm == VIDEO_MODE_SECAM) { /* L NICAM or AM-mono */ - msp->second = carrier_detect_65[max2].cdo; + state->second = carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_AM_NICAM); - msp->nicam_on = 0; + state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - msp3400c_setcarrier(client, msp->second, msp->main); + msp3400c_setcarrier(client, state->second, state->main); /* volume prescale for SCART (AM mono input) */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900); - msp->watch_stereo = 1; - } else if (max2 == 0 && HAVE_NICAM(msp)) { + msp_write_dsp(client, 0x000d, 0x1900); + state->watch_stereo = 1; + } else if (max2 == 0 && HAVE_NICAM(state)) { /* D/K NICAM */ - msp->second = carrier_detect_65[max2].cdo; + state->second = carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - msp->nicam_on = 1; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->watch_stereo = 1; + state->nicam_on = 1; + msp3400c_setcarrier(client, state->second, state->main); + state->watch_stereo = 1; } else { goto no_second; } @@ -1043,30 +1056,30 @@ static int msp3400c_thread(void *data) case 0: /* 4.5 */ default: no_second: - msp->second = carrier_detect_main[max1].cdo; + state->second = carrier_detect_main[max1].cdo; msp3400c_setmode(client, MSP_MODE_FM_TERRA); - msp->nicam_on = 0; - msp3400c_setcarrier(client, msp->second, msp->main); - msp->rxsubchans = V4L2_TUNER_SUB_MONO; + state->nicam_on = 0; + msp3400c_setcarrier(client, state->second, state->main); + state->rxsubchans = V4L2_TUNER_SUB_MONO; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); break; } /* unmute */ - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_set_volume(client, state->muted, state->left, state->right); msp3400c_restore_dfp(client); if (debug) msp3400c_print_mode(client); /* monitor tv audio mode */ - while (msp->watch_stereo) { - if (msp34xx_sleep(msp,5000)) + while (state->watch_stereo) { + if (msp_sleep(state,5000)) goto restart; watch_stereo(client); } } - msp3400_dbg("thread: exit\n"); + msp_dbg1("thread: exit\n"); return 0; } @@ -1079,8 +1092,8 @@ static struct MODES { int main, second; char *name; } modelist[] = { - { 0x0000, 0, 0, "ERROR" }, - { 0x0001, 0, 0, "autodetect start" }, + { 0x0000, 0, 0, "could not detect sound standard" }, + { 0x0001, 0, 0, "autodetect started" }, { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, @@ -1101,7 +1114,7 @@ static struct MODES { { -1, 0, 0, NULL }, /* EOF */ }; -static inline const char *msp34xx_standard_mode_name(int mode) +static inline const char *msp_standard_mode_name(int mode) { int i; for (i = 0; modelist[i].name != NULL; i++) @@ -1110,11 +1123,11 @@ static inline const char *msp34xx_standard_mode_name(int mode) return "unknown"; } -static int msp34xx_modus(struct i2c_client *client, int norm) +static int msp_modus(struct i2c_client *client, int norm) { switch (norm) { case VIDEO_MODE_PAL: - msp3400_dbg("video mode selected to PAL\n"); + msp_dbg1("video mode selected to PAL\n"); #if 1 /* experimental: not sure this works with all chip versions */ @@ -1124,23 +1137,23 @@ static int msp34xx_modus(struct i2c_client *client, int norm) return 0x1003; #endif case VIDEO_MODE_NTSC: /* BTSC */ - msp3400_dbg("video mode selected to NTSC\n"); + msp_dbg1("video mode selected to NTSC\n"); return 0x2003; case VIDEO_MODE_SECAM: - msp3400_dbg("video mode selected to SECAM\n"); + msp_dbg1("video mode selected to SECAM\n"); return 0x0003; case VIDEO_MODE_RADIO: - msp3400_dbg("video mode selected to Radio\n"); + msp_dbg1("video mode selected to Radio\n"); return 0x0003; case VIDEO_MODE_AUTO: - msp3400_dbg("video mode selected to Auto\n"); + msp_dbg1("video mode selected to Auto\n"); return 0x2003; default: return 0x0003; } } -static int msp34xx_standard(int norm) +static int msp_standard(int norm) { switch (norm) { case VIDEO_MODE_PAL: @@ -1159,46 +1172,46 @@ static int msp34xx_standard(int norm) static int msp3410d_thread(void *data) { struct i2c_client *client = data; - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int mode,val,i,std; - msp3400_info("msp3410 daemon started\n"); + msp_info("msp3410 daemon started\n"); for (;;) { - msp3400_dbg_mediumvol("msp3410 thread: sleep\n"); - msp34xx_sleep(msp,-1); - msp3400_dbg_mediumvol("msp3410 thread: wakeup\n"); + msp_dbg2("msp3410 thread: sleep\n"); + msp_sleep(state,-1); + msp_dbg2("msp3410 thread: wakeup\n"); restart: - msp3400_dbg("thread: restart scan\n"); - msp->restart = 0; + msp_dbg1("thread: restart scan\n"); + state->restart = 0; if (kthread_should_stop()) break; - if (msp->mode == MSP_MODE_EXTERN) { + if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - msp3400_dbg("thread: no carrier scan\n"); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_dbg1("thread: no carrier scan\n"); + msp_set_volume(client, state->muted, state->left, state->right); continue; } /* put into sane state (and mute) */ - msp3400c_reset(client); + msp_reset(client); /* some time for the tuner to sync */ - if (msp34xx_sleep(msp,200)) + if (msp_sleep(state,200)) goto restart; /* start autodetect */ - mode = msp34xx_modus(client, msp->norm); - std = msp34xx_standard(msp->norm); - msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); - msp->watch_stereo = 0; + mode = msp_modus(client, state->norm); + std = msp_standard(state->norm); + msp_write_dem(client, 0x30, mode); + msp_write_dem(client, 0x20, std); + state->watch_stereo = 0; if (debug) - msp3400_dbg("setting mode: %s (0x%04x)\n", - msp34xx_standard_mode_name(std) ,std); + msp_dbg1("setting mode: %s (0x%04x)\n", + msp_standard_mode_name(std) ,std); if (std != 1) { /* programmed some specific mode */ @@ -1206,171 +1219,164 @@ static int msp3410d_thread(void *data) } else { /* triggered autodetect */ for (;;) { - if (msp34xx_sleep(msp,100)) + if (msp_sleep(state,100)) goto restart; /* check results */ - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); + val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; - msp3400_dbg("detection still in progress\n"); + msp_dbg1("detection still in progress\n"); } } for (i = 0; modelist[i].name != NULL; i++) if (modelist[i].retval == val) break; - msp3400_dbg("current mode: %s (0x%04x)\n", + msp_dbg1("current mode: %s (0x%04x)\n", modelist[i].name ? modelist[i].name : "unknown", val); - msp->main = modelist[i].main; - msp->second = modelist[i].second; + state->main = modelist[i].main; + state->second = modelist[i].second; - if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { + if (amsound && (state->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { /* autodetection has failed, let backup */ - msp3400_dbg("autodetection failed," + msp_dbg1("autodetection failed," " switching to backup mode: %s (0x%04x)\n", modelist[8].name ? modelist[8].name : "unknown",val); val = 0x0009; - msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val); + msp_write_dem(client, 0x20, val); } /* set various prescales */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ - msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */ + msp_write_dsp(client, 0x0d, 0x1900); /* scart */ + msp_write_dsp(client, 0x0e, 0x2403); /* FM */ + msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ /* set stereo */ switch (val) { case 0x0008: /* B/G NICAM */ case 0x000a: /* I NICAM */ if (val == 0x0008) - msp->mode = MSP_MODE_FM_NICAM1; + state->mode = MSP_MODE_FM_NICAM1; else - msp->mode = MSP_MODE_FM_NICAM2; + state->mode = MSP_MODE_FM_NICAM2; /* just turn on stereo */ - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->nicam_on = 1; - msp->watch_stereo = 1; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->nicam_on = 1; + state->watch_stereo = 1; msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); break; case 0x0009: - msp->mode = MSP_MODE_AM_NICAM; - msp->rxsubchans = V4L2_TUNER_SUB_MONO; - msp->nicam_on = 1; + state->mode = MSP_MODE_AM_NICAM; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + state->nicam_on = 1; msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO); - msp->watch_stereo = 1; + state->watch_stereo = 1; break; case 0x0020: /* BTSC */ /* just turn on stereo */ - msp->mode = MSP_MODE_BTSC; - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->nicam_on = 0; - msp->watch_stereo = 1; + state->mode = MSP_MODE_BTSC; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->nicam_on = 0; + state->watch_stereo = 1; msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); break; case 0x0040: /* FM radio */ - msp->mode = MSP_MODE_FM_RADIO; - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->audmode = V4L2_TUNER_MODE_STEREO; - msp->nicam_on = 0; - msp->watch_stereo = 0; + state->mode = MSP_MODE_FM_RADIO; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; + state->nicam_on = 0; + state->watch_stereo = 0; /* not needed in theory if HAVE_RADIO(), but short programming enables carrier mute */ msp3400c_setmode(client,MSP_MODE_FM_RADIO); msp3400c_setcarrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); /* scart routing */ - msp3400c_set_scart(client,SCART_IN2,0); + msp_set_scart(client,SCART_IN2,0); /* msp34xx does radio decoding */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020); + msp_write_dsp(client, 0x08, 0x0020); + msp_write_dsp(client, 0x09, 0x0020); + msp_write_dsp(client, 0x0b, 0x0020); break; case 0x0003: case 0x0004: case 0x0005: - msp->mode = MSP_MODE_FM_TERRA; - msp->rxsubchans = V4L2_TUNER_SUB_MONO; - msp->audmode = V4L2_TUNER_MODE_MONO; - msp->nicam_on = 0; - msp->watch_stereo = 1; + state->mode = MSP_MODE_FM_TERRA; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + state->audmode = V4L2_TUNER_MODE_MONO; + state->nicam_on = 0; + state->watch_stereo = 1; break; } /* unmute, restore misc registers */ - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); - msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb); - msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode); + msp_set_bass(client, state->bass); + msp_set_treble(client, state->treble); + msp_set_volume(client, state->muted, state->left, state->right); + msp_write_dsp(client, 0x13, state->acb); + msp_write_dem(client, 0x40, state->i2s_mode); msp3400c_restore_dfp(client); /* monitor tv audio mode */ - while (msp->watch_stereo) { - if (msp34xx_sleep(msp,5000)) + while (state->watch_stereo) { + if (msp_sleep(state,5000)) goto restart; watch_stereo(client); } } - msp3400_dbg("thread: exit\n"); + msp_dbg1("thread: exit\n"); return 0; } /* ----------------------------------------------------------------------- */ -/* msp34xxG + (simpler no-thread) */ +/* msp34xxG + (autoselect no-thread) */ /* this one uses both automatic standard detection and automatic sound */ /* select which are available in the newer G versions */ /* struct msp: only norm, acb and source are really used in this mode */ static void msp34xxg_set_source(struct i2c_client *client, int source); -/* (re-)initialize the msp34xxg, according to the current norm in msp->norm +/* (re-)initialize the msp34xxg, according to the current norm in state->norm * return 0 if it worked, -1 if it failed */ static int msp34xxg_reset(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int modus,std; - if (msp3400c_reset(client)) + if (msp_reset(client)) return -1; /* make sure that input/output is muted (paranoid mode) */ - if (msp3400c_write(client, - I2C_MSP3400C_DFP, + if (msp_write_dsp(client, 0x13, /* ACB */ 0x0f20 /* mute DSP input, mute SCART 1 */)) return -1; - msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode); + msp_write_dem(client, 0x40, state->i2s_mode); /* step-by-step initialisation, as described in the manual */ - modus = msp34xx_modus(client, msp->norm); - std = msp34xx_standard(msp->norm); + modus = msp_modus(client, state->norm); + std = msp_standard(state->norm); modus &= ~0x03; /* STATUS_CHANGE=0 */ modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */ - if (msp3400c_write(client, - I2C_MSP3400C_DEM, - 0x30/*MODUS*/, - modus)) + if (msp_write_dem(client, 0x30/*MODUS*/, modus)) return -1; - if (msp3400c_write(client, - I2C_MSP3400C_DEM, - 0x20/*standard*/, - std)) + if (msp_write_dem(client, 0x20/*standard*/, std)) return -1; /* write the dfps that may have an influence on standard/audio autodetection right now */ - msp34xxg_set_source(client, msp->source); + msp34xxg_set_source(client, state->source); - if (msp3400c_write_dfp_with_default(client, 0x0e, /* AM/FM Prescale */ + if (msp_write_dfp_with_default(client, 0x0e, /* AM/FM Prescale */ 0x3000 /* default: [15:8] 75khz deviation */ )) return -1; - if (msp3400c_write_dfp_with_default(client, 0x10, /* NICAM Prescale */ + if (msp_write_dfp_with_default(client, 0x10, /* NICAM Prescale */ 0x5a00 /* default: 9db gain (as recommended) */ )) @@ -1382,20 +1388,20 @@ static int msp34xxg_reset(struct i2c_client *client) static int msp34xxg_thread(void *data) { struct i2c_client *client = data; - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int val, std, i; - msp3400_info("msp34xxg daemon started\n"); + msp_info("msp34xxg daemon started\n"); - msp->source = 1; /* default */ + state->source = 1; /* default */ for (;;) { - msp3400_dbg_mediumvol("msp34xxg thread: sleep\n"); - msp34xx_sleep(msp,-1); - msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n"); + msp_dbg2("msp34xxg thread: sleep\n"); + msp_sleep(state,-1); + msp_dbg2("msp34xxg thread: wakeup\n"); restart: - msp3400_dbg("thread: restart scan\n"); - msp->restart = 0; + msp_dbg1("thread: restart scan\n"); + state->restart = 0; if (kthread_should_stop()) break; @@ -1406,45 +1412,43 @@ static int msp34xxg_thread(void *data) goto unmute; /* watch autodetect */ - msp3400_dbg("triggered autodetect, waiting for result\n"); + msp_dbg1("triggered autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { - if (msp34xx_sleep(msp,100)) + if (msp_sleep(state,100)) goto restart; /* check results */ - val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); + val = msp_read_dem(client, 0x7e); if (val < 0x07ff) { std = val; break; } - msp3400_dbg("detection still in progress\n"); + msp_dbg1("detection still in progress\n"); } if (0x01 == std) { - msp3400_dbg("detection still in progress after 10 tries. giving up.\n"); + msp_dbg1("detection still in progress after 10 tries. giving up.\n"); continue; } unmute: - msp3400_dbg("current mode: %s (0x%04x)\n", - msp34xx_standard_mode_name(std), std); + state->mode = std; + msp_dbg1("current mode: %s (0x%04x)\n", + msp_standard_mode_name(std), std); /* unmute: dispatch sound to scart output, set scart volume */ - msp3400_dbg("unmute\n"); + msp_dbg1("unmute\n"); - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_set_bass(client, state->bass); + msp_set_treble(client, state->treble); + msp_set_volume(client, state->muted, state->left, state->right); /* restore ACB */ - if (msp3400c_write(client, - I2C_MSP3400C_DFP, - 0x13, /* ACB */ - msp->acb)) + if (msp_write_dsp(client, 0x13, state->acb)) return -1; - msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode); + msp_write_dem(client, 0x40, state->i2s_mode); } - msp3400_dbg("thread: exit\n"); + msp_dbg1("thread: exit\n"); return 0; } @@ -1456,24 +1460,21 @@ static int msp34xxg_thread(void *data) */ static void msp34xxg_set_source(struct i2c_client *client, int source) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); /* fix matrix mode to stereo and let the msp choose what * to output according to 'source', as recommended * for MONO (source==0) downmixing set bit[7:0] to 0x30 */ int value = (source&0x07)<<8|(source==0 ? 0x30:0x20); - msp3400_dbg("set source to %d (0x%x)\n", source, value); - msp3400c_write(client, - I2C_MSP3400C_DFP, + msp_dbg1("set source to %d (0x%x)\n", source, value); + msp_write_dsp(client, 0x08, /* Loudspeaker Output */ value); - msp3400c_write(client, - I2C_MSP3400C_DFP, + msp_write_dsp(client, 0x0a, /* SCART1 DA Output */ value); - msp3400c_write(client, - I2C_MSP3400C_DFP, + msp_write_dsp(client, 0x0c, /* Quasi-peak detector */ value); /* @@ -1483,30 +1484,28 @@ static void msp34xxg_set_source(struct i2c_client *client, int source) * this needs tuning. (recommended range 0x00a0-0x03c0) * 0x7f0 = forced mono mode */ - msp3400c_write(client, - I2C_MSP3400C_DEM, + msp_write_dem(client, 0x22, /* a2 threshold for stereo/bilingual */ stereo_threshold); - msp->source=source; + state->source=source; } static void msp34xxg_detect_stereo(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); - int status = msp3400c_read(client, - I2C_MSP3400C_DEM, + int status = msp_read_dem(client, 0x0200 /* STATUS */); int is_bilingual = status&0x100; int is_stereo = status&0x40; - msp->rxsubchans = 0; + state->rxsubchans = 0; if (is_stereo) - msp->rxsubchans |= V4L2_TUNER_SUB_STEREO; + state->rxsubchans |= V4L2_TUNER_SUB_STEREO; else - msp->rxsubchans |= V4L2_TUNER_SUB_MONO; + state->rxsubchans |= V4L2_TUNER_SUB_MONO; if (is_bilingual) { - msp->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2; + state->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2; /* I'm supposed to check whether it's SAP or not * and set only LANG2/SAP in this case. Yet, the MSP * does a lot of work to hide this and handle everything @@ -1514,13 +1513,13 @@ static void msp34xxg_detect_stereo(struct i2c_client *client) * this is a problem, I'll handle SAP just like lang1/lang2. */ } - msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", - status, is_stereo, is_bilingual, msp->rxsubchans); + msp_dbg1("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", + status, is_stereo, is_bilingual, state->rxsubchans); } static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); int source; switch (audmode) { @@ -1542,7 +1541,7 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) source = 1; break; } - msp->audmode = audmode; + state->audmode = audmode; msp34xxg_set_source(client, source); } @@ -1551,14 +1550,14 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) static void msp_wake_thread(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); - if (NULL == msp->kthread) + if (NULL == state->kthread) return; - msp3400c_setvolume(client,msp->muted,0,0); - msp->watch_stereo = 0; - msp->restart = 1; - wake_up_interruptible(&msp->wq); + msp_set_volume(client,state->muted,0,0); + state->watch_stereo = 0; + state->restart = 1; + wake_up_interruptible(&state->wq); } /* ----------------------------------------------------------------------- */ @@ -1591,20 +1590,20 @@ static int mode_v4l1_to_v4l2(int mode) static void msp_any_detect_stereo(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); - switch (msp->opmode) { + switch (state->opmode) { case OPMODE_MANUAL: - case OPMODE_SIMPLE: + case OPMODE_AUTODETECT: autodetect_stereo(client); break; - case OPMODE_SIMPLER: + case OPMODE_AUTOSELECT: msp34xxg_detect_stereo(client); break; } } -static struct v4l2_queryctrl msp34xx_qctrl[] = { +static struct v4l2_queryctrl msp_qctrl[] = { { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", @@ -1645,15 +1644,15 @@ static struct v4l2_queryctrl msp34xx_qctrl[] = { static void msp_any_set_audmode(struct i2c_client *client, int audmode) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); - switch (msp->opmode) { + switch (state->opmode) { case OPMODE_MANUAL: - case OPMODE_SIMPLE: - msp->watch_stereo = 0; + case OPMODE_AUTODETECT: + state->watch_stereo = 0; msp3400c_setstereo(client, audmode); break; - case OPMODE_SIMPLER: + case OPMODE_AUTOSELECT: msp34xxg_set_audmode(client, audmode); break; } @@ -1661,32 +1660,32 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode) static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = msp->muted; + ctrl->value = state->muted; return 0; case V4L2_CID_AUDIO_BALANCE: { - int volume = max(msp->left, msp->right); + int volume = max(state->left, state->right); - ctrl->value = (32768 * min(msp->left, msp->right)) / + ctrl->value = (32768 * min(state->left, state->right)) / (volume ? volume : 1); - ctrl->value = (msp->left < msp->right) ? + ctrl->value = (state->left < state->right) ? (65535 - ctrl->value) : ctrl->value; if (0 == volume) ctrl->value = 32768; return 0; } case V4L2_CID_AUDIO_BASS: - ctrl->value = msp->bass; + ctrl->value = state->bass; return 0; case V4L2_CID_AUDIO_TREBLE: - ctrl->value = msp->treble; + ctrl->value = state->treble; return 0; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = max(msp->left, msp->right); + ctrl->value = max(state->left, state->right); return 0; default: return -EINVAL; @@ -1695,124 +1694,126 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { - struct msp3400c *msp = i2c_get_clientdata(client); - int set_volume=0, balance, volume; + struct msp_state *state = i2c_get_clientdata(client); + int set_volume = 0, balance, volume; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - if (ctrl->value>=0 && ctrl->value<2) - msp->muted = ctrl->value; - else + if (ctrl->value < 0 || ctrl->value >= 2) return -ERANGE; - - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + state->muted = ctrl->value; + msp_set_volume(client, state->muted, state->left, state->right); return 0; + case V4L2_CID_AUDIO_BALANCE: - balance=ctrl->value; - volume = max(msp->left, msp->right); - set_volume=1; + balance = ctrl->value; + volume = max(state->left, state->right); + set_volume = 1; break; + case V4L2_CID_AUDIO_BASS: - msp->bass=ctrl->value; - msp3400c_setbass(client, msp->bass); + state->bass = ctrl->value; + msp_set_bass(client, state->bass); return 0; + case V4L2_CID_AUDIO_TREBLE: - msp->treble=ctrl->value; - msp3400c_settreble(client, msp->treble); + state->treble = ctrl->value; + msp_set_treble(client, state->treble); return 0; + case V4L2_CID_AUDIO_VOLUME: - volume = max(msp->left, msp->right); + volume = max(state->left, state->right); - balance = (32768 * min(msp->left, msp->right)) / + balance = (32768 * min(state->left, state->right)) / (volume ? volume : 1); - balance = (msp->left < msp->right) ? + balance = (state->left < state->right) ? (65535 - balance) : balance; - if (0 == volume) + if (volume == 0) balance = 32768; - volume=ctrl->value; - set_volume=1; + volume = ctrl->value; + set_volume = 1; break; + default: return -EINVAL; } if (set_volume) { - msp->left = (min(65536 - balance, 32768) * volume) / 32768; - msp->right = (min(balance, 32768) * volume) / 32768; + state->left = (min(65536 - balance, 32768) * volume) / 32768; + state->right = (min(balance, 32768) * volume) / 32768; - msp3400_dbg("volume=%d, balance=%d, left=%d, right=%d", - volume,balance,msp->left,msp->right); + msp_dbg2("volume=%d, balance=%d, left=%d, right=%d", + volume, balance, state->left, state->right); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_set_volume(client, state->muted, state->left, state->right); } return 0; } static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct msp3400c *msp = i2c_get_clientdata(client); - __u16 *sarg = arg; + struct msp_state *state = i2c_get_clientdata(client); + u16 *sarg = arg; int scart = 0; switch (cmd) { - case AUDC_SET_INPUT: - msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg); + msp_dbg1("AUDC_SET_INPUT(%d)\n",*sarg); - if (*sarg == msp->input) + if (*sarg == state->input) break; - msp->input = *sarg; + state->input = *sarg; switch (*sarg) { case AUDIO_RADIO: /* Hauppauge uses IN2 for the radio */ - msp->mode = MSP_MODE_FM_RADIO; + state->mode = MSP_MODE_FM_RADIO; scart = SCART_IN2; break; case AUDIO_EXTERN_1: /* IN1 is often used for external input ... */ - msp->mode = MSP_MODE_EXTERN; + state->mode = MSP_MODE_EXTERN; scart = SCART_IN1; break; case AUDIO_EXTERN_2: /* ... sometimes it is IN2 through ;) */ - msp->mode = MSP_MODE_EXTERN; + state->mode = MSP_MODE_EXTERN; scart = SCART_IN2; break; case AUDIO_TUNER: - msp->mode = -1; + state->mode = -1; break; default: if (*sarg & AUDIO_MUTE) - msp3400c_set_scart(client,SCART_MUTE,0); + msp_set_scart(client, SCART_MUTE, 0); break; } if (scart) { - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->audmode = V4L2_TUNER_MODE_STEREO; - msp3400c_set_scart(client,scart,0); - msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900); - if (msp->opmode != OPMODE_SIMPLER) - msp3400c_setstereo(client, msp->audmode); + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; + msp_set_scart(client, scart, 0); + msp_write_dsp(client, 0x000d, 0x1900); + if (state->opmode != OPMODE_AUTOSELECT) + msp3400c_setstereo(client, state->audmode); } msp_wake_thread(client); break; case AUDC_SET_RADIO: - msp3400_dbg("AUDC_SET_RADIO\n"); - msp->norm = VIDEO_MODE_RADIO; - msp3400_dbg("switching to radio mode\n"); - msp->watch_stereo = 0; - switch (msp->opmode) { + msp_dbg1("AUDC_SET_RADIO\n"); + state->norm = VIDEO_MODE_RADIO; + msp_dbg1("switching to radio mode\n"); + state->watch_stereo = 0; + switch (state->opmode) { case OPMODE_MANUAL: /* set msp3400 to FM radio mode */ - msp3400c_setmode(client,MSP_MODE_FM_RADIO); + msp3400c_setmode(client, MSP_MODE_FM_RADIO); msp3400c_setcarrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_set_volume(client, state->muted, state->left, state->right); break; - case OPMODE_SIMPLE: - case OPMODE_SIMPLER: + case OPMODE_AUTODETECT: + case OPMODE_AUTOSELECT: /* the thread will do for us */ msp_wake_thread(client); break; @@ -1829,17 +1830,18 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++) if (r->reg == bl_dfp[i]) return -EINVAL; - msp->dfp_regs[r->reg] = r->value; - msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value); + state->dfp_regs[r->reg] = r->value; + msp_write_dsp(client, r->reg, r->value); return 0; } + case MSP_GET_DFPREG: { struct msp_dfpreg *r = arg; if (r->reg < 0 || r->reg >= DFP_COUNT) return -EINVAL; - r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg); + r->value = msp_read_dsp(client, r->reg); return 0; } @@ -1850,62 +1852,50 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_audio *va = arg; - msp3400_dbg("VIDIOCGAUDIO\n"); + msp_dbg1("VIDIOCGAUDIO\n"); va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE | VIDEO_AUDIO_MUTABLE; - if (msp->muted) + if (state->muted) va->flags |= VIDEO_AUDIO_MUTE; - if (msp->muted) + if (state->muted) va->flags |= VIDEO_AUDIO_MUTE; - va->volume = max(msp->left, msp->right); - va->balance = (32768 * min(msp->left, msp->right)) / + va->volume = max(state->left, state->right); + va->balance = (32768 * min(state->left, state->right)) / (va->volume ? va->volume : 1); - va->balance = (msp->left < msp->right) ? + va->balance = (state->left < state->right) ? (65535 - va->balance) : va->balance; if (0 == va->volume) va->balance = 32768; - va->bass = msp->bass; - va->treble = msp->treble; + va->bass = state->bass; + va->treble = state->treble; msp_any_detect_stereo(client); - va->mode = mode_v4l2_to_v4l1(msp->rxsubchans); + va->mode = mode_v4l2_to_v4l1(state->rxsubchans); break; } + case VIDIOCSAUDIO: { struct video_audio *va = arg; - msp3400_dbg("VIDIOCSAUDIO\n"); - msp->muted = (va->flags & VIDEO_AUDIO_MUTE); - msp->left = (min(65536 - va->balance, 32768) * + msp_dbg1("VIDIOCSAUDIO\n"); + state->muted = (va->flags & VIDEO_AUDIO_MUTE); + state->left = (min(65536 - va->balance, 32768) * va->volume) / 32768; - msp->right = (min((int)va->balance, 32768) * va->volume) / 32768; - msp->bass = va->bass; - msp->treble = va->treble; - msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n", - va->volume); - msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n", - va->balance); - msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n", - va->flags); - msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n", - msp->left); - msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n", - msp->right); - msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n", - msp->bass); - msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n", - msp->treble); - msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n", - msp->mode); - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); - msp3400c_setbass(client, msp->bass); - msp3400c_settreble(client, msp->treble); - - if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO) + state->right = (min((int)va->balance, 32768) * va->volume) / 32768; + state->bass = va->bass; + state->treble = va->treble; + msp_dbg1("vol %d, bal %d, flags %x, left %d, right %d, bass %d, treble %d, mode %x\n", + va->volume, va->balance, va->flags, state->left, + state->right, state->bass, state->treble, state->mode); + msp_set_volume(client, state->muted, state->left, state->right); + msp_set_bass(client, state->bass); + msp_set_treble(client, state->treble); + + if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode)); break; } @@ -1914,8 +1904,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_channel *vc = arg; - msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm); - msp->norm = vc->norm; + msp_dbg1("VIDIOCSCHAN (norm=%d)\n",vc->norm); + state->norm = vc->norm; msp_wake_thread(client); break; } @@ -1924,7 +1914,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_S_FREQUENCY: { /* new channel -- kick audio carrier scan */ - msp3400_dbg("VIDIOCSFREQ\n"); + msp_dbg1("VIDIOCSFREQ\n"); msp_wake_thread(client); break; } @@ -1934,8 +1924,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct msp_matrix *mspm = arg; - msp3400_dbg("MSP_SET_MATRIX\n"); - msp3400c_set_scart(client, mspm->input, mspm->output); + msp_dbg1("MSP_SET_MATRIX\n"); + msp_set_scart(client, mspm->input, mspm->output); break; } @@ -1946,11 +1936,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ if (*id & V4L2_STD_PAL) { - msp->norm=VIDEO_MODE_PAL; + state->norm=VIDEO_MODE_PAL; } else if (*id & V4L2_STD_SECAM) { - msp->norm=VIDEO_MODE_SECAM; + state->norm=VIDEO_MODE_SECAM; } else { - msp->norm=VIDEO_MODE_NTSC; + state->norm=VIDEO_MODE_NTSC; } msp_wake_thread(client); @@ -2008,12 +1998,13 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } msp_any_detect_stereo(client); - if (msp->audmode == V4L2_TUNER_MODE_STEREO) { + if (state->audmode == V4L2_TUNER_MODE_STEREO) { a->capability=V4L2_AUDCAP_STEREO; } break; } + case VIDIOC_S_AUDIO: { struct v4l2_audio *sarg = arg; @@ -2021,50 +2012,52 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) switch (sarg->index) { case AUDIO_RADIO: /* Hauppauge uses IN2 for the radio */ - msp->mode = MSP_MODE_FM_RADIO; + state->mode = MSP_MODE_FM_RADIO; scart = SCART_IN2; break; case AUDIO_EXTERN_1: /* IN1 is often used for external input ... */ - msp->mode = MSP_MODE_EXTERN; + state->mode = MSP_MODE_EXTERN; scart = SCART_IN1; break; case AUDIO_EXTERN_2: /* ... sometimes it is IN2 through ;) */ - msp->mode = MSP_MODE_EXTERN; + state->mode = MSP_MODE_EXTERN; scart = SCART_IN2; break; case AUDIO_TUNER: - msp->mode = -1; + state->mode = -1; break; } if (scart) { - msp->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp->audmode = V4L2_TUNER_MODE_STEREO; - msp3400c_set_scart(client,scart,0); - msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900); + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; + msp_set_scart(client,scart,0); + msp_write_dsp(client,0x000d,0x1900); } if (sarg->capability==V4L2_AUDCAP_STEREO) { - msp->audmode = V4L2_TUNER_MODE_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; } else { - msp->audmode &= ~V4L2_TUNER_MODE_STEREO; + state->audmode &= ~V4L2_TUNER_MODE_STEREO; } - msp_any_set_audmode(client, msp->audmode); + msp_any_set_audmode(client, state->audmode); msp_wake_thread(client); break; } + case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; msp_any_detect_stereo(client); - vt->audmode = msp->audmode; - vt->rxsubchans = msp->rxsubchans; + vt->audmode = state->audmode; + vt->rxsubchans = state->rxsubchans; vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1| V4L2_TUNER_CAP_LANG2; break; } + case VIDIOC_S_TUNER: { struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; @@ -2098,6 +2091,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } + case VIDIOC_S_AUDOUT: { struct v4l2_audioout *a=(struct v4l2_audioout *)arg; @@ -2105,23 +2099,24 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (a->index<0||a->index>2) return -EINVAL; - msp3400_dbg("Setting audio out on msp34xx to input %i\n",a->index); - msp3400c_set_scart(client,msp->in_scart,a->index+1); + msp_dbg1("Setting audio out on msp34xx to input %i\n",a->index); + msp_set_scart(client,state->in_scart,a->index+1); break; } + case VIDIOC_INT_I2S_CLOCK_FREQ: { u32 *a=(u32 *)arg; - msp3400_dbg("Setting I2S speed to %d\n",*a); + msp_dbg1("Setting I2S speed to %d\n",*a); switch (*a) { case 1024000: - msp->i2s_mode=0; + state->i2s_mode=0; break; case 2048000: - msp->i2s_mode=1; + state->i2s_mode=1; break; default: return -EINVAL; @@ -2134,33 +2129,49 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; int i; - msp3400_dbg("VIDIOC_QUERYCTRL\n"); + msp_dbg1("VIDIOC_QUERYCTRL\n"); - for (i = 0; i < ARRAY_SIZE(msp34xx_qctrl); i++) - if (qc->id && qc->id == msp34xx_qctrl[i].id) { - memcpy(qc, &(msp34xx_qctrl[i]), + for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) + if (qc->id && qc->id == msp_qctrl[i].id) { + memcpy(qc, &(msp_qctrl[i]), sizeof(*qc)); return 0; } return -EINVAL; } + case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; - msp3400_dbg("VIDIOC_G_CTRL\n"); + msp_dbg1("VIDIOC_G_CTRL\n"); return msp_get_ctrl(client, ctrl); } + case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; - msp3400_dbg("VIDIOC_S_CTRL\n"); + msp_dbg1("VIDIOC_S_CTRL\n"); return msp_set_ctrl(client, ctrl); } + case VIDIOC_LOG_STATUS: + msp_any_detect_stereo(client); + msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", + client->name, state->rev1, state->rev2); + msp_info("Volume: left %d right %d bass %d treble %d%s\n", + state->left, state->right, + state->bass, state->treble, + state->muted ? " (muted)" : ""); + msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), + (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", + (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); + msp_info("ACB: 0x%04x\n", state->acb); + break; + default: /* nothing */ break; @@ -2172,8 +2183,8 @@ static int msp_suspend(struct device * dev, pm_message_t state) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); - msp3400_dbg("suspend\n"); - msp3400c_reset(client); + msp_dbg1("suspend\n"); + msp_reset(client); return 0; } @@ -2181,133 +2192,113 @@ static int msp_resume(struct device * dev) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); - msp3400_dbg("resume\n"); + msp_dbg1("resume\n"); msp_wake_thread(client); return 0; } /* ----------------------------------------------------------------------- */ -static int msp_probe(struct i2c_adapter *adap); -static int msp_detach(struct i2c_client *client); - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "msp3400", - .id = I2C_DRIVERID_MSP3400, - .flags = I2C_DF_NOTIFY, - .attach_adapter = msp_probe, - .detach_client = msp_detach, - .command = msp_command, - .driver = { - .suspend = msp_suspend, - .resume = msp_resume, - }, -}; - -static struct i2c_client client_template = -{ - .name = "(unset)", - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; +static struct i2c_driver i2c_driver; -static int msp_attach(struct i2c_adapter *adap, int addr, int kind) +static int msp_attach(struct i2c_adapter *adapter, int address, int kind) { - struct msp3400c *msp; - struct i2c_client *client = &client_template; + struct i2c_client *client; + struct msp_state *state; int (*thread_func)(void *data) = NULL; int i; - client_template.adapter = adap; - client_template.addr = addr; - - if (-1 == msp3400c_reset(&client_template)) { - msp3400_dbg("no chip found\n"); + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (client == NULL) + return -ENOMEM; + memset(client, 0, sizeof(*client)); + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + client->flags = I2C_CLIENT_ALLOW_USE; + snprintf(client->name, sizeof(client->name) - 1, "msp3400"); + + if (msp_reset(client) == -1) { + msp_dbg1("msp3400 not found\n"); + kfree(client); return -1; } - if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) { kfree(client); return -ENOMEM; } - - memset(msp,0,sizeof(struct msp3400c)); - msp->norm = VIDEO_MODE_NTSC; - msp->left = 58880; /* 0db gain */ - msp->right = 58880; /* 0db gain */ - msp->bass = 32768; - msp->treble = 32768; - msp->input = -1; - msp->muted = 0; - msp->i2s_mode = 0; + i2c_set_clientdata(client, state); + + memset(state, 0, sizeof(*state)); + state->norm = VIDEO_MODE_NTSC; + state->left = 58880; /* 0db gain */ + state->right = 58880; /* 0db gain */ + state->bass = 32768; + state->treble = 32768; + state->input = -1; + state->muted = 0; + state->i2s_mode = 0; for (i = 0; i < DFP_COUNT; i++) - msp->dfp_regs[i] = -1; - - i2c_set_clientdata(client, msp); - init_waitqueue_head(&msp->wq); - - if (-1 == msp3400c_reset(client)) { - kfree(msp); + state->dfp_regs[i] = -1; + init_waitqueue_head(&state->wq); + + state->rev1 = msp_read_dsp(client, 0x1e); + if (state->rev1 != -1) + state->rev2 = msp_read_dsp(client, 0x1f); + msp_dbg1("rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); + if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { + msp_dbg1("error while reading chip version\n"); + kfree(state); kfree(client); - msp3400_dbg("no chip found\n"); return -1; } - msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e); - if (-1 != msp->rev1) - msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f); - if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { - kfree(msp); - kfree(client); - msp3400_dbg("error while reading chip version\n"); - return -1; - } - msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2); - - msp3400c_setvolume(client, msp->muted, msp->left, msp->right); + msp_set_volume(client, state->muted, state->left, state->right); snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", - ((msp->rev1>>4)&0x0f) + '3', - (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@', - ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f); - - msp->opmode = opmode; - if (OPMODE_AUTO == msp->opmode) { - if (HAVE_SIMPLER(msp)) - msp->opmode = OPMODE_SIMPLER; - else if (HAVE_SIMPLE(msp)) - msp->opmode = OPMODE_SIMPLE; + ((state->rev1 >> 4) & 0x0f) + '3', + (state->rev2 >> 8) & 0xff, + (state->rev1 & 0x0f) + '@', + ((state->rev1 >> 8) & 0xff) + '@', + state->rev2 & 0x1f); + + state->opmode = opmode; + if (state->opmode == OPMODE_AUTO) { + /* MSP revision G and up have both autodetect and autoselect */ + if ((state->rev1 & 0x0f) >= 'G'-'@') + state->opmode = OPMODE_AUTOSELECT; + /* MSP revision D and up have autodetect */ + else if ((state->rev1 & 0x0f) >= 'D'-'@') + state->opmode = OPMODE_AUTODETECT; else - msp->opmode = OPMODE_MANUAL; + state->opmode = OPMODE_MANUAL; } /* hello world :-) */ - msp3400_info("chip=%s", client->name); - if (HAVE_NICAM(msp)) - printk(" +nicam"); - if (HAVE_SIMPLE(msp)) - printk(" +simple"); - if (HAVE_SIMPLER(msp)) - printk(" +simpler"); - if (HAVE_RADIO(msp)) - printk(" +radio"); + msp_info("%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + msp_info("%s ", client->name); + if (HAVE_NICAM(state) && HAVE_RADIO(state)) + printk("supports nicam and radio, "); + else if (HAVE_NICAM(state)) + printk("supports nicam, "); + else if (HAVE_RADIO(state)) + printk("supports radio, "); + printk("mode is "); /* version-specific initialization */ - switch (msp->opmode) { + switch (state->opmode) { case OPMODE_MANUAL: - printk(" mode=manual"); + printk("manual"); thread_func = msp3400c_thread; break; - case OPMODE_SIMPLE: - printk(" mode=simple"); + case OPMODE_AUTODETECT: + printk("autodetect"); thread_func = msp3410d_thread; break; - case OPMODE_SIMPLER: - printk(" mode=simpler"); + case OPMODE_AUTOSELECT: + printk("autodetect and autoselect"); thread_func = msp34xxg_thread; break; } @@ -2315,10 +2306,10 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) /* startup control thread if needed */ if (thread_func) { - msp->kthread = kthread_run(thread_func, client, "msp34xx"); + state->kthread = kthread_run(thread_func, client, "msp34xx"); - if (NULL == msp->kthread) - msp3400_warn("kernel_thread() failed\n"); + if (NULL == state->kthread) + msp_warn("kernel_thread() failed\n"); msp_wake_thread(client); } @@ -2328,39 +2319,60 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) return 0; } +static int msp_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, msp_attach); + return 0; +} + static int msp_detach(struct i2c_client *client) { - struct msp3400c *msp = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); + int err; /* shutdown control thread */ - if (msp->kthread) { - msp->restart = 1; - kthread_stop(msp->kthread); + if (state->kthread) { + state->restart = 1; + kthread_stop(state->kthread); } - msp3400c_reset(client); + msp_reset(client); - i2c_detach_client(client); + err = i2c_detach_client(client); + if (err) { + return err; + } - kfree(msp); + kfree(state); kfree(client); return 0; } -static int msp_probe(struct i2c_adapter *adap) -{ - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, msp_attach); - return 0; -} +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .name = "msp3400", + .id = I2C_DRIVERID_MSP3400, + .flags = I2C_DF_NOTIFY, + .attach_adapter = msp_probe, + .detach_client = msp_detach, + .command = msp_command, + .driver = { + .suspend = msp_suspend, + .resume = msp_resume, + }, + .owner = THIS_MODULE, +}; static int __init msp3400_init_module(void) { - return i2c_add_driver(&driver); + return i2c_add_driver(&i2c_driver); } static void __exit msp3400_cleanup_module(void) { - i2c_del_driver(&driver); + i2c_del_driver(&i2c_driver); } module_init(msp3400_init_module); -- cgit v1.2.3 From effee0333b6090ff4ff0463e8fb6084cf4406bbd Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:47 -0200 Subject: V4L/DVB (3266): Add support for DViCO FusionHDTV5 USB Gold - Adds Bluebird ATSC support to the cxusb driver, using dvb-usb-bluebird-atsc-01.fw firmware. Signed-off-by: Michael Krufky Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 92 ++++++++++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index d05fab01cccd..8ca07fdab03d 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -25,6 +25,7 @@ #include "cxusb.h" #include "cx22702.h" +#include "lgdt330x.h" /* debug */ int dvb_usb_cxusb_debug; @@ -165,17 +166,34 @@ struct cx22702_config cxusb_cx22702_config = { .pll_set = dvb_usb_pll_set_i2c, }; +struct lgdt330x_config cxusb_lgdt330x_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .pll_set = dvb_usb_pll_set_i2c, +}; + /* Callbacks for DVB USB */ -static int cxusb_tuner_attach(struct dvb_usb_device *d) +static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d) { u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; d->pll_addr = 0x61; - memcpy(d->pll_init,bpll,4); + memcpy(d->pll_init, bpll, 4); d->pll_desc = &dvb_pll_fmd1216me; return 0; } -static int cxusb_frontend_attach(struct dvb_usb_device *d) +static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d) +{ + u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 }; + /* bpll[2] : unset bit 3, set bits 4&5 + bpll[3] : 0x50 - digital, 0x20 - analog */ + d->pll_addr = 0x61; + memcpy(d->pll_init, bpll, 4); + d->pll_desc = &dvb_pll_tdvs_tua6034; + return 0; +} + +static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d) { u8 b; if (usb_set_interface(d->udev,0,6) < 0) @@ -189,22 +207,43 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d) return -EIO; } +static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d) +{ + if (usb_set_interface(d->udev,0,0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + + if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + /* DVB USB Driver stuff */ -static struct dvb_usb_properties cxusb_properties; +static struct dvb_usb_properties cxusb_medion_properties; +static struct dvb_usb_properties cxusb_bluebird_atsc_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL); + if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_atsc_properties,THIS_MODULE,NULL) == 0) { + return 0; + } + + return -EINVAL; } static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); -static struct dvb_usb_properties cxusb_properties = { +static struct dvb_usb_properties cxusb_medion_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, @@ -213,8 +252,8 @@ static struct dvb_usb_properties cxusb_properties = { .streaming_ctrl = cxusb_streaming_ctrl, .power_ctrl = cxusb_power_ctrl, - .frontend_attach = cxusb_frontend_attach, - .tuner_attach = cxusb_tuner_attach, + .frontend_attach = cxusb_cx22702_frontend_attach, + .tuner_attach = cxusb_fmd1216me_tuner_attach, .i2c_algo = &cxusb_i2c_algo, @@ -240,6 +279,43 @@ static struct dvb_usb_properties cxusb_properties = { } }; +static struct dvb_usb_properties cxusb_bluebird_atsc_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-bluebird-atsc-01.fw", + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_lgdt330x_frontend_attach, + .tuner_attach = cxusb_lgh064f_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV5 USB Gold", + { &cxusb_table[1], NULL }, + { &cxusb_table[2], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 6be99e537e12..784adfe1c070 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -91,6 +91,8 @@ #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 #define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 +#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 +#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd700 #define USB_PID_MEDION_MD95700 0x0932 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f -- cgit v1.2.3 From 37bdfa06b6bbf085b55d64eb5d9ed112418ed5ad Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:25:47 -0200 Subject: V4L/DVB (3268): Use combined firmware for DVB-T and ATSC Bluebird FusionHDTV USB models. - Now using firmware "dvb-usb-bluebird-01.fw", with combined support for atsc and dvb-t Bluebird models. - Use usb alt setting 0 for EP4 transfer (dvb-t), - Use usb alt setting 7 for EP2 transfer (atsc) */ Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 8ca07fdab03d..1a67ed598d97 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -209,7 +209,7 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d) static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d) { - if (usb_set_interface(d->udev,0,0) < 0) + if (usb_set_interface(d->udev,0,7) < 0) err("set interface failed"); cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); @@ -283,7 +283,9 @@ static struct dvb_usb_properties cxusb_bluebird_atsc_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-bluebird-atsc-01.fw", + .firmware = "dvb-usb-bluebird-01.fw", + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ .size_of_priv = sizeof(struct cxusb_state), -- cgit v1.2.3 From 5e453dc757385ec892a818e4e3b5de027987ced9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:32:31 -0200 Subject: V4L/DVB (3269): ioctls cleanups. - Now, all internal ioctls are at v4l2-common.h - removed unused ioctl at saa6752hs.h - all debug ioctl code moved to v4l2-common.c - removed duplicated stuff from other cards Signed-off-by: Michael Krufky Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-cards.c | 1 + drivers/media/video/bttv-driver.c | 28 +--- drivers/media/video/bttv-i2c.c | 1 + drivers/media/video/cx88/cx88-blackbird.c | 3 +- drivers/media/video/cx88/cx88-core.c | 56 +------ drivers/media/video/cx88/cx88-dvb.c | 1 + drivers/media/video/cx88/cx88-i2c.c | 1 + drivers/media/video/cx88/cx88-video.c | 7 +- drivers/media/video/cx88/cx88.h | 1 - drivers/media/video/em28xx/em28xx-core.c | 53 ------- drivers/media/video/em28xx/em28xx-i2c.c | 1 + drivers/media/video/em28xx/em28xx-video.c | 2 +- drivers/media/video/em28xx/em28xx.h | 2 - drivers/media/video/mxb.c | 1 + drivers/media/video/saa7134/saa7134-cards.c | 1 + drivers/media/video/saa7134/saa7134-core.c | 72 --------- drivers/media/video/saa7134/saa7134-dvb.c | 1 + drivers/media/video/saa7134/saa7134-empress.c | 3 +- drivers/media/video/saa7134/saa7134-i2c.c | 1 + drivers/media/video/saa7134/saa7134-oss.c | 40 ++++- drivers/media/video/saa7134/saa7134-video.c | 5 +- drivers/media/video/saa7134/saa7134.h | 1 - drivers/media/video/tda9887.c | 2 +- drivers/media/video/tuner-core.c | 12 +- drivers/media/video/tvaudio.c | 1 + drivers/media/video/v4l2-common.c | 219 ++++++++++++++++++++------ include/linux/video_decoder.h | 2 + include/linux/videodev2.h | 1 - include/media/audiochip.h | 5 - include/media/tuner.h | 4 - include/media/v4l2-common.h | 25 +++ 31 files changed, 267 insertions(+), 286 deletions(-) diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 440f635e020f..1621ab133d23 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -38,6 +38,7 @@ #include #include "bttvp.h" +#include /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 69a147b85f1a..f3de85251719 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -35,6 +35,7 @@ #include #include #include "bttvp.h" +#include #include @@ -1520,14 +1521,6 @@ static struct videobuf_queue_ops bttv_video_qops = { .buf_release = buffer_release, }; -static const char *v4l1_ioctls[] = { - "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", - "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", - "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", - "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", - "SMICROCODE", "GVBIFMT", "SVBIFMT" }; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) - static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { switch (cmd) { @@ -2216,22 +2209,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, unsigned long flags; int retval = 0; - if (bttv_debug > 1) { - switch (_IOC_TYPE(cmd)) { - case 'v': - printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n", - btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'V': - printk("bttv%d: ioctl 0x%x (v4l2, %s)\n", - btv->c.nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); - break; - default: - printk("bttv%d: ioctl 0x%x (???)\n", - btv->c.nr, cmd); - } - } + if (bttv_debug > 1) + v4l_print_ioctl(btv->c.name, cmd); + if (btv->errors) bttv_reinit_bt848(btv); diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index a8873f48c808..fd66d386fa7d 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -30,6 +30,7 @@ #include #include "bttvp.h" +#include #include #include diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 5a7f940565cc..a49062119313 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -32,6 +32,7 @@ #include #include "cx88.h" +#include MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); @@ -1374,7 +1375,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, struct cx88_core *core = dev->core; if (debug > 1) - cx88_print_ioctl(core->name,cmd); + v4l_print_ioctl(core->name,cmd); switch (cmd) { diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index bb6eb54e19ce..fc814d198694 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -34,6 +34,7 @@ #include #include "cx88.h" +#include MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); @@ -76,60 +77,6 @@ static unsigned int cx88_devcount; static LIST_HEAD(cx88_devlist); static DECLARE_MUTEX(devlist); -/* ------------------------------------------------------------------ */ -/* debug help functions */ - -static const char *v4l1_ioctls[] = { - "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", - "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", - "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", - "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", - "SMICROCODE", "GVBIFMT", "SVBIFMT" }; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) - -static const char *v4l2_ioctls[] = { - "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", - "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", - "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", - "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", - "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", - "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", - "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", - "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", - "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", - "S_MODULATOR" -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -void cx88_print_ioctl(char *name, unsigned int cmd) -{ - char *dir; - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "??"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'v': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'V': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "???"); - break; - default: - printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - } -} - -/* ------------------------------------------------------------------ */ #define NO_SYNC_LINE (-1U) static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist, @@ -1208,7 +1155,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx88_print_ioctl); EXPORT_SYMBOL(cx88_print_irqbits); EXPORT_SYMBOL(cx88_core_irq); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 201050478711..c63f20fdff48 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -31,6 +31,7 @@ #include "cx88.h" #include "dvb-pll.h" +#include #ifdef HAVE_MT352 # include "mt352.h" diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c6492089ee1a..f720901e9638 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -30,6 +30,7 @@ #include #include "cx88.h" +#include static unsigned int i2c_debug = 0; module_param(i2c_debug, int, 0644); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index b76abb9b8961..9a02515fe18b 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -33,6 +33,7 @@ #include #include "cx88.h" +#include /* Include V4L1 specific functions. Should be removed soon */ #include @@ -1118,7 +1119,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, int err; if (video_debug > 1) - cx88_print_ioctl(core->name,cmd); + v4l_print_ioctl(core->name,cmd); switch (cmd) { /* --- capabilities ------------------------------------------ */ @@ -1254,7 +1255,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, dprintk( 1, "CORE IOCTL: 0x%x\n", cmd ); if (video_debug > 1) - cx88_print_ioctl(core->name,cmd); + v4l_print_ioctl(core->name,cmd); switch (cmd) { /* ---------- tv norms ---------- */ @@ -1474,7 +1475,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, struct cx88_core *core = dev->core; if (video_debug > 1) - cx88_print_ioctl(core->name,cmd); + v4l_print_ioctl(core->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 6d370d1b333f..022ef13c45bc 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -461,7 +461,6 @@ struct cx8802_dev { extern void cx88_print_irqbits(char *name, char *tag, char **strings, u32 bits, u32 mask); -extern void cx88_print_ioctl(char *name, unsigned int cmd); extern int cx88_core_irq(struct cx88_core *core, u32 status); extern void cx88_wakeup(struct cx88_core *core, diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index c0db0e9d2cea..dff3893f32fd 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -63,59 +63,6 @@ static int alt = EM28XX_PINOUT; module_param(alt, int, 0644); MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); -/* ------------------------------------------------------------------ */ -/* debug help functions */ - -static const char *v4l1_ioctls[] = { - "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", - "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", - "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", - "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", - "SMICROCODE", "GVBIFMT", "SVBIFMT" }; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) - -static const char *v4l2_ioctls[] = { - "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", - "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", - "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", - "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", - "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", - "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", - "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", - "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", - "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", - "S_MODULATOR" -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -void em28xx_print_ioctl(char *name, unsigned int cmd) -{ - char *dir; - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "??"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'v': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'V': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "???"); - break; - default: - printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - } -} - /* * em28xx_request_buffers() diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 5385338efbf4..0591a705b7a1 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -28,6 +28,7 @@ #include #include "em28xx.h" +#include #include /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 0b5557c479ae..fdc255918dde 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1269,7 +1269,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, return -ENODEV; if (video_debug > 1) - em28xx_print_ioctl(dev->name,cmd); + v4l_print_ioctl(dev->name,cmd); switch (cmd) { diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index ffa9acc9be37..f99ee8eb5577 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -295,8 +295,6 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir); /* Provided by em28xx-core.c */ -void em28xx_print_ioctl(char *name, unsigned int cmd); - u32 em28xx_request_buffers(struct em28xx *dev, u32 count); void em28xx_queue_unusedframes(struct em28xx *dev); void em28xx_release_buffers(struct em28xx *dev); diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index d04793fb80fc..91681aa6c657 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "mxb.h" #include "tea6415c.h" diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 73f2525bc764..991829eb15da 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -25,6 +25,7 @@ #include "saa7134-reg.h" #include "saa7134.h" +#include /* commly used strings */ static char name_mute[] = "mute"; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 0bdbd99d0ae6..d4be1fd20a36 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -95,77 +95,6 @@ int (*dmasound_exit)(struct saa7134_dev *dev); #define dprintk(fmt, arg...) if (core_debug) \ printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) -/* ------------------------------------------------------------------ */ -/* debug help functions */ - -static const char *v4l1_ioctls[] = { - "0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", - "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", - "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", - "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", - "SMICROCODE", "GVBIFMT", "SVBIFMT" }; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) - -static const char *v4l2_ioctls[] = { - "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", - "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", - "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", - "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", - "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", - "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", - "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", - "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", - "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", - "S_MODULATOR" -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -static const char *osspcm_ioctls[] = { - "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", - "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", - "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", - "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", - "SETDUPLEX", "GETODELAY" -}; -#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -void saa7134_print_ioctl(char *name, unsigned int cmd) -{ - char *dir; - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "??"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'v': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'V': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'P': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? - osspcm_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'M': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - break; - default: - printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - } -} - void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) { unsigned long mode,status; @@ -1173,7 +1102,6 @@ module_exit(saa7134_fini); /* ----------------------------------------------------------- */ -EXPORT_SYMBOL(saa7134_print_ioctl); EXPORT_SYMBOL(saa7134_i2c_call_clients); EXPORT_SYMBOL(saa7134_devlist); EXPORT_SYMBOL(saa7134_boards); diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index e016480c3468..399f9952596c 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -31,6 +31,7 @@ #include "saa7134-reg.h" #include "saa7134.h" +#include #ifdef HAVE_MT352 # include "mt352.h" diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 575f3e835f91..bd4c389d4c37 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -29,6 +29,7 @@ #include "saa7134.h" #include +#include /* ------------------------------------------------------------------ */ @@ -163,7 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file, struct saa7134_dev *dev = file->private_data; if (debug > 1) - saa7134_print_ioctl(dev->name,cmd); + v4l_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 7283caa0484b..6162550c4136 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -30,6 +30,7 @@ #include "saa7134-reg.h" #include "saa7134.h" +#include /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 8badd2a9cb2f..7448e386a804 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -373,6 +373,42 @@ static ssize_t dsp_write(struct file *file, const char __user *buffer, return -EINVAL; } +static const char *osspcm_ioctls[] = { + "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", + "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", + "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", + "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", + "SETDUPLEX", "GETODELAY" +}; +#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls) + +static void saa7134_oss_print_ioctl(char *name, unsigned int cmd) +{ + char *dir; + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "??"; break; + } + switch (_IOC_TYPE(cmd)) { + case 'P': + printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", + name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? + osspcm_ioctls[_IOC_NR(cmd)] : "???"); + break; + case 'M': + printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", + name, cmd, dir, _IOC_NR(cmd)); + break; + default: + printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", + name, cmd, dir, _IOC_NR(cmd)); + } +} + static int dsp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -382,7 +418,7 @@ static int dsp_ioctl(struct inode *inode, struct file *file, int val = 0; if (debug > 1) - saa7134_print_ioctl(dev->name,cmd); + saa7134_oss_print_ioctl(dev->name,cmd); switch (cmd) { case OSS_GETVERSION: return put_user(SOUND_VERSION, p); @@ -678,7 +714,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file, int __user *p = argp; if (debug > 1) - saa7134_print_ioctl(dev->name,cmd); + saa7134_oss_print_ioctl(dev->name,cmd); switch (cmd) { case OSS_GETVERSION: return put_user(SOUND_VERSION, p); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9b9e1e7f05ef..adfa8fe49a11 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -29,6 +29,7 @@ #include "saa7134-reg.h" #include "saa7134.h" +#include /* Include V4L1 specific functions. Should be removed soon */ #include @@ -1689,7 +1690,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, int err; if (video_debug > 1) - saa7134_print_ioctl(dev->name,cmd); + v4l_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_S_CTRL: @@ -2142,7 +2143,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, struct saa7134_dev *dev = fh->dev; if (video_debug > 1) - saa7134_print_ioctl(dev->name,cmd); + v4l_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 2f28e83102fd..18978a484ddb 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -546,7 +546,6 @@ struct saa7134_dev { extern struct list_head saa7134_devlist; -void saa7134_print_ioctl(char *name, unsigned int cmd); void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); #define SAA7134_PGTABLE_SIZE 4096 diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 9ae43a8cea52..f64baa4b0025 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index df994311251e..fd18a882668e 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "msp3400.h" @@ -545,6 +546,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); + if (tuner_debug>1) + v4l_i2c_print_ioctl(&(t->i2c),cmd); + switch (cmd) { /* --- configuration --- */ case TUNER_SET_TYPE_ADDR: @@ -575,9 +579,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* Should be implemented, since bttv calls it */ tuner_dbg("VIDIOCSAUDIO not implemented.\n"); - break; - case MSP_SET_MATRIX: - case TDA9887_SET_CONFIG: break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a @@ -764,11 +765,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_LOG_STATUS: tuner_status(client); break; - default: - tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n", - cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd), - _IOC_NR(cmd), _IOC_SIZE(cmd)); - break; } return 0; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index ed6a843dd34a..fec620073aa3 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -31,6 +31,7 @@ #include #include +#include #include "tvaudio.h" diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 62a7d636ef11..5dbd7c1b362a 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -58,6 +58,8 @@ #include #include #include +#include +#include #ifdef CONFIG_KMOD #include @@ -190,55 +192,174 @@ char *v4l2_type_names[] = { [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", }; -char *v4l2_ioctl_names[256] = { - [0 ... 255] = "UNKNOWN", - [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", - [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", - [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", - [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", - [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", - [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", - [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", - [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", - [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", - [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", - [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", - [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", - [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", - [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", - [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", - [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", - [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", - [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", - [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", - [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", - [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", - [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", - [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", - [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", - [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", - [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", - [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", - [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", - [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", - [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", - [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", - [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", - [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", - [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", - [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", - [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", - [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", - [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", - [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", - [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", - [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", - [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", - [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", - [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", - [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", - [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", +/* ------------------------------------------------------------------ */ +/* debug help functions */ + +#ifdef HAVE_V4L1 +static const char *v4l1_ioctls[] = { + [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", + [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", + [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", + [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", + [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", + [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", + [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", + [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", + [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", + [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", + [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", + [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", + [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", + [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", + [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", + [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", + [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", + [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", + [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", + [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", + [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", + [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", + [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", + [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", + [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", + [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", + [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", + [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", + [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" }; +#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) +#endif + +static const char *v4l2_ioctls[] = { + [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", + [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", + [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", + [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", + [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", + [_IOC_NR(VIDIOC_G_MPEGCOMP)] = "VIDIOC_G_MPEGCOMP", + [_IOC_NR(VIDIOC_S_MPEGCOMP)] = "VIDIOC_S_MPEGCOMP", + [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", + [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", + [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", + [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", + [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", + [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", + [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", + [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", + [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", + [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", + [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", + [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", + [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", + [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", + [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", + [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", + [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", + [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", + [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", + [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", + [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", + [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", + [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", + [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", + [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", + [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", + [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", + [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", + [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", + [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", + [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", + [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", + [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", + [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", + [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", + [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", + [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", + [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", + [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", + [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", + [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", + [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", + [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", + [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", + [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", +#if 1 + [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", +#endif + [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS" +}; +#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) + +static const char *v4l2_int_ioctls[] = { +#ifdef HAVE_VIDEO_DECODER + [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", + [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", + [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", + [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", + [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", + [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", + [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", + [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", + [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", + [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", + [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", +#endif + [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", + [_IOC_NR(AUDC_SET_INPUT)] = "AUDC_SET_INPUT", + + [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", + [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", + [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", + + [_IOC_NR(VIDIOC_INT_S_REGISTER)] = "VIDIOC_INT_S_REGISTER", + [_IOC_NR(VIDIOC_INT_G_REGISTER)] = "VIDIOC_INT_G_REGISTER", + [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", + [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", + [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", + [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", + [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", + [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT", + [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ" +}; +#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) + +/* Common ioctl debug function. This function can be used by + external ioctl messages as well as internal V4L ioctl */ +void v4l_printk_ioctl(unsigned int cmd) +{ + char *dir; + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "*ERR*"; break; + } + switch (_IOC_TYPE(cmd)) { + case 'd': + printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n", + (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? + v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); + break; +#ifdef HAVE_V4L1 + case 'v': + printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", + (_IOC_NR(cmd) < V4L1_IOCTLS) ? + v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); + break; +#endif + case 'V': + printk("v4l2 ioctl %s, dir=%s (0x%08x)\n", + (_IOC_NR(cmd) < V4L2_IOCTLS) ? + v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); + break; + + default: + printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n", + _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); + } +} /* ----------------------------------------------------------------- */ @@ -253,7 +374,7 @@ EXPORT_SYMBOL(v4l2_prio_check); EXPORT_SYMBOL(v4l2_field_names); EXPORT_SYMBOL(v4l2_type_names); -EXPORT_SYMBOL(v4l2_ioctl_names); +EXPORT_SYMBOL(v4l_printk_ioctl); /* * Local variables: diff --git a/include/linux/video_decoder.h b/include/linux/video_decoder.h index 0e9e48b83e3b..121e26da2c18 100644 --- a/include/linux/video_decoder.h +++ b/include/linux/video_decoder.h @@ -1,6 +1,8 @@ #ifndef _LINUX_VIDEO_DECODER_H #define _LINUX_VIDEO_DECODER_H +#define HAVE_VIDEO_DECODER 1 + struct video_decoder_capability { /* this name is too long */ __u32 flags; #define VIDEO_DECODER_PAL 1 /* can decode PAL signal */ diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 6ac7c1f7902f..ce40675324bd 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1116,7 +1116,6 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local); /* names for fancy debug output */ extern char *v4l2_field_names[]; extern char *v4l2_type_names[]; -extern char *v4l2_ioctl_names[]; /* Compatibility layer interface -- v4l1-compat module */ typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, diff --git a/include/media/audiochip.h b/include/media/audiochip.h index 411f09fc4574..295d256ee811 100644 --- a/include/media/audiochip.h +++ b/include/media/audiochip.h @@ -23,11 +23,6 @@ enum audiochip { /* ---------------------------------------------------------------------- */ -/* v4l device was opened in Radio mode */ -#define AUDC_SET_RADIO _IO('m',2) -/* select from TV,radio,extern,MUTE */ -#define AUDC_SET_INPUT _IOW('m',17,int) - /* audio inputs */ #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 diff --git a/include/media/tuner.h b/include/media/tuner.h index c5f034ecb002..6a8ef189e5fa 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -115,10 +115,6 @@ #define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ #define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */ -#define TUNER_SET_TYPE_ADDR _IOW('T',3,int) -#define TUNER_SET_STANDBY _IOW('T',4,int) -#define TDA9887_SET_CONFIG _IOW('t',5,int) - /* tv card specific */ #define TDA9887_PRESENT (1<<0) #define TDA9887_PORT1_INACTIVE (1<<1) diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 90248d29ed0a..9ee616261d66 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -63,6 +63,20 @@ enum v4l2_chip_ident { V4L2_IDENT_CX25843 = 243, }; +/* audio ioctls */ +/* v4l device was opened in Radio mode */ +#define AUDC_SET_RADIO _IO('d',88) +/* select from TV,radio,extern,MUTE */ +#define AUDC_SET_INPUT _IOW('d',89,int) + +/* tuner ioctls */ +/* Sets tuner type and its I2C addr */ +#define TUNER_SET_TYPE_ADDR _IOW('d',90,int) +/* Puts tuner on powersaving state, disabling it, except for i2c */ +#define TUNER_SET_STANDBY _IOW('d',91,int) +/* Sets tda9887 specific stuff, like port1, port2 and qss */ +#define TDA9887_SET_CONFIG _IOW('d',92,int) + /* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */ #define VIDIOC_INT_S_REGISTER _IOR ('d', 100, struct v4l2_register) #define VIDIOC_INT_G_REGISTER _IOWR('d', 101, struct v4l2_register) @@ -108,5 +122,16 @@ enum v4l2_chip_ident { If the frequency is not supported, then -EINVAL is returned. */ #define VIDIOC_INT_I2S_CLOCK_FREQ _IOW ('d', 108, u32) +/* Prints used ioctl */ +extern void v4l_printk_ioctl(unsigned int cmd); + +#define v4l_print_ioctl(name,cmd) do {\ + printk(KERN_DEBUG "%s: ", name); \ + v4l_printk_ioctl(cmd); } while (0) + +#define v4l_i2c_print_ioctl(client,cmd) do {\ + printk(KERN_DEBUG "%s %d-%04x: ", (client)->driver->name, \ + i2c_adapter_id((client)->adapter),(client)->addr); \ + v4l_printk_ioctl(cmd); } while (0) #endif /* V4L2_COMMON_H_ */ -- cgit v1.2.3 From e93fa17eb103bad5d2ee7141a988040f077d2a78 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:39 -0200 Subject: V4L/DVB (3271): more cleanups, simplify volume/balance/bass/treble handling - Continue cleanup effort: - more cosmetic changes - combine volume, balance, bass and treble into one audio function. Revert old 2.4 code that crept in. - print internal ioctls using new debug function. - marked all msp3400c (aka manual) functions as such. - removed some unused data structures. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400.c | 642 ++++++++++++++++++------------------------ 1 file changed, 272 insertions(+), 370 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 39058d3b2e61..627c3110d3e3 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -158,8 +158,8 @@ static const int bl_dfp[] = { 0x0b, 0x0d, 0x0e, 0x10 }; -#define HAVE_NICAM(state) (((state->rev2>>8) & 0xff) != 00) -#define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') +#define HAVE_NICAM(state) (((state->rev2 >> 8) & 0xff) != 0) +#define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') struct msp_state { int rev1, rev2; @@ -181,7 +181,7 @@ struct msp_state { int rxsubchans; int muted; - int left, right; /* volume */ + int volume, balance; int bass, treble; /* shadow register set */ @@ -217,9 +217,9 @@ static int msp_reset(struct i2c_client *client) }; msp_dbg3("msp_reset\n"); - if (1 != i2c_transfer(client->adapter, &reset[0], 1) || - 1 != i2c_transfer(client->adapter, &reset[1], 1) || - 2 != i2c_transfer(client->adapter, test, 2)) { + if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || + i2c_transfer(client->adapter, &reset[1], 1) != 1 || + i2c_transfer(client->adapter, test, 2) != 2) { msp_err("chip reset failed\n"); return -1; } @@ -241,14 +241,14 @@ static int msp_read(struct i2c_client *client, int dev, int addr) write[2] = addr & 0xff; for (err = 0; err < 3; err++) { - if (2 == i2c_transfer(client->adapter, msgs, 2)) + if (i2c_transfer(client->adapter, msgs, 2) == 2) break; msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(msecs_to_jiffies(10)); } - if (3 == err) { + if (err == 3) { msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); msp_reset(client); return -1; @@ -281,14 +281,14 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); for (err = 0; err < 3; err++) { - if (5 == i2c_master_send(client, buffer, 5)) + if (i2c_master_send(client, buffer, 5) == 5) break; msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(msecs_to_jiffies(10)); } - if (3 == err) { + if (err == 3) { msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); msp_reset(client); return -1; @@ -306,6 +306,70 @@ static inline int msp_write_dsp(struct i2c_client *client, int addr, int val) return msp_write(client, I2C_MSP_DSP, addr, val); } +/* ----------------------------------------------------------------------- * + * bits 9 8 5 - SCART DSP input Select: + * 0 0 0 - SCART 1 to DSP input (reset position) + * 0 1 0 - MONO to DSP input + * 1 0 0 - SCART 2 to DSP input + * 1 1 1 - Mute DSP input + * + * bits 11 10 6 - SCART 1 Output Select: + * 0 0 0 - undefined (reset position) + * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) + * 1 0 0 - MONO input to SCART 1 Output + * 1 1 0 - SCART 1 DA to SCART 1 Output + * 0 0 1 - SCART 2 DA to SCART 1 Output + * 0 1 1 - SCART 1 Input to SCART 1 Output + * 1 1 1 - Mute SCART 1 Output + * + * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): + * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) + * 0 1 0 - SCART 1 Input to SCART 2 Output + * 1 0 0 - MONO input to SCART 2 Output + * 0 0 1 - SCART 2 DA to SCART 2 Output + * 0 1 1 - SCART 2 Input to SCART 2 Output + * 1 1 0 - Mute SCART 2 Output + * + * Bits 4 to 0 should be zero. + * ----------------------------------------------------------------------- */ + +static int scarts[3][9] = { + /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ + /* SCART DSP Input select */ + { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, + /* SCART1 Output select */ + { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, + /* SCART2 Output select */ + { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, +}; + +static char *scart_names[] = { + "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" +}; + +static void msp_set_scart(struct i2c_client *client, int in, int out) +{ + struct msp_state *state = i2c_get_clientdata(client); + + state->in_scart=in; + + if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { + if (-1 == scarts[out][in]) + return; + + state->acb &= ~scarts[out][SCART_MASK]; + state->acb |= scarts[out][in]; + } else + state->acb = 0xf60; /* Mute Input and SCART 1 Output */ + + msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", + scart_names[in], out, state->acb); + msp_write_dsp(client, 0x13, state->acb); + + /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ + msp_write_dem(client, 0x40, state->i2s_mode); +} + /* ------------------------------------------------------------------------ */ /* This macro is allowed for *constants* only, gcc must calculate it @@ -322,7 +386,7 @@ static inline int msp_write_dsp(struct i2c_client *client, int addr, int val) #define MSP_MODE_BTSC 8 #define MSP_MODE_EXTERN 9 -static struct MSP_INIT_DATA_DEM { +static struct msp3400c_init_data_dem { int fir1[6]; int fir2[6]; int cdo1; @@ -331,7 +395,7 @@ static struct MSP_INIT_DATA_DEM { int mode_reg; int dfp_src; int dfp_matrix; -} msp_init_data[] = { +} msp3400c_init_data[] = { { /* AM (for carrier detect / msp3400) */ {75, 19, 36, 35, 39, 40}, {75, 19, 36, 35, 39, 40}, @@ -375,12 +439,12 @@ static struct MSP_INIT_DATA_DEM { }, }; -struct CARRIER_DETECT { +struct msp3400c_carrier_detect { int cdo; char *name; }; -static struct CARRIER_DETECT carrier_detect_main[] = { +static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { /* main carrier */ { MSP_CARRIER(4.5), "4.5 NTSC" }, { MSP_CARRIER(5.5), "5.5 PAL B/G" }, @@ -388,13 +452,13 @@ static struct CARRIER_DETECT carrier_detect_main[] = { { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } }; -static struct CARRIER_DETECT carrier_detect_55[] = { +static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { /* PAL B/G */ { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } }; -static struct CARRIER_DETECT carrier_detect_65[] = { +static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { /* PAL SAT / SECAM */ { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, @@ -404,72 +468,6 @@ static struct CARRIER_DETECT carrier_detect_65[] = { { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, }; -#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) - -/* ----------------------------------------------------------------------- * - * bits 9 8 5 - SCART DSP input Select: - * 0 0 0 - SCART 1 to DSP input (reset position) - * 0 1 0 - MONO to DSP input - * 1 0 0 - SCART 2 to DSP input - * 1 1 1 - Mute DSP input - * - * bits 11 10 6 - SCART 1 Output Select: - * 0 0 0 - undefined (reset position) - * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) - * 1 0 0 - MONO input to SCART 1 Output - * 1 1 0 - SCART 1 DA to SCART 1 Output - * 0 0 1 - SCART 2 DA to SCART 1 Output - * 0 1 1 - SCART 1 Input to SCART 1 Output - * 1 1 1 - Mute SCART 1 Output - * - * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): - * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) - * 0 1 0 - SCART 1 Input to SCART 2 Output - * 1 0 0 - MONO input to SCART 2 Output - * 0 0 1 - SCART 2 DA to SCART 2 Output - * 0 1 1 - SCART 2 Input to SCART 2 Output - * 1 1 0 - Mute SCART 2 Output - * - * Bits 4 to 0 should be zero. - * ----------------------------------------------------------------------- */ - -static int scarts[3][9] = { - /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ - /* SCART DSP Input select */ - { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, - /* SCART1 Output select */ - { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, - /* SCART2 Output select */ - { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, -}; - -static char *scart_names[] = { - "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" -}; - -static void msp_set_scart(struct i2c_client *client, int in, int out) -{ - struct msp_state *state = i2c_get_clientdata(client); - - state->in_scart=in; - - if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { - if (-1 == scarts[out][in]) - return; - - state->acb &= ~scarts[out][SCART_MASK]; - state->acb |= scarts[out][in]; - } else - state->acb = 0xf60; /* Mute Input and SCART 1 Output */ - - msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); - msp_write_dsp(client, 0x13, state->acb); - - /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ - msp_write_dem(client, 0x40, state->i2s_mode); -} - /* ------------------------------------------------------------------------ */ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) @@ -481,42 +479,35 @@ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ } -static void msp_set_volume(struct i2c_client *client, - int muted, int left, int right) - { - int vol = 0, val = 0, balance = 0; - - if (!muted) { - vol = (left > right) ? left : right; - val = (vol * 0x7f / 65535) << 8; - } - if (vol > 0) { - balance = ((right - left) * 127) / vol; - } - - msp_dbg1("setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n", - muted ? "on" : "off", left, right, val >> 8, balance); - msp_write_dsp(client, 0x0000, val); /* loudspeaker */ - msp_write_dsp(client, 0x0006, val); /* headphones */ - msp_write_dsp(client, 0x0007, - muted ? 0x1 : (val | 0x1)); - msp_write_dsp(client, 0x0001, balance << 8); +static void msp_set_mute(struct i2c_client *client) +{ + msp_dbg1("mute audio\n"); + msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ + msp_write_dsp(client, 0x0006, 0); /* headphones */ } -static void msp_set_bass(struct i2c_client *client, int bass) +static void msp_set_audio(struct i2c_client *client) { - int val = ((bass-32768) * 0x60 / 65535) << 8; + struct msp_state *state = i2c_get_clientdata(client); + int val = 0, bal = 0, bass, treble; - msp_dbg1("setbass: %d 0x%02x\n", bass, val >> 8); - msp_write_dsp(client, 0x0002, val); /* loudspeaker */ -} + if (!state->muted) + val = (state->volume * 0x7f / 65535) << 8; + if (val) + bal = (state->balance / 256) - 128; + bass = ((state->bass - 32768) * 0x60 / 65535) << 8; + treble = ((state->treble - 32768) * 0x60 / 65535) << 8; -static void msp_set_treble(struct i2c_client *client, int treble) -{ - int val = ((treble-32768) * 0x60 / 65535) << 8; + msp_dbg1("mute=%s volume=%d balance=%d bass=%d treble=%d\n", + state->muted ? "on" : "off", state->volume, state->balance, + state->bass, state->treble); - msp_dbg1("settreble: %d 0x%02x\n",treble, val>>8); - msp_write_dsp(client, 0x0003, val); /* loudspeaker */ + msp_write_dsp(client, 0x0000, val); /* loudspeaker */ + msp_write_dsp(client, 0x0006, val); /* headphones */ + msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); + msp_write_dsp(client, 0x0001, bal << 8); + msp_write_dsp(client, 0x0002, bass); /* loudspeaker */ + msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ } static void msp3400c_setmode(struct i2c_client *client, int type) @@ -530,24 +521,24 @@ static void msp3400c_setmode(struct i2c_client *client, int type) state->rxsubchans = V4L2_TUNER_SUB_MONO; msp_write_dem(client, 0x00bb, /* ad_cv */ - msp_init_data[type].ad_cv); + msp3400c_init_data[type].ad_cv); for (i = 5; i >= 0; i--) /* fir 1 */ msp_write_dem(client, 0x0001, - msp_init_data[type].fir1[i]); + msp3400c_init_data[type].fir1[i]); msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ msp_write_dem(client, 0x0005, 0x0040); msp_write_dem(client, 0x0005, 0x0000); for (i = 5; i >= 0; i--) msp_write_dem(client, 0x0005, - msp_init_data[type].fir2[i]); + msp3400c_init_data[type].fir2[i]); msp_write_dem(client, 0x0083, /* MODE_REG */ - msp_init_data[type].mode_reg); + msp3400c_init_data[type].mode_reg); - msp3400c_setcarrier(client, msp_init_data[type].cdo1, - msp_init_data[type].cdo2); + msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1, + msp3400c_init_data[type].cdo2); msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ @@ -557,19 +548,19 @@ static void msp3400c_setmode(struct i2c_client *client, int type) msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ msp_write_dsp(client, 0x000b, - msp_init_data[type].dfp_src); + msp3400c_init_data[type].dfp_src); } else { msp_write_dsp(client, 0x0008, - msp_init_data[type].dfp_src); + msp3400c_init_data[type].dfp_src); msp_write_dsp(client, 0x0009, - msp_init_data[type].dfp_src); + msp3400c_init_data[type].dfp_src); msp_write_dsp(client, 0x000b, - msp_init_data[type].dfp_src); + msp3400c_init_data[type].dfp_src); } msp_write_dsp(client, 0x000a, - msp_init_data[type].dfp_src); + msp3400c_init_data[type].dfp_src); msp_write_dsp(client, 0x000e, - msp_init_data[type].dfp_matrix); + msp3400c_init_data[type].dfp_matrix); if (HAVE_NICAM(state)) { /* nicam prescale */ @@ -701,8 +692,7 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) } } -static void -msp3400c_print_mode(struct i2c_client *client) +static void msp3400c_print_mode(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); @@ -739,7 +729,7 @@ static void msp3400c_restore_dfp(struct i2c_client *client) } /* if the dfp_regs is set, set what's in there. Otherwise, set the default value */ -static int msp_write_dfp_with_default(struct i2c_client *client, +static int msp34xxg_write_dfp_with_default(struct i2c_client *client, int addr, int default_value) { struct msp_state *state = i2c_get_clientdata(client); @@ -751,19 +741,6 @@ static int msp_write_dfp_with_default(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -struct REGISTER_DUMP { - int addr; - char *name; -}; - -struct REGISTER_DUMP d1[] = { - {0x007e, "autodetect"}, - {0x0023, "C_AD_BITS "}, - {0x0038, "ADD_BITS "}, - {0x003e, "CIB_BITS "}, - {0x0057, "ERROR_RATE"}, -}; - static int autodetect_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); @@ -899,7 +876,7 @@ static int msp3400c_thread(void *data) { struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); - struct CARRIER_DETECT *cd; + struct msp3400c_carrier_detect *cd; int count, max1,max2,val1,val2, val,this; @@ -919,12 +896,12 @@ static int msp3400c_thread(void *data) MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ msp_info("thread: no carrier scan\n"); - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); continue; } /* mute */ - msp_set_volume(client, state->muted, 0, 0); + msp_set_mute(client); msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; @@ -935,8 +912,8 @@ static int msp3400c_thread(void *data) goto restart; /* carrier detect pass #1 -- main carrier */ - cd = carrier_detect_main; - count = CARRIER_COUNT(carrier_detect_main); + cd = msp3400c_carrier_detect_main; + count = ARRAY_SIZE(msp3400c_carrier_detect_main); if (amsound && (state->norm == VIDEO_MODE_SECAM)) { /* autodetect doesn't work well with AM ... */ @@ -960,12 +937,12 @@ static int msp3400c_thread(void *data) /* carrier detect pass #2 -- second (stereo) carrier */ switch (max1) { case 1: /* 5.5 */ - cd = carrier_detect_55; - count = CARRIER_COUNT(carrier_detect_55); + cd = msp3400c_carrier_detect_55; + count = ARRAY_SIZE(msp3400c_carrier_detect_55); break; case 3: /* 6.5 */ - cd = carrier_detect_65; - count = CARRIER_COUNT(carrier_detect_65); + cd = msp3400c_carrier_detect_65; + count = ARRAY_SIZE(msp3400c_carrier_detect_65); break; case 0: /* 4.5 */ case 2: /* 6.0 */ @@ -994,19 +971,19 @@ static int msp3400c_thread(void *data) } /* program the msp3400 according to the results */ - state->main = carrier_detect_main[max1].cdo; + state->main = msp3400c_carrier_detect_main[max1].cdo; switch (max1) { case 1: /* 5.5 */ if (max2 == 0) { /* B/G FM-stereo */ - state->second = carrier_detect_55[max2].cdo; + state->second = msp3400c_carrier_detect_55[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_TERRA); state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); state->watch_stereo = 1; } else if (max2 == 1 && HAVE_NICAM(state)) { /* B/G NICAM */ - state->second = carrier_detect_55[max2].cdo; + state->second = msp3400c_carrier_detect_55[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_NICAM1); state->nicam_on = 1; msp3400c_setcarrier(client, state->second, state->main); @@ -1026,7 +1003,7 @@ static int msp3400c_thread(void *data) case 3: /* 6.5 */ if (max2 == 1 || max2 == 2) { /* D/K FM-stereo */ - state->second = carrier_detect_65[max2].cdo; + state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_TERRA); state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); @@ -1034,7 +1011,7 @@ static int msp3400c_thread(void *data) } else if (max2 == 0 && state->norm == VIDEO_MODE_SECAM) { /* L NICAM or AM-mono */ - state->second = carrier_detect_65[max2].cdo; + state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_AM_NICAM); state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); @@ -1044,7 +1021,7 @@ static int msp3400c_thread(void *data) state->watch_stereo = 1; } else if (max2 == 0 && HAVE_NICAM(state)) { /* D/K NICAM */ - state->second = carrier_detect_65[max2].cdo; + state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_FM_NICAM1); state->nicam_on = 1; msp3400c_setcarrier(client, state->second, state->main); @@ -1056,7 +1033,7 @@ static int msp3400c_thread(void *data) case 0: /* 4.5 */ default: no_second: - state->second = carrier_detect_main[max1].cdo; + state->second = msp3400c_carrier_detect_main[max1].cdo; msp3400c_setmode(client, MSP_MODE_FM_TERRA); state->nicam_on = 0; msp3400c_setcarrier(client, state->second, state->main); @@ -1066,7 +1043,7 @@ static int msp3400c_thread(void *data) } /* unmute */ - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); msp3400c_restore_dfp(client); if (debug) @@ -1191,7 +1168,7 @@ static int msp3410d_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ msp_dbg1("thread: no carrier scan\n"); - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); continue; } @@ -1311,9 +1288,7 @@ static int msp3410d_thread(void *data) } /* unmute, restore misc registers */ - msp_set_bass(client, state->bass); - msp_set_treble(client, state->treble); - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); msp_write_dsp(client, 0x13, state->acb); msp_write_dem(client, 0x40, state->i2s_mode); msp3400c_restore_dfp(client); @@ -1335,7 +1310,40 @@ static int msp3410d_thread(void *data) /* select which are available in the newer G versions */ /* struct msp: only norm, acb and source are really used in this mode */ -static void msp34xxg_set_source(struct i2c_client *client, int source); +/* set the same 'source' for the loudspeaker, scart and quasi-peak detector + * the value for source is the same as bit 15:8 of DFP registers 0x08, + * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B + * + * this function replaces msp3400c_setstereo + */ +static void msp34xxg_set_source(struct i2c_client *client, int source) +{ + struct msp_state *state = i2c_get_clientdata(client); + + /* fix matrix mode to stereo and let the msp choose what + * to output according to 'source', as recommended + * for MONO (source==0) downmixing set bit[7:0] to 0x30 + */ + int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20); + + msp_dbg1("set source to %d (0x%x)\n", source, value); + /* Loudspeaker Output */ + msp_write_dsp(client, 0x08, value); + /* SCART1 DA Output */ + msp_write_dsp(client, 0x0a, value); + /* Quasi-peak detector */ + msp_write_dsp(client, 0x0c, value); + /* + * set identification threshold. Personally, I + * I set it to a higher value that the default + * of 0x190 to ignore noisy stereo signals. + * this needs tuning. (recommended range 0x00a0-0x03c0) + * 0x7f0 = forced mono mode + */ + /* a2 threshold for stereo/bilingual */ + msp_write_dem(client, 0x22, stereo_threshold); + state->source = source; +} /* (re-)initialize the msp34xxg, according to the current norm in state->norm * return 0 if it worked, -1 if it failed @@ -1343,15 +1351,14 @@ static void msp34xxg_set_source(struct i2c_client *client, int source); static int msp34xxg_reset(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int modus,std; + int modus, std; if (msp_reset(client)) return -1; /* make sure that input/output is muted (paranoid mode) */ - if (msp_write_dsp(client, - 0x13, /* ACB */ - 0x0f20 /* mute DSP input, mute SCART 1 */)) + /* ACB, mute DSP input, mute SCART 1 */ + if (msp_write_dsp(client, 0x13, 0x0f20)) return -1; msp_write_dem(client, 0x40, state->i2s_mode); @@ -1359,27 +1366,23 @@ static int msp34xxg_reset(struct i2c_client *client) /* step-by-step initialisation, as described in the manual */ modus = msp_modus(client, state->norm); std = msp_standard(state->norm); - modus &= ~0x03; /* STATUS_CHANGE=0 */ - modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */ - if (msp_write_dem(client, 0x30/*MODUS*/, modus)) + modus &= ~0x03; /* STATUS_CHANGE = 0 */ + modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ + if (msp_write_dem(client, 0x30, modus)) return -1; - if (msp_write_dem(client, 0x20/*standard*/, std)) + if (msp_write_dem(client, 0x20, std)) return -1; /* write the dfps that may have an influence on standard/audio autodetection right now */ msp34xxg_set_source(client, state->source); - if (msp_write_dfp_with_default(client, 0x0e, /* AM/FM Prescale */ - 0x3000 - /* default: [15:8] 75khz deviation */ - )) + /* AM/FM Prescale, default: [15:8] 75khz deviation */ + if (msp34xxg_write_dfp_with_default(client, 0x0e, 0x3000)) return -1; - if (msp_write_dfp_with_default(client, 0x10, /* NICAM Prescale */ - 0x5a00 - /* default: 9db gain (as recommended) */ - )) + /* NICAM Prescale, default: 9db gain (as recommended) */ + if (msp34xxg_write_dfp_with_default(client, 0x10, 0x5a00)) return -1; return 0; @@ -1396,7 +1399,7 @@ static int msp34xxg_thread(void *data) state->source = 1; /* default */ for (;;) { msp_dbg2("msp34xxg thread: sleep\n"); - msp_sleep(state,-1); + msp_sleep(state, -1); msp_dbg2("msp34xxg thread: wakeup\n"); restart: @@ -1414,7 +1417,7 @@ static int msp34xxg_thread(void *data) /* watch autodetect */ msp_dbg1("triggered autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { - if (msp_sleep(state,100)) + if (msp_sleep(state, 100)) goto restart; /* check results */ @@ -1425,7 +1428,7 @@ static int msp34xxg_thread(void *data) } msp_dbg1("detection still in progress\n"); } - if (0x01 == std) { + if (std == 1) { msp_dbg1("detection still in progress after 10 tries. giving up.\n"); continue; } @@ -1436,11 +1439,7 @@ static int msp34xxg_thread(void *data) msp_standard_mode_name(std), std); /* unmute: dispatch sound to scart output, set scart volume */ - msp_dbg1("unmute\n"); - - msp_set_bass(client, state->bass); - msp_set_treble(client, state->treble); - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); /* restore ACB */ if (msp_write_dsp(client, 0x13, state->acb)) @@ -1452,52 +1451,13 @@ static int msp34xxg_thread(void *data) return 0; } -/* set the same 'source' for the loudspeaker, scart and quasi-peak detector - * the value for source is the same as bit 15:8 of DFP registers 0x08, - * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B - * - * this function replaces msp3400c_setstereo - */ -static void msp34xxg_set_source(struct i2c_client *client, int source) -{ - struct msp_state *state = i2c_get_clientdata(client); - - /* fix matrix mode to stereo and let the msp choose what - * to output according to 'source', as recommended - * for MONO (source==0) downmixing set bit[7:0] to 0x30 - */ - int value = (source&0x07)<<8|(source==0 ? 0x30:0x20); - msp_dbg1("set source to %d (0x%x)\n", source, value); - msp_write_dsp(client, - 0x08, /* Loudspeaker Output */ - value); - msp_write_dsp(client, - 0x0a, /* SCART1 DA Output */ - value); - msp_write_dsp(client, - 0x0c, /* Quasi-peak detector */ - value); - /* - * set identification threshold. Personally, I - * I set it to a higher value that the default - * of 0x190 to ignore noisy stereo signals. - * this needs tuning. (recommended range 0x00a0-0x03c0) - * 0x7f0 = forced mono mode - */ - msp_write_dem(client, - 0x22, /* a2 threshold for stereo/bilingual */ - stereo_threshold); - state->source=source; -} - static void msp34xxg_detect_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int status = msp_read_dem(client, - 0x0200 /* STATUS */); - int is_bilingual = status&0x100; - int is_stereo = status&0x40; + int status = msp_read_dem(client, 0x0200); + int is_bilingual = status & 0x100; + int is_stereo = status & 0x40; state->rxsubchans = 0; if (is_stereo) @@ -1505,7 +1465,7 @@ static void msp34xxg_detect_stereo(struct i2c_client *client) else state->rxsubchans |= V4L2_TUNER_SUB_MONO; if (is_bilingual) { - state->rxsubchans |= V4L2_TUNER_SUB_LANG1|V4L2_TUNER_SUB_LANG2; + state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; /* I'm supposed to check whether it's SAP or not * and set only LANG2/SAP in this case. Yet, the MSP * does a lot of work to hide this and handle everything @@ -1524,17 +1484,17 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) switch (audmode) { case V4L2_TUNER_MODE_MONO: - source=0; /* mono only */ + source = 0; /* mono only */ break; case V4L2_TUNER_MODE_STEREO: - source=1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ + source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ /* problem: that could also mean 2 (scart input) */ break; case V4L2_TUNER_MODE_LANG1: - source=3; /* stereo or A */ + source = 3; /* stereo or A */ break; case V4L2_TUNER_MODE_LANG2: - source=4; /* stereo or B */ + source = 4; /* stereo or B */ break; default: audmode = 0; @@ -1550,11 +1510,11 @@ static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) static void msp_wake_thread(struct i2c_client *client) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); if (NULL == state->kthread) return; - msp_set_volume(client,state->muted,0,0); + msp_set_mute(client); state->watch_stereo = 0; state->restart = 1; wake_up_interruptible(&state->wq); @@ -1572,7 +1532,7 @@ static int mode_v4l2_to_v4l1(int rxsubchans) mode |= VIDEO_SOUND_LANG2; if (rxsubchans & V4L2_TUNER_SUB_LANG1) mode |= VIDEO_SOUND_LANG1; - if (0 == mode) + if (mode == 0) mode |= VIDEO_SOUND_MONO; return mode; } @@ -1644,7 +1604,7 @@ static struct v4l2_queryctrl msp_qctrl[] = { static void msp_any_set_audmode(struct i2c_client *client, int audmode) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); switch (state->opmode) { case OPMODE_MANUAL: @@ -1660,94 +1620,68 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode) static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = i2c_get_clientdata(client); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = state->muted; - return 0; + break; + case V4L2_CID_AUDIO_BALANCE: - { - int volume = max(state->left, state->right); - - ctrl->value = (32768 * min(state->left, state->right)) / - (volume ? volume : 1); - ctrl->value = (state->left < state->right) ? - (65535 - ctrl->value) : ctrl->value; - if (0 == volume) - ctrl->value = 32768; - return 0; - } + ctrl->value = state->balance; + break; + case V4L2_CID_AUDIO_BASS: ctrl->value = state->bass; - return 0; + break; + case V4L2_CID_AUDIO_TREBLE: ctrl->value = state->treble; - return 0; + break; + case V4L2_CID_AUDIO_VOLUME: - ctrl->value = max(state->left, state->right); - return 0; + ctrl->value = state->volume; + break; + default: return -EINVAL; } + return 0; } static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { struct msp_state *state = i2c_get_clientdata(client); - int set_volume = 0, balance, volume; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value < 0 || ctrl->value >= 2) return -ERANGE; state->muted = ctrl->value; - msp_set_volume(client, state->muted, state->left, state->right); - return 0; - - case V4L2_CID_AUDIO_BALANCE: - balance = ctrl->value; - volume = max(state->left, state->right); - set_volume = 1; break; case V4L2_CID_AUDIO_BASS: state->bass = ctrl->value; - msp_set_bass(client, state->bass); - return 0; + break; case V4L2_CID_AUDIO_TREBLE: state->treble = ctrl->value; - msp_set_treble(client, state->treble); - return 0; - - case V4L2_CID_AUDIO_VOLUME: - volume = max(state->left, state->right); + break; - balance = (32768 * min(state->left, state->right)) / - (volume ? volume : 1); - balance = (state->left < state->right) ? - (65535 - balance) : balance; - if (volume == 0) - balance = 32768; + case V4L2_CID_AUDIO_BALANCE: + state->balance = ctrl->value; + break; - volume = ctrl->value; - set_volume = 1; + case V4L2_CID_AUDIO_VOLUME: + state->volume = ctrl->value; + if (state->volume == 0) + state->balance = 32768; break; default: return -EINVAL; } - - if (set_volume) { - state->left = (min(65536 - balance, 32768) * volume) / 32768; - state->right = (min(balance, 32768) * volume) / 32768; - - msp_dbg2("volume=%d, balance=%d, left=%d, right=%d", - volume, balance, state->left, state->right); - - msp_set_volume(client, state->muted, state->left, state->right); - } + msp_set_audio(client); return 0; } @@ -1757,10 +1691,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) u16 *sarg = arg; int scart = 0; + if (debug >= 2) + v4l_i2c_print_ioctl(client, cmd); + switch (cmd) { case AUDC_SET_INPUT: - msp_dbg1("AUDC_SET_INPUT(%d)\n",*sarg); - if (*sarg == state->input) break; state->input = *sarg; @@ -1800,7 +1735,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; case AUDC_SET_RADIO: - msp_dbg1("AUDC_SET_RADIO\n"); state->norm = VIDEO_MODE_RADIO; msp_dbg1("switching to radio mode\n"); state->watch_stereo = 0; @@ -1810,7 +1744,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp3400c_setmode(client, MSP_MODE_FM_RADIO); msp3400c_setcarrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); break; case OPMODE_AUTODETECT: case OPMODE_AUTOSELECT: @@ -1852,7 +1786,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_audio *va = arg; - msp_dbg1("VIDIOCGAUDIO\n"); va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE | @@ -1862,13 +1795,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (state->muted) va->flags |= VIDEO_AUDIO_MUTE; - va->volume = max(state->left, state->right); - va->balance = (32768 * min(state->left, state->right)) / - (va->volume ? va->volume : 1); - va->balance = (state->left < state->right) ? - (65535 - va->balance) : va->balance; - if (0 == va->volume) - va->balance = 32768; + va->volume = state->volume; + va->balance = state->volume ? state->balance : 32768; va->bass = state->bass; va->treble = state->treble; @@ -1881,19 +1809,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_audio *va = arg; - msp_dbg1("VIDIOCSAUDIO\n"); state->muted = (va->flags & VIDEO_AUDIO_MUTE); - state->left = (min(65536 - va->balance, 32768) * - va->volume) / 32768; - state->right = (min((int)va->balance, 32768) * va->volume) / 32768; + state->volume = va->volume; + state->balance = va->balance; state->bass = va->bass; state->treble = va->treble; - msp_dbg1("vol %d, bal %d, flags %x, left %d, right %d, bass %d, treble %d, mode %x\n", - va->volume, va->balance, va->flags, state->left, - state->right, state->bass, state->treble, state->mode); - msp_set_volume(client, state->muted, state->left, state->right); - msp_set_bass(client, state->bass); - msp_set_treble(client, state->treble); + msp_set_audio(client); if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode)); @@ -1904,7 +1825,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_channel *vc = arg; - msp_dbg1("VIDIOCSCHAN (norm=%d)\n",vc->norm); state->norm = vc->norm; msp_wake_thread(client); break; @@ -1914,7 +1834,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_S_FREQUENCY: { /* new channel -- kick audio carrier scan */ - msp_dbg1("VIDIOCSFREQ\n"); msp_wake_thread(client); break; } @@ -1924,7 +1843,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct msp_matrix *mspm = arg; - msp_dbg1("MSP_SET_MATRIX\n"); msp_set_scart(client, mspm->input, mspm->output); break; } @@ -1936,11 +1854,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ if (*id & V4L2_STD_PAL) { - state->norm=VIDEO_MODE_PAL; + state->norm = VIDEO_MODE_PAL; } else if (*id & V4L2_STD_SECAM) { - state->norm=VIDEO_MODE_SECAM; + state->norm = VIDEO_MODE_SECAM; } else { - state->norm=VIDEO_MODE_NTSC; + state->norm = VIDEO_MODE_NTSC; } msp_wake_thread(client); @@ -1957,16 +1875,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) i->type = V4L2_INPUT_TYPE_TUNER; switch (i->index) { case AUDIO_RADIO: - strcpy(i->name,"Radio"); + strcpy(i->name, "Radio"); break; case AUDIO_EXTERN_1: - strcpy(i->name,"Extern 1"); + strcpy(i->name, "Extern 1"); break; case AUDIO_EXTERN_2: - strcpy(i->name,"Extern 2"); + strcpy(i->name, "Extern 2"); break; case AUDIO_TUNER: - strcpy(i->name,"Television"); + strcpy(i->name, "Television"); break; default: return -EINVAL; @@ -1978,20 +1896,20 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_audio *a = arg; - memset(a,0,sizeof(*a)); + memset(a, 0, sizeof(*a)); switch (a->index) { case AUDIO_RADIO: - strcpy(a->name,"Radio"); + strcpy(a->name, "Radio"); break; case AUDIO_EXTERN_1: - strcpy(a->name,"Extern 1"); + strcpy(a->name, "Extern 1"); break; case AUDIO_EXTERN_2: - strcpy(a->name,"Extern 2"); + strcpy(a->name, "Extern 2"); break; case AUDIO_TUNER: - strcpy(a->name,"Television"); + strcpy(a->name, "Television"); break; default: return -EINVAL; @@ -1999,7 +1917,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp_any_detect_stereo(client); if (state->audmode == V4L2_TUNER_MODE_STEREO) { - a->capability=V4L2_AUDCAP_STEREO; + a->capability = V4L2_AUDCAP_STEREO; } break; @@ -2032,10 +1950,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (scart) { state->rxsubchans = V4L2_TUNER_SUB_STEREO; state->audmode = V4L2_TUNER_MODE_STEREO; - msp_set_scart(client,scart,0); - msp_write_dsp(client,0x000d,0x1900); + msp_set_scart(client, scart, 0); + msp_write_dsp(client, 0x000d, 0x1900); } - if (sarg->capability==V4L2_AUDCAP_STEREO) { + if (sarg->capability == V4L2_AUDCAP_STEREO) { state->audmode = V4L2_TUNER_MODE_STEREO; } else { state->audmode &= ~V4L2_TUNER_MODE_STEREO; @@ -2053,14 +1971,13 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->audmode = state->audmode; vt->rxsubchans = state->rxsubchans; vt->capability = V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1| - V4L2_TUNER_CAP_LANG2; + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; break; } case VIDIOC_S_TUNER: { - struct v4l2_tuner *vt=(struct v4l2_tuner *)arg; + struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; /* only set audmode */ if (vt->audmode != -1 && vt->audmode != 0) @@ -2070,20 +1987,20 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_G_AUDOUT: { - struct v4l2_audioout *a=(struct v4l2_audioout *)arg; - int idx=a->index; + struct v4l2_audioout *a = (struct v4l2_audioout *)arg; + int idx = a->index; - memset(a,0,sizeof(*a)); + memset(a, 0, sizeof(*a)); switch (idx) { case 0: - strcpy(a->name,"Scart1 Out"); + strcpy(a->name, "Scart1 Out"); break; case 1: - strcpy(a->name,"Scart2 Out"); + strcpy(a->name, "Scart2 Out"); break; case 2: - strcpy(a->name,"I2S Out"); + strcpy(a->name, "I2S Out"); break; default: return -EINVAL; @@ -2094,29 +2011,29 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_S_AUDOUT: { - struct v4l2_audioout *a=(struct v4l2_audioout *)arg; + struct v4l2_audioout *a = (struct v4l2_audioout *)arg; - if (a->index<0||a->index>2) + if (a->index < 0 || a->index > 2) return -EINVAL; - msp_dbg1("Setting audio out on msp34xx to input %i\n",a->index); - msp_set_scart(client,state->in_scart,a->index+1); + msp_dbg1("Setting audio out on msp34xx to input %i\n", a->index); + msp_set_scart(client, state->in_scart, a->index + 1); break; } case VIDIOC_INT_I2S_CLOCK_FREQ: { - u32 *a=(u32 *)arg; + u32 *a = (u32 *)arg; - msp_dbg1("Setting I2S speed to %d\n",*a); + msp_dbg1("Setting I2S speed to %d\n", *a); switch (*a) { case 1024000: - state->i2s_mode=0; + state->i2s_mode = 0; break; case 2048000: - state->i2s_mode=1; + state->i2s_mode = 1; break; default: return -EINVAL; @@ -2129,41 +2046,26 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; int i; - msp_dbg1("VIDIOC_QUERYCTRL\n"); - for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) - if (qc->id && qc->id == msp_qctrl[i].id) { - memcpy(qc, &(msp_qctrl[i]), - sizeof(*qc)); + if (qc->id && qc->id == msp_qctrl[i].id) { + memcpy(qc, &msp_qctrl[i], sizeof(*qc)); return 0; } - return -EINVAL; } case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - msp_dbg1("VIDIOC_G_CTRL\n"); - - return msp_get_ctrl(client, ctrl); - } + return msp_get_ctrl(client, arg); case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - msp_dbg1("VIDIOC_S_CTRL\n"); - - return msp_set_ctrl(client, ctrl); - } + return msp_set_ctrl(client, arg); case VIDIOC_LOG_STATUS: msp_any_detect_stereo(client); msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", client->name, state->rev1, state->rev2); - msp_info("Volume: left %d right %d bass %d treble %d%s\n", - state->left, state->right, + msp_info("Audio: volume %d balance %d bass %d treble %d%s\n", + state->volume, state->balance, state->bass, state->treble, state->muted ? " (muted)" : ""); msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), @@ -2233,8 +2135,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) memset(state, 0, sizeof(*state)); state->norm = VIDEO_MODE_NTSC; - state->left = 58880; /* 0db gain */ - state->right = 58880; /* 0db gain */ + state->volume = 58880; /* 0db gain */ + state->balance = 32768; /* 0db gain */ state->bass = 32768; state->treble = 32768; state->input = -1; @@ -2255,7 +2157,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) return -1; } - msp_set_volume(client, state->muted, state->left, state->right); + msp_set_audio(client); snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", ((state->rev1 >> 4) & 0x0f) + '3', @@ -2308,7 +2210,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) if (thread_func) { state->kthread = kthread_run(thread_func, client, "msp34xx"); - if (NULL == state->kthread) + if (state->kthread == NULL) msp_warn("kernel_thread() failed\n"); msp_wake_thread(client); } -- cgit v1.2.3 From 53b0a1c60bcc167534b31f56adfbbe2919e6f80b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:39 -0200 Subject: V4L/DVB (3275): Split msp3400.c into msp3400-driver.c and msp3400-kthreads.c - Split msp3400.c into msp3400-driver.c and msp3400-kthreads.c. - Removed experimental DFPREG ioctls. If this is really needed one day then it should be implemented using VIDIOC_G/S_REGISTER. - Added missing BALANCE control info for VIDIOC_QUERYCTRL. - Still more cleanup, clarified some kernel messages. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 + drivers/media/video/msp3400-driver.c | 1144 +++++++++++++++++ drivers/media/video/msp3400.c | 2289 ---------------------------------- drivers/media/video/msp3400.h | 127 +- 4 files changed, 1266 insertions(+), 2296 deletions(-) create mode 100644 drivers/media/video/msp3400-driver.c delete mode 100644 drivers/media/video/msp3400.c diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 49aae8a54aa4..dd24896906fe 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -10,6 +10,8 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o +msp3400-objs := msp3400-driver.o msp3400-kthreads.o + obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c new file mode 100644 index 000000000000..de79c641583a --- /dev/null +++ b/drivers/media/video/msp3400-driver.c @@ -0,0 +1,1144 @@ +/* + * Programming the mspx4xx sound processor family + * + * (c) 1997-2001 Gerd Knorr + * + * what works and what doesn't: + * + * AM-Mono + * Support for Hauppauge cards added (decoding handled by tuner) added by + * Frederic Crozat + * + * FM-Mono + * should work. The stereo modes are backward compatible to FM-mono, + * therefore FM-Mono should be allways available. + * + * FM-Stereo (B/G, used in germany) + * should work, with autodetect + * + * FM-Stereo (satellite) + * should work, no autodetect (i.e. default is mono, but you can + * switch to stereo -- untested) + * + * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) + * should work, with autodetect. Support for NICAM was added by + * Pekka Pietikainen + * + * TODO: + * - better SAT support + * + * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) + * using soundcore instead of OSS + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msp3400.h" + +/* ---------------------------------------------------------------------- */ + +MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); + +/* module parameters */ +static int opmode = OPMODE_AUTO; +int debug = 0; /* debug output */ +int once = 0; /* no continous stereo monitoring */ +int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), + the autoscan seems work well only with FM... */ +int standard = 1; /* Override auto detect of audio standard, if needed. */ +int dolby = 0; + +int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual + (msp34xxg only) 0x00a0-0x03c0 */ + +/* read-only */ +module_param(opmode, int, 0444); + +/* read-write */ +module_param(once, int, 0644); +module_param(debug, int, 0644); +module_param(stereo_threshold, int, 0644); +module_param(standard, int, 0644); +module_param(amsound, int, 0644); +module_param(dolby, int, 0644); + +MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); +MODULE_PARM_DESC(once, "No continuous stereo monitoring"); +MODULE_PARM_DESC(debug, "Enable debug messages [0-3]"); +MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); +MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); +MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); +MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); + +/* ---------------------------------------------------------------------- */ + +/* control subaddress */ +#define I2C_MSP_CONTROL 0x00 +/* demodulator unit subaddress */ +#define I2C_MSP_DEM 0x10 +/* DSP unit subaddress */ +#define I2C_MSP_DSP 0x12 + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + + +/* ----------------------------------------------------------------------- */ +/* functions for talking to the MSP3400C Sound processor */ + +int msp_reset(struct i2c_client *client) +{ + /* reset and read revision code */ + static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; + static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; + static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; + u8 read[2]; + struct i2c_msg reset[2] = { + { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, + { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, + }; + struct i2c_msg test[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read }, + }; + + msp_dbg3("msp_reset\n"); + if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || + i2c_transfer(client->adapter, &reset[1], 1) != 1 || + i2c_transfer(client->adapter, test, 2) != 2) { + msp_err("chip reset failed\n"); + return -1; + } + return 0; +} + +static int msp_read(struct i2c_client *client, int dev, int addr) +{ + int err, retval; + u8 write[3]; + u8 read[2]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read } + }; + + write[0] = dev + 1; + write[1] = addr >> 8; + write[2] = addr & 0xff; + + for (err = 0; err < 3; err++) { + if (i2c_transfer(client->adapter, msgs, 2) == 2) + break; + msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, + dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(msecs_to_jiffies(10)); + } + if (err == 3) { + msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + msp_reset(client); + return -1; + } + retval = read[0] << 8 | read[1]; + msp_dbg3("msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); + return retval; +} + +int msp_read_dem(struct i2c_client *client, int addr) +{ + return msp_read(client, I2C_MSP_DEM, addr); +} + +int msp_read_dsp(struct i2c_client *client, int addr) +{ + return msp_read(client, I2C_MSP_DSP, addr); +} + +static int msp_write(struct i2c_client *client, int dev, int addr, int val) +{ + int err; + u8 buffer[5]; + + buffer[0] = dev; + buffer[1] = addr >> 8; + buffer[2] = addr & 0xff; + buffer[3] = val >> 8; + buffer[4] = val & 0xff; + + msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); + for (err = 0; err < 3; err++) { + if (i2c_master_send(client, buffer, 5) == 5) + break; + msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, + dev, addr); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(msecs_to_jiffies(10)); + } + if (err == 3) { + msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + msp_reset(client); + return -1; + } + return 0; +} + +int msp_write_dem(struct i2c_client *client, int addr, int val) +{ + return msp_write(client, I2C_MSP_DEM, addr, val); +} + +int msp_write_dsp(struct i2c_client *client, int addr, int val) +{ + return msp_write(client, I2C_MSP_DSP, addr, val); +} + +/* ----------------------------------------------------------------------- * + * bits 9 8 5 - SCART DSP input Select: + * 0 0 0 - SCART 1 to DSP input (reset position) + * 0 1 0 - MONO to DSP input + * 1 0 0 - SCART 2 to DSP input + * 1 1 1 - Mute DSP input + * + * bits 11 10 6 - SCART 1 Output Select: + * 0 0 0 - undefined (reset position) + * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) + * 1 0 0 - MONO input to SCART 1 Output + * 1 1 0 - SCART 1 DA to SCART 1 Output + * 0 0 1 - SCART 2 DA to SCART 1 Output + * 0 1 1 - SCART 1 Input to SCART 1 Output + * 1 1 1 - Mute SCART 1 Output + * + * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): + * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) + * 0 1 0 - SCART 1 Input to SCART 2 Output + * 1 0 0 - MONO input to SCART 2 Output + * 0 0 1 - SCART 2 DA to SCART 2 Output + * 0 1 1 - SCART 2 Input to SCART 2 Output + * 1 1 0 - Mute SCART 2 Output + * + * Bits 4 to 0 should be zero. + * ----------------------------------------------------------------------- */ + +static int scarts[3][9] = { + /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ + /* SCART DSP Input select */ + { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, + /* SCART1 Output select */ + { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, + /* SCART2 Output select */ + { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, +}; + +static char *scart_names[] = { + "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" +}; + +void msp_set_scart(struct i2c_client *client, int in, int out) +{ + struct msp_state *state = i2c_get_clientdata(client); + + state->in_scart=in; + + if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { + if (-1 == scarts[out][in]) + return; + + state->acb &= ~scarts[out][SCART_MASK]; + state->acb |= scarts[out][in]; + } else + state->acb = 0xf60; /* Mute Input and SCART 1 Output */ + + msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", + scart_names[in], out, state->acb); + msp_write_dsp(client, 0x13, state->acb); + + /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ + msp_write_dem(client, 0x40, state->i2s_mode); +} + +void msp_set_mute(struct i2c_client *client) +{ + msp_dbg1("mute audio\n"); + msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ + msp_write_dsp(client, 0x0006, 0); /* headphones */ +} + +void msp_set_audio(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + int val = 0, bal = 0, bass, treble; + + if (!state->muted) + val = (state->volume * 0x7f / 65535) << 8; + if (val) + bal = (state->balance / 256) - 128; + bass = ((state->bass - 32768) * 0x60 / 65535) << 8; + treble = ((state->treble - 32768) * 0x60 / 65535) << 8; + + msp_dbg1("mute=%s volume=%d balance=%d bass=%d treble=%d\n", + state->muted ? "on" : "off", state->volume, state->balance, + state->bass, state->treble); + + msp_write_dsp(client, 0x0000, val); /* loudspeaker */ + msp_write_dsp(client, 0x0006, val); /* headphones */ + msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); + msp_write_dsp(client, 0x0001, bal << 8); + msp_write_dsp(client, 0x0002, bass); /* loudspeaker */ + msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ +} + +int msp_modus(struct i2c_client *client, int norm) +{ + switch (norm) { + case VIDEO_MODE_PAL: + msp_dbg1("video mode selected to PAL\n"); + +#if 1 + /* experimental: not sure this works with all chip versions */ + return 0x7003; +#else + /* previous value, try this if it breaks ... */ + return 0x1003; +#endif + case VIDEO_MODE_NTSC: /* BTSC */ + msp_dbg1("video mode selected to NTSC\n"); + return 0x2003; + case VIDEO_MODE_SECAM: + msp_dbg1("video mode selected to SECAM\n"); + return 0x0003; + case VIDEO_MODE_RADIO: + msp_dbg1("video mode selected to Radio\n"); + return 0x0003; + case VIDEO_MODE_AUTO: + msp_dbg1("video mode selected to Auto\n"); + return 0x2003; + default: + return 0x0003; + } +} + +int msp_standard(int norm) +{ + switch (norm) { + case VIDEO_MODE_PAL: + return 1; + case VIDEO_MODE_NTSC: /* BTSC */ + return 0x0020; + case VIDEO_MODE_SECAM: + return 1; + case VIDEO_MODE_RADIO: + return 0x0040; + default: + return 1; + } +} + +/* ------------------------------------------------------------------------ */ + + +static void msp_wake_thread(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + if (NULL == state->kthread) + return; + msp_set_mute(client); + state->watch_stereo = 0; + state->restart = 1; + wake_up_interruptible(&state->wq); +} + +int msp_sleep(struct msp_state *state, int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&state->wq, &wait); + if (!kthread_should_stop()) { + if (timeout < 0) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } else { + schedule_timeout_interruptible + (msecs_to_jiffies(timeout)); + } + } + + remove_wait_queue(&state->wq, &wait); + try_to_freeze(); + return state->restart; +} + +/* ------------------------------------------------------------------------ */ + +static int msp_mode_v4l2_to_v4l1(int rxsubchans) +{ + int mode = 0; + + if (rxsubchans & V4L2_TUNER_SUB_STEREO) + mode |= VIDEO_SOUND_STEREO; + if (rxsubchans & V4L2_TUNER_SUB_LANG2) + mode |= VIDEO_SOUND_LANG2; + if (rxsubchans & V4L2_TUNER_SUB_LANG1) + mode |= VIDEO_SOUND_LANG1; + if (mode == 0) + mode |= VIDEO_SOUND_MONO; + return mode; +} + +static int msp_mode_v4l1_to_v4l2(int mode) +{ + if (mode & VIDEO_SOUND_STEREO) + return V4L2_TUNER_MODE_STEREO; + if (mode & VIDEO_SOUND_LANG2) + return V4L2_TUNER_MODE_LANG2; + if (mode & VIDEO_SOUND_LANG1) + return V4L2_TUNER_MODE_LANG1; + return V4L2_TUNER_MODE_MONO; +} + +static void msp_any_detect_stereo(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + switch (state->opmode) { + case OPMODE_MANUAL: + case OPMODE_AUTODETECT: + autodetect_stereo(client); + break; + case OPMODE_AUTOSELECT: + msp34xxg_detect_stereo(client); + break; + } +} + +static struct v4l2_queryctrl msp_qctrl[] = { + { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 58880, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_BALANCE, + .name = "Balance", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_AUDIO_BASS, + .name = "Bass", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_TREBLE, + .name = "Treble", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + }, +}; + + +static void msp_any_set_audmode(struct i2c_client *client, int audmode) +{ + struct msp_state *state = i2c_get_clientdata(client); + + switch (state->opmode) { + case OPMODE_MANUAL: + case OPMODE_AUTODETECT: + state->watch_stereo = 0; + msp3400c_setstereo(client, audmode); + break; + case OPMODE_AUTOSELECT: + msp34xxg_set_audmode(client, audmode); + break; + } +} + +static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct msp_state *state = i2c_get_clientdata(client); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = state->muted; + break; + + case V4L2_CID_AUDIO_BALANCE: + ctrl->value = state->balance; + break; + + case V4L2_CID_AUDIO_BASS: + ctrl->value = state->bass; + break; + + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = state->treble; + break; + + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = state->volume; + break; + + default: + return -EINVAL; + } + return 0; +} + +static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct msp_state *state = i2c_get_clientdata(client); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value < 0 || ctrl->value >= 2) + return -ERANGE; + state->muted = ctrl->value; + break; + + case V4L2_CID_AUDIO_BASS: + state->bass = ctrl->value; + break; + + case V4L2_CID_AUDIO_TREBLE: + state->treble = ctrl->value; + break; + + case V4L2_CID_AUDIO_BALANCE: + state->balance = ctrl->value; + break; + + case V4L2_CID_AUDIO_VOLUME: + state->volume = ctrl->value; + if (state->volume == 0) + state->balance = 32768; + break; + + default: + return -EINVAL; + } + msp_set_audio(client); + return 0; +} + +static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct msp_state *state = i2c_get_clientdata(client); + u16 *sarg = arg; + int scart = 0; + + if (debug >= 2) + v4l_i2c_print_ioctl(client, cmd); + + switch (cmd) { + case AUDC_SET_INPUT: + if (*sarg == state->input) + break; + state->input = *sarg; + switch (*sarg) { + case AUDIO_RADIO: + /* Hauppauge uses IN2 for the radio */ + state->mode = MSP_MODE_FM_RADIO; + scart = SCART_IN2; + break; + case AUDIO_EXTERN_1: + /* IN1 is often used for external input ... */ + state->mode = MSP_MODE_EXTERN; + scart = SCART_IN1; + break; + case AUDIO_EXTERN_2: + /* ... sometimes it is IN2 through ;) */ + state->mode = MSP_MODE_EXTERN; + scart = SCART_IN2; + break; + case AUDIO_TUNER: + state->mode = -1; + break; + default: + if (*sarg & AUDIO_MUTE) + msp_set_scart(client, SCART_MUTE, 0); + break; + } + if (scart) { + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; + msp_set_scart(client, scart, 0); + msp_write_dsp(client, 0x000d, 0x1900); + if (state->opmode != OPMODE_AUTOSELECT) + msp3400c_setstereo(client, state->audmode); + } + msp_wake_thread(client); + break; + + case AUDC_SET_RADIO: + state->norm = VIDEO_MODE_RADIO; + msp_dbg1("switching to radio mode\n"); + state->watch_stereo = 0; + switch (state->opmode) { + case OPMODE_MANUAL: + /* set msp3400 to FM radio mode */ + msp3400c_setmode(client, MSP_MODE_FM_RADIO); + msp3400c_setcarrier(client, MSP_CARRIER(10.7), + MSP_CARRIER(10.7)); + msp_set_audio(client); + break; + case OPMODE_AUTODETECT: + case OPMODE_AUTOSELECT: + /* the thread will do for us */ + msp_wake_thread(client); + break; + } + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE | + VIDEO_AUDIO_MUTABLE; + if (state->muted) + va->flags |= VIDEO_AUDIO_MUTE; + + if (state->muted) + va->flags |= VIDEO_AUDIO_MUTE; + va->volume = state->volume; + va->balance = state->volume ? state->balance : 32768; + va->bass = state->bass; + va->treble = state->treble; + + msp_any_detect_stereo(client); + va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans); + break; + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + state->muted = (va->flags & VIDEO_AUDIO_MUTE); + state->volume = va->volume; + state->balance = va->balance; + state->bass = va->bass; + state->treble = va->treble; + msp_set_audio(client); + + if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) + msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode)); + break; + } + + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + state->norm = vc->norm; + msp_wake_thread(client); + break; + } + + case VIDIOCSFREQ: + case VIDIOC_S_FREQUENCY: + { + /* new channel -- kick audio carrier scan */ + msp_wake_thread(client); + break; + } + + /* msp34xx specific */ + case MSP_SET_MATRIX: + { + struct msp_matrix *mspm = arg; + + msp_set_scart(client, mspm->input, mspm->output); + break; + } + + /* --- v4l2 ioctls --- */ + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + + /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ + if (*id & V4L2_STD_PAL) { + state->norm = VIDEO_MODE_PAL; + } else if (*id & V4L2_STD_SECAM) { + state->norm = VIDEO_MODE_SECAM; + } else { + state->norm = VIDEO_MODE_NTSC; + } + + msp_wake_thread(client); + return 0; + } + + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + + if (i->index != 0) + return -EINVAL; + + i->type = V4L2_INPUT_TYPE_TUNER; + switch (i->index) { + case AUDIO_RADIO: + strcpy(i->name, "Radio"); + break; + case AUDIO_EXTERN_1: + strcpy(i->name, "Extern 1"); + break; + case AUDIO_EXTERN_2: + strcpy(i->name, "Extern 2"); + break; + case AUDIO_TUNER: + strcpy(i->name, "Television"); + break; + default: + return -EINVAL; + } + return 0; + } + + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; + + memset(a, 0, sizeof(*a)); + + switch (a->index) { + case AUDIO_RADIO: + strcpy(a->name, "Radio"); + break; + case AUDIO_EXTERN_1: + strcpy(a->name, "Extern 1"); + break; + case AUDIO_EXTERN_2: + strcpy(a->name, "Extern 2"); + break; + case AUDIO_TUNER: + strcpy(a->name, "Television"); + break; + default: + return -EINVAL; + } + + msp_any_detect_stereo(client); + if (state->audmode == V4L2_TUNER_MODE_STEREO) { + a->capability = V4L2_AUDCAP_STEREO; + } + + break; + } + + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *sarg = arg; + + switch (sarg->index) { + case AUDIO_RADIO: + /* Hauppauge uses IN2 for the radio */ + state->mode = MSP_MODE_FM_RADIO; + scart = SCART_IN2; + break; + case AUDIO_EXTERN_1: + /* IN1 is often used for external input ... */ + state->mode = MSP_MODE_EXTERN; + scart = SCART_IN1; + break; + case AUDIO_EXTERN_2: + /* ... sometimes it is IN2 through ;) */ + state->mode = MSP_MODE_EXTERN; + scart = SCART_IN2; + break; + case AUDIO_TUNER: + state->mode = -1; + break; + } + if (scart) { + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; + msp_set_scart(client, scart, 0); + msp_write_dsp(client, 0x000d, 0x1900); + } + if (sarg->capability == V4L2_AUDCAP_STEREO) { + state->audmode = V4L2_TUNER_MODE_STEREO; + } else { + state->audmode &= ~V4L2_TUNER_MODE_STEREO; + } + msp_any_set_audmode(client, state->audmode); + msp_wake_thread(client); + break; + } + + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *vt = arg; + + msp_any_detect_stereo(client); + vt->audmode = state->audmode; + vt->rxsubchans = state->rxsubchans; + vt->capability = V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + break; + } + + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; + + /* only set audmode */ + if (vt->audmode != -1 && vt->audmode != 0) + msp_any_set_audmode(client, vt->audmode); + break; + } + + case VIDIOC_G_AUDOUT: + { + struct v4l2_audioout *a = (struct v4l2_audioout *)arg; + int idx = a->index; + + memset(a, 0, sizeof(*a)); + + switch (idx) { + case 0: + strcpy(a->name, "Scart1 Out"); + break; + case 1: + strcpy(a->name, "Scart2 Out"); + break; + case 2: + strcpy(a->name, "I2S Out"); + break; + default: + return -EINVAL; + } + break; + + } + + case VIDIOC_S_AUDOUT: + { + struct v4l2_audioout *a = (struct v4l2_audioout *)arg; + + if (a->index < 0 || a->index > 2) + return -EINVAL; + + msp_dbg1("Setting audio out on msp34xx to input %i\n", a->index); + msp_set_scart(client, state->in_scart, a->index + 1); + + break; + } + + case VIDIOC_INT_I2S_CLOCK_FREQ: + { + u32 *a = (u32 *)arg; + + msp_dbg1("Setting I2S speed to %d\n", *a); + + switch (*a) { + case 1024000: + state->i2s_mode = 0; + break; + case 2048000: + state->i2s_mode = 1; + break; + default: + return -EINVAL; + } + break; + } + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) + if (qc->id && qc->id == msp_qctrl[i].id) { + memcpy(qc, &msp_qctrl[i], sizeof(*qc)); + return 0; + } + return -EINVAL; + } + + case VIDIOC_G_CTRL: + return msp_get_ctrl(client, arg); + + case VIDIOC_S_CTRL: + return msp_set_ctrl(client, arg); + + case VIDIOC_LOG_STATUS: + msp_any_detect_stereo(client); + msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", + client->name, state->rev1, state->rev2); + msp_info("Audio: volume %d balance %d bass %d treble %d%s\n", + state->volume, state->balance, + state->bass, state->treble, + state->muted ? " (muted)" : ""); + msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), + (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", + (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); + msp_info("ACB: 0x%04x\n", state->acb); + break; + + default: + /* nothing */ + break; + } + return 0; +} + +static int msp_suspend(struct device * dev, pm_message_t state) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + msp_dbg1("suspend\n"); + msp_reset(client); + return 0; +} + +static int msp_resume(struct device * dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + msp_dbg1("resume\n"); + msp_wake_thread(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver; + +static int msp_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct msp_state *state; + int (*thread_func)(void *data) = NULL; + + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (client == NULL) + return -ENOMEM; + memset(client, 0, sizeof(*client)); + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + client->flags = I2C_CLIENT_ALLOW_USE; + snprintf(client->name, sizeof(client->name) - 1, "msp3400"); + + if (msp_reset(client) == -1) { + msp_dbg1("msp3400 not found\n"); + kfree(client); + return -1; + } + + state = kmalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + i2c_set_clientdata(client, state); + + memset(state, 0, sizeof(*state)); + state->norm = VIDEO_MODE_NTSC; + state->volume = 58880; /* 0db gain */ + state->balance = 32768; /* 0db gain */ + state->bass = 32768; + state->treble = 32768; + state->input = -1; + state->muted = 0; + state->i2s_mode = 0; + init_waitqueue_head(&state->wq); + + state->rev1 = msp_read_dsp(client, 0x1e); + if (state->rev1 != -1) + state->rev2 = msp_read_dsp(client, 0x1f); + msp_dbg1("rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); + if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { + msp_dbg1("not an msp3400 (cannot read chip version)\n"); + kfree(state); + kfree(client); + return -1; + } + + msp_set_audio(client); + + snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", + ((state->rev1 >> 4) & 0x0f) + '3', + (state->rev2 >> 8) & 0xff, + (state->rev1 & 0x0f) + '@', + ((state->rev1 >> 8) & 0xff) + '@', + state->rev2 & 0x1f); + + state->opmode = opmode; + if (state->opmode == OPMODE_AUTO) { + /* MSP revision G and up have both autodetect and autoselect */ + if ((state->rev1 & 0x0f) >= 'G'-'@') + state->opmode = OPMODE_AUTOSELECT; + /* MSP revision D and up have autodetect */ + else if ((state->rev1 & 0x0f) >= 'D'-'@') + state->opmode = OPMODE_AUTODETECT; + else + state->opmode = OPMODE_MANUAL; + } + + /* hello world :-) */ + msp_info("%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + msp_info("%s ", client->name); + if (HAVE_NICAM(state) && HAVE_RADIO(state)) + printk("supports nicam and radio, "); + else if (HAVE_NICAM(state)) + printk("supports nicam, "); + else if (HAVE_RADIO(state)) + printk("supports radio, "); + printk("mode is "); + + /* version-specific initialization */ + switch (state->opmode) { + case OPMODE_MANUAL: + printk("manual"); + thread_func = msp3400c_thread; + break; + case OPMODE_AUTODETECT: + printk("autodetect"); + thread_func = msp3410d_thread; + break; + case OPMODE_AUTOSELECT: + printk("autodetect and autoselect"); + thread_func = msp34xxg_thread; + break; + } + printk("\n"); + + /* startup control thread if needed */ + if (thread_func) { + state->kthread = kthread_run(thread_func, client, "msp34xx"); + + if (state->kthread == NULL) + msp_warn("kernel_thread() failed\n"); + msp_wake_thread(client); + } + + /* done */ + i2c_attach_client(client); + + return 0; +} + +static int msp_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, msp_attach); + return 0; +} + +static int msp_detach(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + int err; + + /* shutdown control thread */ + if (state->kthread) { + state->restart = 1; + kthread_stop(state->kthread); + } + msp_reset(client); + + err = i2c_detach_client(client); + if (err) { + return err; + } + + kfree(state); + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .id = I2C_DRIVERID_MSP3400, + .attach_adapter = msp_probe, + .detach_client = msp_detach, + .command = msp_command, + .driver = { + .name = "msp3400", + .suspend = msp_suspend, + .resume = msp_resume, + }, + .owner = THIS_MODULE, +}; + +static int __init msp3400_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit msp3400_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(msp3400_init_module); +module_exit(msp3400_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c deleted file mode 100644 index 627c3110d3e3..000000000000 --- a/drivers/media/video/msp3400.c +++ /dev/null @@ -1,2289 +0,0 @@ -/* - * programming the msp34* sound processor family - * - * (c) 1997-2001 Gerd Knorr - * - * what works and what doesn't: - * - * AM-Mono - * Support for Hauppauge cards added (decoding handled by tuner) added by - * Frederic Crozat - * - * FM-Mono - * should work. The stereo modes are backward compatible to FM-mono, - * therefore FM-Mono should be allways available. - * - * FM-Stereo (B/G, used in germany) - * should work, with autodetect - * - * FM-Stereo (satellite) - * should work, no autodetect (i.e. default is mono, but you can - * switch to stereo -- untested) - * - * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) - * should work, with autodetect. Support for NICAM was added by - * Pekka Pietikainen - * - * - * TODO: - * - better SAT support - * - * - * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) - * using soundcore instead of OSS - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "msp3400.h" - -/* ---------------------------------------------------------------------- */ - -MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -#define OPMODE_AUTO -1 -#define OPMODE_MANUAL 0 -#define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ -#define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ - -/* module parameters */ -static int opmode = OPMODE_AUTO; -static int debug = 0; /* debug output */ -static int once = 0; /* no continous stereo monitoring */ -static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), - the autoscan seems work well only with FM... */ -static int standard = 1; /* Override auto detect of audio standard, if needed. */ -static int dolby = 0; - -static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual - (msp34xxg only) 0x00a0-0x03c0 */ - -/* read-only */ -module_param(opmode, int, 0444); - -/* read-write */ -module_param(once, int, 0644); -module_param(debug, int, 0644); -module_param(stereo_threshold, int, 0644); -module_param(standard, int, 0644); -module_param(amsound, int, 0644); -module_param(dolby, int, 0644); - -MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); -MODULE_PARM_DESC(once, "No continuous stereo monitoring"); -MODULE_PARM_DESC(debug, "Enable debug messages"); -MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); -MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); -MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); -MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); - -/* ---------------------------------------------------------------------- */ - -#define msp3400_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define msp3400_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define msp3400_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - -/* level 1 debug. */ -#define msp_dbg1(fmt, arg...) \ - do { \ - if (debug) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -/* level 2 debug. */ -#define msp_dbg2(fmt, arg...) \ - do { \ - if (debug >= 2) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -/* level 3 debug. Use with care. */ -#define msp_dbg3(fmt, arg...) \ - do { \ - if (debug >= 16) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -/* control subaddress */ -#define I2C_MSP_CONTROL 0x00 -/* demodulator unit subaddress */ -#define I2C_MSP_DEM 0x10 -/* DSP unit subaddress */ -#define I2C_MSP_DSP 0x12 - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; ->>>>>>> remote - - -I2C_CLIENT_INSMOD; - -#define DFP_COUNT 0x41 -static const int bl_dfp[] = { - 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a, - 0x0b, 0x0d, 0x0e, 0x10 -}; - -#define HAVE_NICAM(state) (((state->rev2 >> 8) & 0xff) != 0) -#define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') - -struct msp_state { - int rev1, rev2; - - int opmode; - int mode; - int norm; - int stereo; - int nicam_on; - int acb; - int in_scart; - int i2s_mode; - int main, second; /* sound carrier */ - int input; - int source; /* see msp34xxg_set_source */ - - /* v4l2 */ - int audmode; - int rxsubchans; - - int muted; - int volume, balance; - int bass, treble; - - /* shadow register set */ - int dfp_regs[DFP_COUNT]; - - /* thread */ - struct task_struct *kthread; - wait_queue_head_t wq; - int restart:1; - int watch_stereo:1; -}; - -#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ - - -/* ----------------------------------------------------------------------- */ -/* functions for talking to the MSP3400C Sound processor */ - -static int msp_reset(struct i2c_client *client) -{ - /* reset and read revision code */ - static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; - static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; - static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; - u8 read[2]; - struct i2c_msg reset[2] = { - { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, - { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, - }; - struct i2c_msg test[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read }, - }; - - msp_dbg3("msp_reset\n"); - if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || - i2c_transfer(client->adapter, &reset[1], 1) != 1 || - i2c_transfer(client->adapter, test, 2) != 2) { - msp_err("chip reset failed\n"); - return -1; - } - return 0; -} - -static int msp_read(struct i2c_client *client, int dev, int addr) -{ - int err, retval; - u8 write[3]; - u8 read[2]; - struct i2c_msg msgs[2] = { - { client->addr, 0, 3, write }, - { client->addr, I2C_M_RD, 2, read } - }; - - write[0] = dev + 1; - write[1] = addr >> 8; - write[2] = addr & 0xff; - - for (err = 0; err < 3; err++) { - if (i2c_transfer(client->adapter, msgs, 2) == 2) - break; - msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, - dev, addr); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(msecs_to_jiffies(10)); - } - if (err == 3) { - msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); - msp_reset(client); - return -1; - } - retval = read[0] << 8 | read[1]; - msp_dbg3("msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); - return retval; -} - -static inline int msp_read_dem(struct i2c_client *client, int addr) -{ - return msp_read(client, I2C_MSP_DEM, addr); -} - -static inline int msp_read_dsp(struct i2c_client *client, int addr) -{ - return msp_read(client, I2C_MSP_DSP, addr); -} - -static int msp_write(struct i2c_client *client, int dev, int addr, int val) -{ - int err; - u8 buffer[5]; - - buffer[0] = dev; - buffer[1] = addr >> 8; - buffer[2] = addr & 0xff; - buffer[3] = val >> 8; - buffer[4] = val & 0xff; - - msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); - for (err = 0; err < 3; err++) { - if (i2c_master_send(client, buffer, 5) == 5) - break; - msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, - dev, addr); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(msecs_to_jiffies(10)); - } - if (err == 3) { - msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); - msp_reset(client); - return -1; - } - return 0; -} - -static inline int msp_write_dem(struct i2c_client *client, int addr, int val) -{ - return msp_write(client, I2C_MSP_DEM, addr, val); -} - -static inline int msp_write_dsp(struct i2c_client *client, int addr, int val) -{ - return msp_write(client, I2C_MSP_DSP, addr, val); -} - -/* ----------------------------------------------------------------------- * - * bits 9 8 5 - SCART DSP input Select: - * 0 0 0 - SCART 1 to DSP input (reset position) - * 0 1 0 - MONO to DSP input - * 1 0 0 - SCART 2 to DSP input - * 1 1 1 - Mute DSP input - * - * bits 11 10 6 - SCART 1 Output Select: - * 0 0 0 - undefined (reset position) - * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) - * 1 0 0 - MONO input to SCART 1 Output - * 1 1 0 - SCART 1 DA to SCART 1 Output - * 0 0 1 - SCART 2 DA to SCART 1 Output - * 0 1 1 - SCART 1 Input to SCART 1 Output - * 1 1 1 - Mute SCART 1 Output - * - * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): - * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) - * 0 1 0 - SCART 1 Input to SCART 2 Output - * 1 0 0 - MONO input to SCART 2 Output - * 0 0 1 - SCART 2 DA to SCART 2 Output - * 0 1 1 - SCART 2 Input to SCART 2 Output - * 1 1 0 - Mute SCART 2 Output - * - * Bits 4 to 0 should be zero. - * ----------------------------------------------------------------------- */ - -static int scarts[3][9] = { - /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ - /* SCART DSP Input select */ - { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, - /* SCART1 Output select */ - { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, - /* SCART2 Output select */ - { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, -}; - -static char *scart_names[] = { - "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" -}; - -static void msp_set_scart(struct i2c_client *client, int in, int out) -{ - struct msp_state *state = i2c_get_clientdata(client); - - state->in_scart=in; - - if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { - if (-1 == scarts[out][in]) - return; - - state->acb &= ~scarts[out][SCART_MASK]; - state->acb |= scarts[out][in]; - } else - state->acb = 0xf60; /* Mute Input and SCART 1 Output */ - - msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); - msp_write_dsp(client, 0x13, state->acb); - - /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ - msp_write_dem(client, 0x40, state->i2s_mode); -} - -/* ------------------------------------------------------------------------ */ - -/* This macro is allowed for *constants* only, gcc must calculate it - at compile time. Remember -- no floats in kernel mode */ -#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) - -#define MSP_MODE_AM_DETECT 0 -#define MSP_MODE_FM_RADIO 2 -#define MSP_MODE_FM_TERRA 3 -#define MSP_MODE_FM_SAT 4 -#define MSP_MODE_FM_NICAM1 5 -#define MSP_MODE_FM_NICAM2 6 -#define MSP_MODE_AM_NICAM 7 -#define MSP_MODE_BTSC 8 -#define MSP_MODE_EXTERN 9 - -static struct msp3400c_init_data_dem { - int fir1[6]; - int fir2[6]; - int cdo1; - int cdo2; - int ad_cv; - int mode_reg; - int dfp_src; - int dfp_matrix; -} msp3400c_init_data[] = { - { /* AM (for carrier detect / msp3400) */ - {75, 19, 36, 35, 39, 40}, - {75, 19, 36, 35, 39, 40}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0500, 0x0020, 0x3000 - },{ /* AM (for carrier detect / msp3410) */ - {-1, -1, -8, 2, 59, 126}, - {-1, -1, -8, 2, 59, 126}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0100, 0x0020, 0x3000 - },{ /* FM Radio */ - {-8, -8, 4, 6, 78, 107}, - {-8, -8, 4, 6, 78, 107}, - MSP_CARRIER(10.7), MSP_CARRIER(10.7), - 0x00d0, 0x0480, 0x0020, 0x3000 - },{ /* Terrestial FM-mono + FM-stereo */ - {3, 18, 27, 48, 66, 72}, - {3, 18, 27, 48, 66, 72}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0480, 0x0030, 0x3000 - },{ /* Sat FM-mono */ - { 1, 9, 14, 24, 33, 37}, - { 3, 18, 27, 48, 66, 72}, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0480, 0x0000, 0x3000 - },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ - {-2, -8, -10, 10, 50, 86}, - {3, 18, 27, 48, 66, 72}, - MSP_CARRIER(5.5), MSP_CARRIER(5.5), - 0x00d0, 0x0040, 0x0120, 0x3000 - },{ /* NICAM/FM -- I (6.0/6.552) */ - {2, 4, -6, -4, 40, 94}, - {3, 18, 27, 48, 66, 72}, - MSP_CARRIER(6.0), MSP_CARRIER(6.0), - 0x00d0, 0x0040, 0x0120, 0x3000 - },{ /* NICAM/AM -- L (6.5/5.85) */ - {-2, -8, -10, 10, 50, 86}, - {-4, -12, -9, 23, 79, 126}, - MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0140, 0x0120, 0x7c03 - }, -}; - -struct msp3400c_carrier_detect { - int cdo; - char *name; -}; - -static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { - /* main carrier */ - { MSP_CARRIER(4.5), "4.5 NTSC" }, - { MSP_CARRIER(5.5), "5.5 PAL B/G" }, - { MSP_CARRIER(6.0), "6.0 PAL I" }, - { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } -}; - -static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { - /* PAL B/G */ - { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, - { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } -}; - -static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { - /* PAL SAT / SECAM */ - { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, - { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, - { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, - { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, - { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, - { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, -}; - -/* ------------------------------------------------------------------------ */ - -static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) -{ - msp_write_dem(client, 0x0093, cdo1 & 0xfff); - msp_write_dem(client, 0x009b, cdo1 >> 12); - msp_write_dem(client, 0x00a3, cdo2 & 0xfff); - msp_write_dem(client, 0x00ab, cdo2 >> 12); - msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ -} - -static void msp_set_mute(struct i2c_client *client) -{ - msp_dbg1("mute audio\n"); - msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ - msp_write_dsp(client, 0x0006, 0); /* headphones */ -} - -static void msp_set_audio(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - int val = 0, bal = 0, bass, treble; - - if (!state->muted) - val = (state->volume * 0x7f / 65535) << 8; - if (val) - bal = (state->balance / 256) - 128; - bass = ((state->bass - 32768) * 0x60 / 65535) << 8; - treble = ((state->treble - 32768) * 0x60 / 65535) << 8; - - msp_dbg1("mute=%s volume=%d balance=%d bass=%d treble=%d\n", - state->muted ? "on" : "off", state->volume, state->balance, - state->bass, state->treble); - - msp_write_dsp(client, 0x0000, val); /* loudspeaker */ - msp_write_dsp(client, 0x0006, val); /* headphones */ - msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); - msp_write_dsp(client, 0x0001, bal << 8); - msp_write_dsp(client, 0x0002, bass); /* loudspeaker */ - msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ -} - -static void msp3400c_setmode(struct i2c_client *client, int type) -{ - struct msp_state *state = i2c_get_clientdata(client); - int i; - - msp_dbg1("setmode: %d\n",type); - state->mode = type; - state->audmode = V4L2_TUNER_MODE_MONO; - state->rxsubchans = V4L2_TUNER_SUB_MONO; - - msp_write_dem(client, 0x00bb, /* ad_cv */ - msp3400c_init_data[type].ad_cv); - - for (i = 5; i >= 0; i--) /* fir 1 */ - msp_write_dem(client, 0x0001, - msp3400c_init_data[type].fir1[i]); - - msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ - msp_write_dem(client, 0x0005, 0x0040); - msp_write_dem(client, 0x0005, 0x0000); - for (i = 5; i >= 0; i--) - msp_write_dem(client, 0x0005, - msp3400c_init_data[type].fir2[i]); - - msp_write_dem(client, 0x0083, /* MODE_REG */ - msp3400c_init_data[type].mode_reg); - - msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1, - msp3400c_init_data[type].cdo2); - - msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ - - if (dolby) { - msp_write_dsp(client, 0x0008, - 0x0520); /* I2S1 */ - msp_write_dsp(client, 0x0009, - 0x0620); /* I2S2 */ - msp_write_dsp(client, 0x000b, - msp3400c_init_data[type].dfp_src); - } else { - msp_write_dsp(client, 0x0008, - msp3400c_init_data[type].dfp_src); - msp_write_dsp(client, 0x0009, - msp3400c_init_data[type].dfp_src); - msp_write_dsp(client, 0x000b, - msp3400c_init_data[type].dfp_src); - } - msp_write_dsp(client, 0x000a, - msp3400c_init_data[type].dfp_src); - msp_write_dsp(client, 0x000e, - msp3400c_init_data[type].dfp_matrix); - - if (HAVE_NICAM(state)) { - /* nicam prescale */ - msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ - } -} - -/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */ -static int msp3400c_best_video_sound(int rxsubchans) -{ - if (rxsubchans & V4L2_TUNER_SUB_STEREO) - return V4L2_TUNER_MODE_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG1) - return V4L2_TUNER_MODE_LANG1; - if (rxsubchans & V4L2_TUNER_SUB_LANG2) - return V4L2_TUNER_MODE_LANG2; - return V4L2_TUNER_MODE_MONO; -} - -/* turn on/off nicam + stereo */ -static void msp3400c_setstereo(struct i2c_client *client, int mode) -{ - static char *strmode[] = { "0", "mono", "stereo", "3", - "lang1", "5", "6", "7", "lang2" - }; - struct msp_state *state = i2c_get_clientdata(client); - int nicam = 0; /* channel source: FM/AM or nicam */ - int src = 0; - - if (state->opmode == OPMODE_AUTOSELECT) { - /* this method would break everything, let's make sure - * it's never called - */ - msp_dbg1("setstereo called with mode=%d instead of set_source (ignored)\n", - mode); - return; - } - - /* switch demodulator */ - switch (state->mode) { - case MSP_MODE_FM_TERRA: - msp_dbg1("FM setstereo: %s\n", strmode[mode]); - msp3400c_setcarrier(client,state->second,state->main); - switch (mode) { - case V4L2_TUNER_MODE_STEREO: - msp_write_dsp(client, 0x000e, 0x3001); - break; - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - case V4L2_TUNER_MODE_LANG2: - msp_write_dsp(client, 0x000e, 0x3000); - break; - } - break; - case MSP_MODE_FM_SAT: - msp_dbg1("SAT setstereo: %s\n", strmode[mode]); - switch (mode) { - case V4L2_TUNER_MODE_MONO: - msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); - break; - case V4L2_TUNER_MODE_STEREO: - msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); - break; - case V4L2_TUNER_MODE_LANG1: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - case V4L2_TUNER_MODE_LANG2: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); - break; - } - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - msp_dbg1("NICAM setstereo: %s\n",strmode[mode]); - msp3400c_setcarrier(client,state->second,state->main); - if (state->nicam_on) - nicam=0x0100; - break; - case MSP_MODE_BTSC: - msp_dbg1("BTSC setstereo: %s\n",strmode[mode]); - nicam=0x0300; - break; - case MSP_MODE_EXTERN: - msp_dbg1("extern setstereo: %s\n",strmode[mode]); - nicam = 0x0200; - break; - case MSP_MODE_FM_RADIO: - msp_dbg1("FM-Radio setstereo: %s\n",strmode[mode]); - break; - default: - msp_dbg1("mono setstereo\n"); - return; - } - - /* switch audio */ - switch (msp3400c_best_video_sound(mode)) { - case V4L2_TUNER_MODE_STEREO: - src = 0x0020 | nicam; - break; - case V4L2_TUNER_MODE_MONO: - if (state->mode == MSP_MODE_AM_NICAM) { - msp_dbg1("switching to AM mono\n"); - /* AM mono decoding is handled by tuner, not MSP chip */ - /* SCART switching control register */ - msp_set_scart(client,SCART_MONO,0); - src = 0x0200; - break; - } - case V4L2_TUNER_MODE_LANG1: - src = 0x0000 | nicam; - break; - case V4L2_TUNER_MODE_LANG2: - src = 0x0010 | nicam; - break; - } - msp_dbg1("setstereo final source/matrix = 0x%x\n", src); - - if (dolby) { - msp_write_dsp(client, 0x0008,0x0520); - msp_write_dsp(client, 0x0009,0x0620); - msp_write_dsp(client, 0x000a,src); - msp_write_dsp(client, 0x000b,src); - } else { - msp_write_dsp(client, 0x0008,src); - msp_write_dsp(client, 0x0009,src); - msp_write_dsp(client, 0x000a,src); - msp_write_dsp(client, 0x000b,src); - } -} - -static void msp3400c_print_mode(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - if (state->main == state->second) { - msp_dbg1("mono sound carrier: %d.%03d MHz\n", - state->main/910000,(state->main/910)%1000); - } else { - msp_dbg1("main sound carrier: %d.%03d MHz\n", - state->main/910000,(state->main/910)%1000); - } - if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) - msp_dbg1("NICAM/FM carrier : %d.%03d MHz\n", - state->second/910000,(state->second/910)%1000); - if (state->mode == MSP_MODE_AM_NICAM) - msp_dbg1("NICAM/AM carrier : %d.%03d MHz\n", - state->second/910000,(state->second/910)%1000); - if (state->mode == MSP_MODE_FM_TERRA && - state->main != state->second) { - msp_dbg1("FM-stereo carrier : %d.%03d MHz\n", - state->second/910000,(state->second/910)%1000); - } -} - -static void msp3400c_restore_dfp(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - int i; - - for (i = 0; i < DFP_COUNT; i++) { - if (-1 == state->dfp_regs[i]) - continue; - msp_write_dsp(client, i, state->dfp_regs[i]); - } -} - -/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */ -static int msp34xxg_write_dfp_with_default(struct i2c_client *client, - int addr, int default_value) -{ - struct msp_state *state = i2c_get_clientdata(client); - int value = default_value; - if (addr < DFP_COUNT && -1 != state->dfp_regs[addr]) - value = state->dfp_regs[addr]; - return msp_write_dsp(client, addr, value); -} - -/* ----------------------------------------------------------------------- */ - -static int autodetect_stereo(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - int val; - int rxsubchans = state->rxsubchans; - int newnicam = state->nicam_on; - int update = 0; - - switch (state->mode) { - case MSP_MODE_FM_TERRA: - val = msp_read_dsp(client, 0x18); - if (val > 32767) - val -= 65536; - msp_dbg2("stereo detect register: %d\n",val); - if (val > 4096) { - rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - } else if (val < -4096) { - rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - } else { - rxsubchans = V4L2_TUNER_SUB_MONO; - } - newnicam = 0; - break; - case MSP_MODE_FM_NICAM1: - case MSP_MODE_FM_NICAM2: - case MSP_MODE_AM_NICAM: - val = msp_read_dem(client, 0x23); - msp_dbg2("nicam sync=%d, mode=%d\n", - val & 1, (val & 0x1e) >> 1); - - if (val & 1) { - /* nicam synced */ - switch ((val & 0x1e) >> 1) { - case 0: - case 8: - rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 1: - case 9: - rxsubchans = V4L2_TUNER_SUB_MONO - | V4L2_TUNER_SUB_LANG1; - break; - case 2: - case 10: - rxsubchans = V4L2_TUNER_SUB_MONO - | V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; - break; - default: - rxsubchans = V4L2_TUNER_SUB_MONO; - break; - } - newnicam=1; - } else { - newnicam = 0; - rxsubchans = V4L2_TUNER_SUB_MONO; - } - break; - case MSP_MODE_BTSC: - val = msp_read_dem(client, 0x200); - msp_dbg2("status=0x%x (pri=%s, sec=%s, %s%s%s)\n", - val, - (val & 0x0002) ? "no" : "yes", - (val & 0x0004) ? "no" : "yes", - (val & 0x0040) ? "stereo" : "mono", - (val & 0x0080) ? ", nicam 2nd mono" : "", - (val & 0x0100) ? ", bilingual/SAP" : ""); - rxsubchans = V4L2_TUNER_SUB_MONO; - if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO; - if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; - break; - } - if (rxsubchans != state->rxsubchans) { - update = 1; - msp_dbg1("watch: rxsubchans %d => %d\n", - state->rxsubchans,rxsubchans); - state->rxsubchans = rxsubchans; - } - if (newnicam != state->nicam_on) { - update = 1; - msp_dbg1("watch: nicam %d => %d\n", - state->nicam_on,newnicam); - state->nicam_on = newnicam; - } - return update; -} - -/* - * A kernel thread for msp3400 control -- we don't want to block the - * in the ioctl while doing the sound carrier & stereo detect - */ - -static int msp_sleep(struct msp_state *state, int timeout) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&state->wq, &wait); - if (!kthread_should_stop()) { - if (timeout < 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } else { - schedule_timeout_interruptible - (msecs_to_jiffies(timeout)); - } - } - - remove_wait_queue(&state->wq, &wait); - try_to_freeze(); - return state->restart; -} - -/* stereo/multilang monitoring */ -static void watch_stereo(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - if (autodetect_stereo(client)) { - if (state->stereo & V4L2_TUNER_MODE_STEREO) - msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO); - else if (state->stereo & VIDEO_SOUND_LANG1) - msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1); - else - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - } - - if (once) - state->watch_stereo = 0; -} - - -static int msp3400c_thread(void *data) -{ - struct i2c_client *client = data; - struct msp_state *state = i2c_get_clientdata(client); - struct msp3400c_carrier_detect *cd; - int count, max1,max2,val1,val2, val,this; - - - msp_info("msp3400 daemon started\n"); - for (;;) { - msp_dbg2("msp3400 thread: sleep\n"); - msp_sleep(state, -1); - msp_dbg2("msp3400 thread: wakeup\n"); - - restart: - msp_dbg1("thread: restart scan\n"); - state->restart = 0; - if (kthread_should_stop()) - break; - - if (VIDEO_MODE_RADIO == state->norm || - MSP_MODE_EXTERN == state->mode) { - /* no carrier scan, just unmute */ - msp_info("thread: no carrier scan\n"); - msp_set_audio(client); - continue; - } - - /* mute */ - msp_set_mute(client); - msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); - val1 = val2 = 0; - max1 = max2 = -1; - state->watch_stereo = 0; - - /* some time for the tuner to sync */ - if (msp_sleep(state,200)) - goto restart; - - /* carrier detect pass #1 -- main carrier */ - cd = msp3400c_carrier_detect_main; - count = ARRAY_SIZE(msp3400c_carrier_detect_main); - - if (amsound && (state->norm == VIDEO_MODE_SECAM)) { - /* autodetect doesn't work well with AM ... */ - max1 = 3; - count = 0; - msp_dbg1("AM sound override\n"); - } - - for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - if (msp_sleep(state,100)) - goto restart; - val = msp_read_dsp(client, 0x1b); - if (val > 32767) - val -= 65536; - if (val1 < val) - val1 = val, max1 = this; - msp_dbg1("carrier1 val: %5d / %s\n", val,cd[this].name); - } - - /* carrier detect pass #2 -- second (stereo) carrier */ - switch (max1) { - case 1: /* 5.5 */ - cd = msp3400c_carrier_detect_55; - count = ARRAY_SIZE(msp3400c_carrier_detect_55); - break; - case 3: /* 6.5 */ - cd = msp3400c_carrier_detect_65; - count = ARRAY_SIZE(msp3400c_carrier_detect_65); - break; - case 0: /* 4.5 */ - case 2: /* 6.0 */ - default: - cd = NULL; - count = 0; - break; - } - - if (amsound && (state->norm == VIDEO_MODE_SECAM)) { - /* autodetect doesn't work well with AM ... */ - cd = NULL; - count = 0; - max2 = 0; - } - for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); - if (msp_sleep(state,100)) - goto restart; - val = msp_read_dsp(client, 0x1b); - if (val > 32767) - val -= 65536; - if (val2 < val) - val2 = val, max2 = this; - msp_dbg1("carrier2 val: %5d / %s\n", val,cd[this].name); - } - - /* program the msp3400 according to the results */ - state->main = msp3400c_carrier_detect_main[max1].cdo; - switch (max1) { - case 1: /* 5.5 */ - if (max2 == 0) { - /* B/G FM-stereo */ - state->second = msp3400c_carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - state->nicam_on = 0; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - state->watch_stereo = 1; - } else if (max2 == 1 && HAVE_NICAM(state)) { - /* B/G NICAM */ - state->second = msp3400c_carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - state->nicam_on = 1; - msp3400c_setcarrier(client, state->second, state->main); - state->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 2: /* 6.0 */ - /* PAL I NICAM */ - state->second = MSP_CARRIER(6.552); - msp3400c_setmode(client, MSP_MODE_FM_NICAM2); - state->nicam_on = 1; - msp3400c_setcarrier(client, state->second, state->main); - state->watch_stereo = 1; - break; - case 3: /* 6.5 */ - if (max2 == 1 || max2 == 2) { - /* D/K FM-stereo */ - state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - state->nicam_on = 0; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - state->watch_stereo = 1; - } else if (max2 == 0 && - state->norm == VIDEO_MODE_SECAM) { - /* L NICAM or AM-mono */ - state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_AM_NICAM); - state->nicam_on = 0; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - msp3400c_setcarrier(client, state->second, state->main); - /* volume prescale for SCART (AM mono input) */ - msp_write_dsp(client, 0x000d, 0x1900); - state->watch_stereo = 1; - } else if (max2 == 0 && HAVE_NICAM(state)) { - /* D/K NICAM */ - state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); - state->nicam_on = 1; - msp3400c_setcarrier(client, state->second, state->main); - state->watch_stereo = 1; - } else { - goto no_second; - } - break; - case 0: /* 4.5 */ - default: - no_second: - state->second = msp3400c_carrier_detect_main[max1].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - state->nicam_on = 0; - msp3400c_setcarrier(client, state->second, state->main); - state->rxsubchans = V4L2_TUNER_SUB_MONO; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - break; - } - - /* unmute */ - msp_set_audio(client); - msp3400c_restore_dfp(client); - - if (debug) - msp3400c_print_mode(client); - - /* monitor tv audio mode */ - while (state->watch_stereo) { - if (msp_sleep(state,5000)) - goto restart; - watch_stereo(client); - } - } - msp_dbg1("thread: exit\n"); - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* this one uses the automatic sound standard detection of newer */ -/* msp34xx chip versions */ - -static struct MODES { - int retval; - int main, second; - char *name; -} modelist[] = { - { 0x0000, 0, 0, "could not detect sound standard" }, - { 0x0001, 0, 0, "autodetect started" }, - { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, - { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, - { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, - { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, - { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, - { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, - { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, - { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, - { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, - { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, - { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, - { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, - { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, - { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, - { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, - { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, - { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, - { -1, 0, 0, NULL }, /* EOF */ -}; - -static inline const char *msp_standard_mode_name(int mode) -{ - int i; - for (i = 0; modelist[i].name != NULL; i++) - if (modelist[i].retval == mode) - return modelist[i].name; - return "unknown"; -} - -static int msp_modus(struct i2c_client *client, int norm) -{ - switch (norm) { - case VIDEO_MODE_PAL: - msp_dbg1("video mode selected to PAL\n"); - -#if 1 - /* experimental: not sure this works with all chip versions */ - return 0x7003; -#else - /* previous value, try this if it breaks ... */ - return 0x1003; -#endif - case VIDEO_MODE_NTSC: /* BTSC */ - msp_dbg1("video mode selected to NTSC\n"); - return 0x2003; - case VIDEO_MODE_SECAM: - msp_dbg1("video mode selected to SECAM\n"); - return 0x0003; - case VIDEO_MODE_RADIO: - msp_dbg1("video mode selected to Radio\n"); - return 0x0003; - case VIDEO_MODE_AUTO: - msp_dbg1("video mode selected to Auto\n"); - return 0x2003; - default: - return 0x0003; - } -} - -static int msp_standard(int norm) -{ - switch (norm) { - case VIDEO_MODE_PAL: - return 1; - case VIDEO_MODE_NTSC: /* BTSC */ - return 0x0020; - case VIDEO_MODE_SECAM: - return 1; - case VIDEO_MODE_RADIO: - return 0x0040; - default: - return 1; - } -} - -static int msp3410d_thread(void *data) -{ - struct i2c_client *client = data; - struct msp_state *state = i2c_get_clientdata(client); - int mode,val,i,std; - - msp_info("msp3410 daemon started\n"); - - for (;;) { - msp_dbg2("msp3410 thread: sleep\n"); - msp_sleep(state,-1); - msp_dbg2("msp3410 thread: wakeup\n"); - - restart: - msp_dbg1("thread: restart scan\n"); - state->restart = 0; - if (kthread_should_stop()) - break; - - if (state->mode == MSP_MODE_EXTERN) { - /* no carrier scan needed, just unmute */ - msp_dbg1("thread: no carrier scan\n"); - msp_set_audio(client); - continue; - } - - /* put into sane state (and mute) */ - msp_reset(client); - - /* some time for the tuner to sync */ - if (msp_sleep(state,200)) - goto restart; - - /* start autodetect */ - mode = msp_modus(client, state->norm); - std = msp_standard(state->norm); - msp_write_dem(client, 0x30, mode); - msp_write_dem(client, 0x20, std); - state->watch_stereo = 0; - - if (debug) - msp_dbg1("setting mode: %s (0x%04x)\n", - msp_standard_mode_name(std) ,std); - - if (std != 1) { - /* programmed some specific mode */ - val = std; - } else { - /* triggered autodetect */ - for (;;) { - if (msp_sleep(state,100)) - goto restart; - - /* check results */ - val = msp_read_dem(client, 0x7e); - if (val < 0x07ff) - break; - msp_dbg1("detection still in progress\n"); - } - } - for (i = 0; modelist[i].name != NULL; i++) - if (modelist[i].retval == val) - break; - msp_dbg1("current mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown", - val); - state->main = modelist[i].main; - state->second = modelist[i].second; - - if (amsound && (state->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { - /* autodetection has failed, let backup */ - msp_dbg1("autodetection failed," - " switching to backup mode: %s (0x%04x)\n", - modelist[8].name ? modelist[8].name : "unknown",val); - val = 0x0009; - msp_write_dem(client, 0x20, val); - } - - /* set various prescales */ - msp_write_dsp(client, 0x0d, 0x1900); /* scart */ - msp_write_dsp(client, 0x0e, 0x2403); /* FM */ - msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ - - /* set stereo */ - switch (val) { - case 0x0008: /* B/G NICAM */ - case 0x000a: /* I NICAM */ - if (val == 0x0008) - state->mode = MSP_MODE_FM_NICAM1; - else - state->mode = MSP_MODE_FM_NICAM2; - /* just turn on stereo */ - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->nicam_on = 1; - state->watch_stereo = 1; - msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); - break; - case 0x0009: - state->mode = MSP_MODE_AM_NICAM; - state->rxsubchans = V4L2_TUNER_SUB_MONO; - state->nicam_on = 1; - msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO); - state->watch_stereo = 1; - break; - case 0x0020: /* BTSC */ - /* just turn on stereo */ - state->mode = MSP_MODE_BTSC; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->nicam_on = 0; - state->watch_stereo = 1; - msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); - break; - case 0x0040: /* FM radio */ - state->mode = MSP_MODE_FM_RADIO; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->audmode = V4L2_TUNER_MODE_STEREO; - state->nicam_on = 0; - state->watch_stereo = 0; - /* not needed in theory if HAVE_RADIO(), but - short programming enables carrier mute */ - msp3400c_setmode(client,MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - /* scart routing */ - msp_set_scart(client,SCART_IN2,0); - /* msp34xx does radio decoding */ - msp_write_dsp(client, 0x08, 0x0020); - msp_write_dsp(client, 0x09, 0x0020); - msp_write_dsp(client, 0x0b, 0x0020); - break; - case 0x0003: - case 0x0004: - case 0x0005: - state->mode = MSP_MODE_FM_TERRA; - state->rxsubchans = V4L2_TUNER_SUB_MONO; - state->audmode = V4L2_TUNER_MODE_MONO; - state->nicam_on = 0; - state->watch_stereo = 1; - break; - } - - /* unmute, restore misc registers */ - msp_set_audio(client); - msp_write_dsp(client, 0x13, state->acb); - msp_write_dem(client, 0x40, state->i2s_mode); - msp3400c_restore_dfp(client); - - /* monitor tv audio mode */ - while (state->watch_stereo) { - if (msp_sleep(state,5000)) - goto restart; - watch_stereo(client); - } - } - msp_dbg1("thread: exit\n"); - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* msp34xxG + (autoselect no-thread) */ -/* this one uses both automatic standard detection and automatic sound */ -/* select which are available in the newer G versions */ -/* struct msp: only norm, acb and source are really used in this mode */ - -/* set the same 'source' for the loudspeaker, scart and quasi-peak detector - * the value for source is the same as bit 15:8 of DFP registers 0x08, - * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B - * - * this function replaces msp3400c_setstereo - */ -static void msp34xxg_set_source(struct i2c_client *client, int source) -{ - struct msp_state *state = i2c_get_clientdata(client); - - /* fix matrix mode to stereo and let the msp choose what - * to output according to 'source', as recommended - * for MONO (source==0) downmixing set bit[7:0] to 0x30 - */ - int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20); - - msp_dbg1("set source to %d (0x%x)\n", source, value); - /* Loudspeaker Output */ - msp_write_dsp(client, 0x08, value); - /* SCART1 DA Output */ - msp_write_dsp(client, 0x0a, value); - /* Quasi-peak detector */ - msp_write_dsp(client, 0x0c, value); - /* - * set identification threshold. Personally, I - * I set it to a higher value that the default - * of 0x190 to ignore noisy stereo signals. - * this needs tuning. (recommended range 0x00a0-0x03c0) - * 0x7f0 = forced mono mode - */ - /* a2 threshold for stereo/bilingual */ - msp_write_dem(client, 0x22, stereo_threshold); - state->source = source; -} - -/* (re-)initialize the msp34xxg, according to the current norm in state->norm - * return 0 if it worked, -1 if it failed - */ -static int msp34xxg_reset(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - int modus, std; - - if (msp_reset(client)) - return -1; - - /* make sure that input/output is muted (paranoid mode) */ - /* ACB, mute DSP input, mute SCART 1 */ - if (msp_write_dsp(client, 0x13, 0x0f20)) - return -1; - - msp_write_dem(client, 0x40, state->i2s_mode); - - /* step-by-step initialisation, as described in the manual */ - modus = msp_modus(client, state->norm); - std = msp_standard(state->norm); - modus &= ~0x03; /* STATUS_CHANGE = 0 */ - modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ - if (msp_write_dem(client, 0x30, modus)) - return -1; - if (msp_write_dem(client, 0x20, std)) - return -1; - - /* write the dfps that may have an influence on - standard/audio autodetection right now */ - msp34xxg_set_source(client, state->source); - - /* AM/FM Prescale, default: [15:8] 75khz deviation */ - if (msp34xxg_write_dfp_with_default(client, 0x0e, 0x3000)) - return -1; - - /* NICAM Prescale, default: 9db gain (as recommended) */ - if (msp34xxg_write_dfp_with_default(client, 0x10, 0x5a00)) - return -1; - - return 0; -} - -static int msp34xxg_thread(void *data) -{ - struct i2c_client *client = data; - struct msp_state *state = i2c_get_clientdata(client); - int val, std, i; - - msp_info("msp34xxg daemon started\n"); - - state->source = 1; /* default */ - for (;;) { - msp_dbg2("msp34xxg thread: sleep\n"); - msp_sleep(state, -1); - msp_dbg2("msp34xxg thread: wakeup\n"); - - restart: - msp_dbg1("thread: restart scan\n"); - state->restart = 0; - if (kthread_should_stop()) - break; - - /* setup the chip*/ - msp34xxg_reset(client); - std = standard; - if (std != 0x01) - goto unmute; - - /* watch autodetect */ - msp_dbg1("triggered autodetect, waiting for result\n"); - for (i = 0; i < 10; i++) { - if (msp_sleep(state, 100)) - goto restart; - - /* check results */ - val = msp_read_dem(client, 0x7e); - if (val < 0x07ff) { - std = val; - break; - } - msp_dbg1("detection still in progress\n"); - } - if (std == 1) { - msp_dbg1("detection still in progress after 10 tries. giving up.\n"); - continue; - } - - unmute: - state->mode = std; - msp_dbg1("current mode: %s (0x%04x)\n", - msp_standard_mode_name(std), std); - - /* unmute: dispatch sound to scart output, set scart volume */ - msp_set_audio(client); - - /* restore ACB */ - if (msp_write_dsp(client, 0x13, state->acb)) - return -1; - - msp_write_dem(client, 0x40, state->i2s_mode); - } - msp_dbg1("thread: exit\n"); - return 0; -} - -static void msp34xxg_detect_stereo(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - int status = msp_read_dem(client, 0x0200); - int is_bilingual = status & 0x100; - int is_stereo = status & 0x40; - - state->rxsubchans = 0; - if (is_stereo) - state->rxsubchans |= V4L2_TUNER_SUB_STEREO; - else - state->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (is_bilingual) { - state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - /* I'm supposed to check whether it's SAP or not - * and set only LANG2/SAP in this case. Yet, the MSP - * does a lot of work to hide this and handle everything - * the same way. I don't want to work around it so unless - * this is a problem, I'll handle SAP just like lang1/lang2. - */ - } - msp_dbg1("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", - status, is_stereo, is_bilingual, state->rxsubchans); -} - -static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) -{ - struct msp_state *state = i2c_get_clientdata(client); - int source; - - switch (audmode) { - case V4L2_TUNER_MODE_MONO: - source = 0; /* mono only */ - break; - case V4L2_TUNER_MODE_STEREO: - source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ - /* problem: that could also mean 2 (scart input) */ - break; - case V4L2_TUNER_MODE_LANG1: - source = 3; /* stereo or A */ - break; - case V4L2_TUNER_MODE_LANG2: - source = 4; /* stereo or B */ - break; - default: - audmode = 0; - source = 1; - break; - } - state->audmode = audmode; - msp34xxg_set_source(client, source); -} - - -/* ----------------------------------------------------------------------- */ - -static void msp_wake_thread(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - if (NULL == state->kthread) - return; - msp_set_mute(client); - state->watch_stereo = 0; - state->restart = 1; - wake_up_interruptible(&state->wq); -} - -/* ----------------------------------------------------------------------- */ - -static int mode_v4l2_to_v4l1(int rxsubchans) -{ - int mode = 0; - - if (rxsubchans & V4L2_TUNER_SUB_STEREO) - mode |= VIDEO_SOUND_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG2) - mode |= VIDEO_SOUND_LANG2; - if (rxsubchans & V4L2_TUNER_SUB_LANG1) - mode |= VIDEO_SOUND_LANG1; - if (mode == 0) - mode |= VIDEO_SOUND_MONO; - return mode; -} - -static int mode_v4l1_to_v4l2(int mode) -{ - if (mode & VIDEO_SOUND_STEREO) - return V4L2_TUNER_MODE_STEREO; - if (mode & VIDEO_SOUND_LANG2) - return V4L2_TUNER_MODE_LANG2; - if (mode & VIDEO_SOUND_LANG1) - return V4L2_TUNER_MODE_LANG1; - return V4L2_TUNER_MODE_MONO; -} - -static void msp_any_detect_stereo(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - switch (state->opmode) { - case OPMODE_MANUAL: - case OPMODE_AUTODETECT: - autodetect_stereo(client); - break; - case OPMODE_AUTOSELECT: - msp34xxg_detect_stereo(client); - break; - } -} - -static struct v4l2_queryctrl msp_qctrl[] = { - { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 58880, - .flags = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = 0, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_BASS, - .name = "Bass", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_TREBLE, - .name = "Treble", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, -}; - - -static void msp_any_set_audmode(struct i2c_client *client, int audmode) -{ - struct msp_state *state = i2c_get_clientdata(client); - - switch (state->opmode) { - case OPMODE_MANUAL: - case OPMODE_AUTODETECT: - state->watch_stereo = 0; - msp3400c_setstereo(client, audmode); - break; - case OPMODE_AUTOSELECT: - msp34xxg_set_audmode(client, audmode); - break; - } -} - -static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) -{ - struct msp_state *state = i2c_get_clientdata(client); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = state->muted; - break; - - case V4L2_CID_AUDIO_BALANCE: - ctrl->value = state->balance; - break; - - case V4L2_CID_AUDIO_BASS: - ctrl->value = state->bass; - break; - - case V4L2_CID_AUDIO_TREBLE: - ctrl->value = state->treble; - break; - - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = state->volume; - break; - - default: - return -EINVAL; - } - return 0; -} - -static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) -{ - struct msp_state *state = i2c_get_clientdata(client); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value < 0 || ctrl->value >= 2) - return -ERANGE; - state->muted = ctrl->value; - break; - - case V4L2_CID_AUDIO_BASS: - state->bass = ctrl->value; - break; - - case V4L2_CID_AUDIO_TREBLE: - state->treble = ctrl->value; - break; - - case V4L2_CID_AUDIO_BALANCE: - state->balance = ctrl->value; - break; - - case V4L2_CID_AUDIO_VOLUME: - state->volume = ctrl->value; - if (state->volume == 0) - state->balance = 32768; - break; - - default: - return -EINVAL; - } - msp_set_audio(client); - return 0; -} - -static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct msp_state *state = i2c_get_clientdata(client); - u16 *sarg = arg; - int scart = 0; - - if (debug >= 2) - v4l_i2c_print_ioctl(client, cmd); - - switch (cmd) { - case AUDC_SET_INPUT: - if (*sarg == state->input) - break; - state->input = *sarg; - switch (*sarg) { - case AUDIO_RADIO: - /* Hauppauge uses IN2 for the radio */ - state->mode = MSP_MODE_FM_RADIO; - scart = SCART_IN2; - break; - case AUDIO_EXTERN_1: - /* IN1 is often used for external input ... */ - state->mode = MSP_MODE_EXTERN; - scart = SCART_IN1; - break; - case AUDIO_EXTERN_2: - /* ... sometimes it is IN2 through ;) */ - state->mode = MSP_MODE_EXTERN; - scart = SCART_IN2; - break; - case AUDIO_TUNER: - state->mode = -1; - break; - default: - if (*sarg & AUDIO_MUTE) - msp_set_scart(client, SCART_MUTE, 0); - break; - } - if (scart) { - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->audmode = V4L2_TUNER_MODE_STEREO; - msp_set_scart(client, scart, 0); - msp_write_dsp(client, 0x000d, 0x1900); - if (state->opmode != OPMODE_AUTOSELECT) - msp3400c_setstereo(client, state->audmode); - } - msp_wake_thread(client); - break; - - case AUDC_SET_RADIO: - state->norm = VIDEO_MODE_RADIO; - msp_dbg1("switching to radio mode\n"); - state->watch_stereo = 0; - switch (state->opmode) { - case OPMODE_MANUAL: - /* set msp3400 to FM radio mode */ - msp3400c_setmode(client, MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - msp_set_audio(client); - break; - case OPMODE_AUTODETECT: - case OPMODE_AUTOSELECT: - /* the thread will do for us */ - msp_wake_thread(client); - break; - } - break; - /* work-in-progress: hook to control the DFP registers */ - case MSP_SET_DFPREG: - { - struct msp_dfpreg *r = arg; - int i; - - if (r->reg < 0 || r->reg >= DFP_COUNT) - return -EINVAL; - for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++) - if (r->reg == bl_dfp[i]) - return -EINVAL; - state->dfp_regs[r->reg] = r->value; - msp_write_dsp(client, r->reg, r->value); - return 0; - } - - case MSP_GET_DFPREG: - { - struct msp_dfpreg *r = arg; - - if (r->reg < 0 || r->reg >= DFP_COUNT) - return -EINVAL; - r->value = msp_read_dsp(client, r->reg); - return 0; - } - - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE | - VIDEO_AUDIO_MUTABLE; - if (state->muted) - va->flags |= VIDEO_AUDIO_MUTE; - - if (state->muted) - va->flags |= VIDEO_AUDIO_MUTE; - va->volume = state->volume; - va->balance = state->volume ? state->balance : 32768; - va->bass = state->bass; - va->treble = state->treble; - - msp_any_detect_stereo(client); - va->mode = mode_v4l2_to_v4l1(state->rxsubchans); - break; - } - - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - - state->muted = (va->flags & VIDEO_AUDIO_MUTE); - state->volume = va->volume; - state->balance = va->balance; - state->bass = va->bass; - state->treble = va->treble; - msp_set_audio(client); - - if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) - msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode)); - break; - } - - case VIDIOCSCHAN: - { - struct video_channel *vc = arg; - - state->norm = vc->norm; - msp_wake_thread(client); - break; - } - - case VIDIOCSFREQ: - case VIDIOC_S_FREQUENCY: - { - /* new channel -- kick audio carrier scan */ - msp_wake_thread(client); - break; - } - - /* msp34xx specific */ - case MSP_SET_MATRIX: - { - struct msp_matrix *mspm = arg; - - msp_set_scart(client, mspm->input, mspm->output); - break; - } - - /* --- v4l2 ioctls --- */ - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - - /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ - if (*id & V4L2_STD_PAL) { - state->norm = VIDEO_MODE_PAL; - } else if (*id & V4L2_STD_SECAM) { - state->norm = VIDEO_MODE_SECAM; - } else { - state->norm = VIDEO_MODE_NTSC; - } - - msp_wake_thread(client); - return 0; - } - - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - - if (i->index != 0) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_TUNER; - switch (i->index) { - case AUDIO_RADIO: - strcpy(i->name, "Radio"); - break; - case AUDIO_EXTERN_1: - strcpy(i->name, "Extern 1"); - break; - case AUDIO_EXTERN_2: - strcpy(i->name, "Extern 2"); - break; - case AUDIO_TUNER: - strcpy(i->name, "Television"); - break; - default: - return -EINVAL; - } - return 0; - } - - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - - memset(a, 0, sizeof(*a)); - - switch (a->index) { - case AUDIO_RADIO: - strcpy(a->name, "Radio"); - break; - case AUDIO_EXTERN_1: - strcpy(a->name, "Extern 1"); - break; - case AUDIO_EXTERN_2: - strcpy(a->name, "Extern 2"); - break; - case AUDIO_TUNER: - strcpy(a->name, "Television"); - break; - default: - return -EINVAL; - } - - msp_any_detect_stereo(client); - if (state->audmode == V4L2_TUNER_MODE_STEREO) { - a->capability = V4L2_AUDCAP_STEREO; - } - - break; - } - - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *sarg = arg; - - switch (sarg->index) { - case AUDIO_RADIO: - /* Hauppauge uses IN2 for the radio */ - state->mode = MSP_MODE_FM_RADIO; - scart = SCART_IN2; - break; - case AUDIO_EXTERN_1: - /* IN1 is often used for external input ... */ - state->mode = MSP_MODE_EXTERN; - scart = SCART_IN1; - break; - case AUDIO_EXTERN_2: - /* ... sometimes it is IN2 through ;) */ - state->mode = MSP_MODE_EXTERN; - scart = SCART_IN2; - break; - case AUDIO_TUNER: - state->mode = -1; - break; - } - if (scart) { - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->audmode = V4L2_TUNER_MODE_STEREO; - msp_set_scart(client, scart, 0); - msp_write_dsp(client, 0x000d, 0x1900); - } - if (sarg->capability == V4L2_AUDCAP_STEREO) { - state->audmode = V4L2_TUNER_MODE_STEREO; - } else { - state->audmode &= ~V4L2_TUNER_MODE_STEREO; - } - msp_any_set_audmode(client, state->audmode); - msp_wake_thread(client); - break; - } - - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *vt = arg; - - msp_any_detect_stereo(client); - vt->audmode = state->audmode; - vt->rxsubchans = state->rxsubchans; - vt->capability = V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - break; - } - - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; - - /* only set audmode */ - if (vt->audmode != -1 && vt->audmode != 0) - msp_any_set_audmode(client, vt->audmode); - break; - } - - case VIDIOC_G_AUDOUT: - { - struct v4l2_audioout *a = (struct v4l2_audioout *)arg; - int idx = a->index; - - memset(a, 0, sizeof(*a)); - - switch (idx) { - case 0: - strcpy(a->name, "Scart1 Out"); - break; - case 1: - strcpy(a->name, "Scart2 Out"); - break; - case 2: - strcpy(a->name, "I2S Out"); - break; - default: - return -EINVAL; - } - break; - - } - - case VIDIOC_S_AUDOUT: - { - struct v4l2_audioout *a = (struct v4l2_audioout *)arg; - - if (a->index < 0 || a->index > 2) - return -EINVAL; - - msp_dbg1("Setting audio out on msp34xx to input %i\n", a->index); - msp_set_scart(client, state->in_scart, a->index + 1); - - break; - } - - case VIDIOC_INT_I2S_CLOCK_FREQ: - { - u32 *a = (u32 *)arg; - - msp_dbg1("Setting I2S speed to %d\n", *a); - - switch (*a) { - case 1024000: - state->i2s_mode = 0; - break; - case 2048000: - state->i2s_mode = 1; - break; - default: - return -EINVAL; - } - break; - } - - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) - if (qc->id && qc->id == msp_qctrl[i].id) { - memcpy(qc, &msp_qctrl[i], sizeof(*qc)); - return 0; - } - return -EINVAL; - } - - case VIDIOC_G_CTRL: - return msp_get_ctrl(client, arg); - - case VIDIOC_S_CTRL: - return msp_set_ctrl(client, arg); - - case VIDIOC_LOG_STATUS: - msp_any_detect_stereo(client); - msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", - client->name, state->rev1, state->rev2); - msp_info("Audio: volume %d balance %d bass %d treble %d%s\n", - state->volume, state->balance, - state->bass, state->treble, - state->muted ? " (muted)" : ""); - msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), - (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", - (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - msp_info("ACB: 0x%04x\n", state->acb); - break; - - default: - /* nothing */ - break; - } - return 0; -} - -static int msp_suspend(struct device * dev, pm_message_t state) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - - msp_dbg1("suspend\n"); - msp_reset(client); - return 0; -} - -static int msp_resume(struct device * dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - - msp_dbg1("resume\n"); - msp_wake_thread(client); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver i2c_driver; - -static int msp_attach(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *client; - struct msp_state *state; - int (*thread_func)(void *data) = NULL; - int i; - - client = kmalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) - return -ENOMEM; - memset(client, 0, sizeof(*client)); - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - client->flags = I2C_CLIENT_ALLOW_USE; - snprintf(client->name, sizeof(client->name) - 1, "msp3400"); - - if (msp_reset(client) == -1) { - msp_dbg1("msp3400 not found\n"); - kfree(client); - return -1; - } - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) { - kfree(client); - return -ENOMEM; - } - i2c_set_clientdata(client, state); - - memset(state, 0, sizeof(*state)); - state->norm = VIDEO_MODE_NTSC; - state->volume = 58880; /* 0db gain */ - state->balance = 32768; /* 0db gain */ - state->bass = 32768; - state->treble = 32768; - state->input = -1; - state->muted = 0; - state->i2s_mode = 0; - for (i = 0; i < DFP_COUNT; i++) - state->dfp_regs[i] = -1; - init_waitqueue_head(&state->wq); - - state->rev1 = msp_read_dsp(client, 0x1e); - if (state->rev1 != -1) - state->rev2 = msp_read_dsp(client, 0x1f); - msp_dbg1("rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); - if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - msp_dbg1("error while reading chip version\n"); - kfree(state); - kfree(client); - return -1; - } - - msp_set_audio(client); - - snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", - ((state->rev1 >> 4) & 0x0f) + '3', - (state->rev2 >> 8) & 0xff, - (state->rev1 & 0x0f) + '@', - ((state->rev1 >> 8) & 0xff) + '@', - state->rev2 & 0x1f); - - state->opmode = opmode; - if (state->opmode == OPMODE_AUTO) { - /* MSP revision G and up have both autodetect and autoselect */ - if ((state->rev1 & 0x0f) >= 'G'-'@') - state->opmode = OPMODE_AUTOSELECT; - /* MSP revision D and up have autodetect */ - else if ((state->rev1 & 0x0f) >= 'D'-'@') - state->opmode = OPMODE_AUTODETECT; - else - state->opmode = OPMODE_MANUAL; - } - - /* hello world :-) */ - msp_info("%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); - msp_info("%s ", client->name); - if (HAVE_NICAM(state) && HAVE_RADIO(state)) - printk("supports nicam and radio, "); - else if (HAVE_NICAM(state)) - printk("supports nicam, "); - else if (HAVE_RADIO(state)) - printk("supports radio, "); - printk("mode is "); - - /* version-specific initialization */ - switch (state->opmode) { - case OPMODE_MANUAL: - printk("manual"); - thread_func = msp3400c_thread; - break; - case OPMODE_AUTODETECT: - printk("autodetect"); - thread_func = msp3410d_thread; - break; - case OPMODE_AUTOSELECT: - printk("autodetect and autoselect"); - thread_func = msp34xxg_thread; - break; - } - printk("\n"); - - /* startup control thread if needed */ - if (thread_func) { - state->kthread = kthread_run(thread_func, client, "msp34xx"); - - if (state->kthread == NULL) - msp_warn("kernel_thread() failed\n"); - msp_wake_thread(client); - } - - /* done */ - i2c_attach_client(client); - - return 0; -} - -static int msp_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, msp_attach); - return 0; -} - -static int msp_detach(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - int err; - - /* shutdown control thread */ - if (state->kthread) { - state->restart = 1; - kthread_stop(state->kthread); - } - msp_reset(client); - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .name = "msp3400", - .id = I2C_DRIVERID_MSP3400, - .flags = I2C_DF_NOTIFY, - .attach_adapter = msp_probe, - .detach_client = msp_detach, - .command = msp_command, - .driver = { - .suspend = msp_suspend, - .resume = msp_resume, - }, - .owner = THIS_MODULE, -}; - -static int __init msp3400_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit msp3400_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 2d9ff40f0b09..33d64ac75d37 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -6,22 +6,62 @@ /* ---------------------------------------------------------------------- */ -struct msp_dfpreg { - int reg; - int value; -}; +#define msp_err(fmt, arg...) \ + printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg) +#define msp_warn(fmt, arg...) \ + printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg) +#define msp_info(fmt, arg...) \ + printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg) + +/* level 1 debug. */ +#define msp_dbg1(fmt, arg...) \ + do { \ + if (debug) \ + printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->driver.name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg); \ + } while (0) + +/* level 2 debug. */ +#define msp_dbg2(fmt, arg...) \ + do { \ + if (debug >= 2) \ + printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg); \ + } while (0) + +/* level 3 debug. Use with care. */ +#define msp_dbg3(fmt, arg...) \ + do { \ + if (debug >= 16) \ + printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ + i2c_adapter_id(client->adapter), client->addr , ## arg); \ + } while (0) struct msp_matrix { int input; int output; }; -#define MSP_SET_DFPREG _IOW('m',15,struct msp_dfpreg) -#define MSP_GET_DFPREG _IOW('m',16,struct msp_dfpreg) - /* ioctl for MSP_SET_MATRIX will have to be registered */ #define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix) +/* This macro is allowed for *constants* only, gcc must calculate it + at compile time. Remember -- no floats in kernel mode */ +#define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) + +#define MSP_MODE_AM_DETECT 0 +#define MSP_MODE_FM_RADIO 2 +#define MSP_MODE_FM_TERRA 3 +#define MSP_MODE_FM_SAT 4 +#define MSP_MODE_FM_NICAM1 5 +#define MSP_MODE_FM_NICAM2 6 +#define MSP_MODE_AM_NICAM 7 +#define MSP_MODE_BTSC 8 +#define MSP_MODE_EXTERN 9 + #define SCART_MASK 0 #define SCART_IN1 1 #define SCART_IN2 2 @@ -36,4 +76,77 @@ struct msp_matrix { #define SCART1_OUT 1 #define SCART2_OUT 2 +#define OPMODE_AUTO -1 +#define OPMODE_MANUAL 0 +#define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ +#define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ + +/* module parameters */ +extern int debug; +extern int once; +extern int amsound; +extern int standard; +extern int dolby; +extern int stereo_threshold; + +struct msp_state { + int rev1, rev2; + + int opmode; + int mode; + int norm; + int stereo; + int nicam_on; + int acb; + int in_scart; + int i2s_mode; + int main, second; /* sound carrier */ + int input; + int source; /* see msp34xxg_set_source */ + + /* v4l2 */ + int audmode; + int rxsubchans; + + int muted; + int volume, balance; + int bass, treble; + + /* thread */ + struct task_struct *kthread; + wait_queue_head_t wq; + int restart:1; + int watch_stereo:1; +}; + +#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ + +#define HAVE_NICAM(state) (((state->rev2 >> 8) & 0xff) != 0) +#define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') + +/* msp3400-driver.c */ +int msp_write_dem(struct i2c_client *client, int addr, int val); +int msp_write_dsp(struct i2c_client *client, int addr, int val); +int msp_read_dem(struct i2c_client *client, int addr); +int msp_read_dsp(struct i2c_client *client, int addr); +int msp_reset(struct i2c_client *client); +void msp_set_scart(struct i2c_client *client, int in, int out); +void msp_set_mute(struct i2c_client *client); +void msp_set_audio(struct i2c_client *client); +int msp_modus(struct i2c_client *client, int norm); +int msp_standard(int norm); +int msp_sleep(struct msp_state *state, int timeout); + +/* msp3400-kthreads.c */ +const char *msp_standard_mode_name(int mode); +void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2); +void msp3400c_setmode(struct i2c_client *client, int type); +void msp3400c_setstereo(struct i2c_client *client, int mode); +int autodetect_stereo(struct i2c_client *client); +int msp3400c_thread(void *data); +int msp3410d_thread(void *data); +int msp34xxg_thread(void *data); +void msp34xxg_detect_stereo(struct i2c_client *client); +void msp34xxg_set_audmode(struct i2c_client *client, int audmode); + #endif /* MSP3400_H */ -- cgit v1.2.3 From 7e8b09ea1636e360a8fabebeaeb91c17f64e01b5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:40 -0200 Subject: V4L/DVB (3276): Added new diagnositics macros, convert msp3400 to the new macros. - Added new v4l_err, v4l_warn, v4l_info and v4l_dbg macros to v4l2-common.h for use in v4l-dvb i2c drivers. This ensures a unique prefix for each device instance. - At a later stage these macros may be reimplemented using the device-generic macros from device.h. - Converted the msp3400 driver to the new macros. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/msp3400-driver.c | 62 +- drivers/media/video/msp3400-kthreads.c | 1015 ++++++++++++++++++++++++++++++++ drivers/media/video/msp3400.h | 34 -- include/media/v4l2-common.h | 63 +- 4 files changed, 1097 insertions(+), 77 deletions(-) create mode 100644 drivers/media/video/msp3400-kthreads.c diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index de79c641583a..4c0c7bed2edf 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -129,11 +129,11 @@ int msp_reset(struct i2c_client *client) { client->addr, I2C_M_RD, 2, read }, }; - msp_dbg3("msp_reset\n"); + v4l_dbg(3, client, "msp_reset\n"); if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || i2c_transfer(client->adapter, &reset[1], 1) != 1 || i2c_transfer(client->adapter, test, 2) != 2) { - msp_err("chip reset failed\n"); + v4l_err(client, "chip reset failed\n"); return -1; } return 0; @@ -156,18 +156,18 @@ static int msp_read(struct i2c_client *client, int dev, int addr) for (err = 0; err < 3; err++) { if (i2c_transfer(client->adapter, msgs, 2) == 2) break; - msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, + v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(msecs_to_jiffies(10)); } if (err == 3) { - msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - msp_dbg3("msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); + v4l_dbg(3, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); return retval; } @@ -192,17 +192,17 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); + v4l_dbg(3, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); for (err = 0; err < 3; err++) { if (i2c_master_send(client, buffer, 5) == 5) break; - msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, + v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(msecs_to_jiffies(10)); } if (err == 3) { - msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); msp_reset(client); return -1; } @@ -275,7 +275,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) } else state->acb = 0xf60; /* Mute Input and SCART 1 Output */ - msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", + v4l_dbg(1, client, "scart switch: %s => %d (ACB=0x%04x)\n", scart_names[in], out, state->acb); msp_write_dsp(client, 0x13, state->acb); @@ -285,7 +285,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) void msp_set_mute(struct i2c_client *client) { - msp_dbg1("mute audio\n"); + v4l_dbg(1, client, "mute audio\n"); msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ msp_write_dsp(client, 0x0006, 0); /* headphones */ } @@ -302,7 +302,7 @@ void msp_set_audio(struct i2c_client *client) bass = ((state->bass - 32768) * 0x60 / 65535) << 8; treble = ((state->treble - 32768) * 0x60 / 65535) << 8; - msp_dbg1("mute=%s volume=%d balance=%d bass=%d treble=%d\n", + v4l_dbg(1, client, "mute=%s volume=%d balance=%d bass=%d treble=%d\n", state->muted ? "on" : "off", state->volume, state->balance, state->bass, state->treble); @@ -318,7 +318,7 @@ int msp_modus(struct i2c_client *client, int norm) { switch (norm) { case VIDEO_MODE_PAL: - msp_dbg1("video mode selected to PAL\n"); + v4l_dbg(1, client, "video mode selected to PAL\n"); #if 1 /* experimental: not sure this works with all chip versions */ @@ -328,16 +328,16 @@ int msp_modus(struct i2c_client *client, int norm) return 0x1003; #endif case VIDEO_MODE_NTSC: /* BTSC */ - msp_dbg1("video mode selected to NTSC\n"); + v4l_dbg(1, client, "video mode selected to NTSC\n"); return 0x2003; case VIDEO_MODE_SECAM: - msp_dbg1("video mode selected to SECAM\n"); + v4l_dbg(1, client, "video mode selected to SECAM\n"); return 0x0003; case VIDEO_MODE_RADIO: - msp_dbg1("video mode selected to Radio\n"); + v4l_dbg(1, client, "video mode selected to Radio\n"); return 0x0003; case VIDEO_MODE_AUTO: - msp_dbg1("video mode selected to Auto\n"); + v4l_dbg(1, client, "video mode selected to Auto\n"); return 0x2003; default: return 0x0003; @@ -620,7 +620,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case AUDC_SET_RADIO: state->norm = VIDEO_MODE_RADIO; - msp_dbg1("switching to radio mode\n"); + v4l_dbg(1, client, "switching to radio mode\n"); state->watch_stereo = 0; switch (state->opmode) { case OPMODE_MANUAL: @@ -875,7 +875,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (a->index < 0 || a->index > 2) return -EINVAL; - msp_dbg1("Setting audio out on msp34xx to input %i\n", a->index); + v4l_dbg(1, client, "Setting audio out on msp34xx to input %i\n", a->index); msp_set_scart(client, state->in_scart, a->index + 1); break; @@ -885,7 +885,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { u32 *a = (u32 *)arg; - msp_dbg1("Setting I2S speed to %d\n", *a); + v4l_dbg(1, client, "Setting I2S speed to %d\n", *a); switch (*a) { case 1024000: @@ -921,16 +921,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_LOG_STATUS: msp_any_detect_stereo(client); - msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", + v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", client->name, state->rev1, state->rev2); - msp_info("Audio: volume %d balance %d bass %d treble %d%s\n", + v4l_info(client, "Audio: volume %d balance %d bass %d treble %d%s\n", state->volume, state->balance, state->bass, state->treble, state->muted ? " (muted)" : ""); - msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), + v4l_info(client, "Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - msp_info("ACB: 0x%04x\n", state->acb); + v4l_info(client, "ACB: 0x%04x\n", state->acb); break; default: @@ -944,7 +944,7 @@ static int msp_suspend(struct device * dev, pm_message_t state) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); - msp_dbg1("suspend\n"); + v4l_dbg(1, client, "suspend\n"); msp_reset(client); return 0; } @@ -953,7 +953,7 @@ static int msp_resume(struct device * dev) { struct i2c_client *client = container_of(dev, struct i2c_client, dev); - msp_dbg1("resume\n"); + v4l_dbg(1, client, "resume\n"); msp_wake_thread(client); return 0; } @@ -979,7 +979,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { - msp_dbg1("msp3400 not found\n"); + v4l_dbg(1, client, "msp3400 not found\n"); kfree(client); return -1; } @@ -1005,9 +1005,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->rev1 = msp_read_dsp(client, 0x1e); if (state->rev1 != -1) state->rev2 = msp_read_dsp(client, 0x1f); - msp_dbg1("rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); + v4l_dbg(1, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - msp_dbg1("not an msp3400 (cannot read chip version)\n"); + v4l_dbg(1, client, "not an msp3400 (cannot read chip version)\n"); kfree(state); kfree(client); return -1; @@ -1035,8 +1035,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) } /* hello world :-) */ - msp_info("%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); - msp_info("%s ", client->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + v4l_info(client, "%s ", client->name); if (HAVE_NICAM(state) && HAVE_RADIO(state)) printk("supports nicam and radio, "); else if (HAVE_NICAM(state)) @@ -1067,7 +1067,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->kthread = kthread_run(thread_func, client, "msp34xx"); if (state->kthread == NULL) - msp_warn("kernel_thread() failed\n"); + v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c new file mode 100644 index 000000000000..934f0d3b9138 --- /dev/null +++ b/drivers/media/video/msp3400-kthreads.c @@ -0,0 +1,1015 @@ +/* + * Programming the mspx4xx sound processor family + * + * (c) 1997-2001 Gerd Knorr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msp3400.h" + +/* this one uses the automatic sound standard detection of newer msp34xx + chip versions */ +static struct { + int retval; + int main, second; + char *name; +} msp_modelist[] = { + { 0x0000, 0, 0, "could not detect sound standard" }, + { 0x0001, 0, 0, "autodetect start" }, + { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, + { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, + { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, + { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, + { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, + { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, + { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, + { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, + { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, + { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, + { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, + { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, + { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, + { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, + { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, + { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, + { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, + { -1, 0, 0, NULL }, /* EOF */ +}; + +static struct msp3400c_init_data_dem { + int fir1[6]; + int fir2[6]; + int cdo1; + int cdo2; + int ad_cv; + int mode_reg; + int dsp_src; + int dsp_matrix; +} msp3400c_init_data[] = { + { /* AM (for carrier detect / msp3400) */ + {75, 19, 36, 35, 39, 40}, + {75, 19, 36, 35, 39, 40}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0500, 0x0020, 0x3000 + },{ /* AM (for carrier detect / msp3410) */ + {-1, -1, -8, 2, 59, 126}, + {-1, -1, -8, 2, 59, 126}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0100, 0x0020, 0x3000 + },{ /* FM Radio */ + {-8, -8, 4, 6, 78, 107}, + {-8, -8, 4, 6, 78, 107}, + MSP_CARRIER(10.7), MSP_CARRIER(10.7), + 0x00d0, 0x0480, 0x0020, 0x3000 + },{ /* Terrestial FM-mono + FM-stereo */ + {3, 18, 27, 48, 66, 72}, + {3, 18, 27, 48, 66, 72}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0480, 0x0030, 0x3000 + },{ /* Sat FM-mono */ + { 1, 9, 14, 24, 33, 37}, + { 3, 18, 27, 48, 66, 72}, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0480, 0x0000, 0x3000 + },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ + {-2, -8, -10, 10, 50, 86}, + {3, 18, 27, 48, 66, 72}, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), + 0x00d0, 0x0040, 0x0120, 0x3000 + },{ /* NICAM/FM -- I (6.0/6.552) */ + {2, 4, -6, -4, 40, 94}, + {3, 18, 27, 48, 66, 72}, + MSP_CARRIER(6.0), MSP_CARRIER(6.0), + 0x00d0, 0x0040, 0x0120, 0x3000 + },{ /* NICAM/AM -- L (6.5/5.85) */ + {-2, -8, -10, 10, 50, 86}, + {-4, -12, -9, 23, 79, 126}, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0140, 0x0120, 0x7c03 + }, +}; + +struct msp3400c_carrier_detect { + int cdo; + char *name; +}; + +static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { + /* main carrier */ + { MSP_CARRIER(4.5), "4.5 NTSC" }, + { MSP_CARRIER(5.5), "5.5 PAL B/G" }, + { MSP_CARRIER(6.0), "6.0 PAL I" }, + { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } +}; + +static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { + /* PAL B/G */ + { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, + { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } +}; + +static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { + /* PAL SAT / SECAM */ + { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, + { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, + { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, + { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, + { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, + { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, +}; + +/* ------------------------------------------------------------------------ */ + +const char *msp_standard_mode_name(int mode) +{ + int i; + + for (i = 0; msp_modelist[i].name != NULL; i++) + if (msp_modelist[i].retval == mode) + return msp_modelist[i].name; + return "unknown"; +} + +void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) +{ + msp_write_dem(client, 0x0093, cdo1 & 0xfff); + msp_write_dem(client, 0x009b, cdo1 >> 12); + msp_write_dem(client, 0x00a3, cdo2 & 0xfff); + msp_write_dem(client, 0x00ab, cdo2 >> 12); + msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ +} + +void msp3400c_setmode(struct i2c_client *client, int type) +{ + struct msp_state *state = i2c_get_clientdata(client); + int i; + + v4l_dbg(1, client, "setmode: %d\n", type); + state->mode = type; + state->audmode = V4L2_TUNER_MODE_MONO; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + + msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv); + + for (i = 5; i >= 0; i--) /* fir 1 */ + msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]); + + msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ + msp_write_dem(client, 0x0005, 0x0040); + msp_write_dem(client, 0x0005, 0x0000); + for (i = 5; i >= 0; i--) + msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]); + + msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg); + + msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1, + msp3400c_init_data[type].cdo2); + + msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ + + if (dolby) { + msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ + msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ + msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src); + } else { + msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src); + msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src); + msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src); + } + msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src); + msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix); + + if (HAVE_NICAM(state)) { + /* nicam prescale */ + msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ + } +} + +/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */ +static int msp3400c_best_video_sound(int rxsubchans) +{ + if (rxsubchans & V4L2_TUNER_SUB_STEREO) + return V4L2_TUNER_MODE_STEREO; + if (rxsubchans & V4L2_TUNER_SUB_LANG1) + return V4L2_TUNER_MODE_LANG1; + if (rxsubchans & V4L2_TUNER_SUB_LANG2) + return V4L2_TUNER_MODE_LANG2; + return V4L2_TUNER_MODE_MONO; +} + +/* turn on/off nicam + stereo */ +void msp3400c_setstereo(struct i2c_client *client, int mode) +{ + static char *strmode[] = { "0", "mono", "stereo", "3", + "lang1", "5", "6", "7", "lang2" + }; + struct msp_state *state = i2c_get_clientdata(client); + int nicam = 0; /* channel source: FM/AM or nicam */ + int src = 0; + + if (state->opmode == OPMODE_AUTOSELECT) { + /* this method would break everything, let's make sure + * it's never called + */ + v4l_dbg(1, client, "setstereo called with mode=%d instead of set_source (ignored)\n", + mode); + return; + } + + /* switch demodulator */ + switch (state->mode) { + case MSP_MODE_FM_TERRA: + v4l_dbg(1, client, "FM setstereo: %s\n", strmode[mode]); + msp3400c_setcarrier(client,state->second,state->main); + switch (mode) { + case V4L2_TUNER_MODE_STEREO: + msp_write_dsp(client, 0x000e, 0x3001); + break; + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + msp_write_dsp(client, 0x000e, 0x3000); + break; + } + break; + case MSP_MODE_FM_SAT: + v4l_dbg(1, client, "SAT setstereo: %s\n", strmode[mode]); + switch (mode) { + case V4L2_TUNER_MODE_MONO: + msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + break; + case V4L2_TUNER_MODE_STEREO: + msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + break; + case V4L2_TUNER_MODE_LANG1: + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + case V4L2_TUNER_MODE_LANG2: + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + } + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + v4l_dbg(1, client, "NICAM setstereo: %s\n",strmode[mode]); + msp3400c_setcarrier(client,state->second,state->main); + if (state->nicam_on) + nicam=0x0100; + break; + case MSP_MODE_BTSC: + v4l_dbg(1, client, "BTSC setstereo: %s\n",strmode[mode]); + nicam=0x0300; + break; + case MSP_MODE_EXTERN: + v4l_dbg(1, client, "extern setstereo: %s\n",strmode[mode]); + nicam = 0x0200; + break; + case MSP_MODE_FM_RADIO: + v4l_dbg(1, client, "FM-Radio setstereo: %s\n",strmode[mode]); + break; + default: + v4l_dbg(1, client, "mono setstereo\n"); + return; + } + + /* switch audio */ + switch (msp3400c_best_video_sound(mode)) { + case V4L2_TUNER_MODE_STEREO: + src = 0x0020 | nicam; + break; + case V4L2_TUNER_MODE_MONO: + if (state->mode == MSP_MODE_AM_NICAM) { + v4l_dbg(1, client, "switching to AM mono\n"); + /* AM mono decoding is handled by tuner, not MSP chip */ + /* SCART switching control register */ + msp_set_scart(client, SCART_MONO, 0); + src = 0x0200; + break; + } + case V4L2_TUNER_MODE_LANG1: + src = 0x0000 | nicam; + break; + case V4L2_TUNER_MODE_LANG2: + src = 0x0010 | nicam; + break; + } + v4l_dbg(1, client, "setstereo final source/matrix = 0x%x\n", src); + + if (dolby) { + msp_write_dsp(client, 0x0008, 0x0520); + msp_write_dsp(client, 0x0009, 0x0620); + msp_write_dsp(client, 0x000a, src); + msp_write_dsp(client, 0x000b, src); + } else { + msp_write_dsp(client, 0x0008, src); + msp_write_dsp(client, 0x0009, src); + msp_write_dsp(client, 0x000a, src); + msp_write_dsp(client, 0x000b, src); + } +} + +static void msp3400c_print_mode(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + if (state->main == state->second) { + v4l_dbg(1, client, "mono sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + } else { + v4l_dbg(1, client, "main sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + } + if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) + v4l_dbg(1, client, "NICAM/FM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second/910) % 1000); + if (state->mode == MSP_MODE_AM_NICAM) + v4l_dbg(1, client, "NICAM/AM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); + if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { + v4l_dbg(1, client, "FM-stereo carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); + } +} + +/* ----------------------------------------------------------------------- */ + +int autodetect_stereo(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + int val; + int rxsubchans = state->rxsubchans; + int newnicam = state->nicam_on; + int update = 0; + + switch (state->mode) { + case MSP_MODE_FM_TERRA: + val = msp_read_dsp(client, 0x18); + if (val > 32767) + val -= 65536; + v4l_dbg(2, client, "stereo detect register: %d\n", val); + if (val > 4096) { + rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + } else if (val < -4096) { + rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + } else { + rxsubchans = V4L2_TUNER_SUB_MONO; + } + newnicam = 0; + break; + case MSP_MODE_FM_NICAM1: + case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: + val = msp_read_dem(client, 0x23); + v4l_dbg(2, client, "nicam sync=%d, mode=%d\n", + val & 1, (val & 0x1e) >> 1); + + if (val & 1) { + /* nicam synced */ + switch ((val & 0x1e) >> 1) { + case 0: + case 8: + rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 1: + case 9: + rxsubchans = V4L2_TUNER_SUB_MONO + | V4L2_TUNER_SUB_LANG1; + break; + case 2: + case 10: + rxsubchans = V4L2_TUNER_SUB_MONO + | V4L2_TUNER_SUB_LANG1 + | V4L2_TUNER_SUB_LANG2; + break; + default: + rxsubchans = V4L2_TUNER_SUB_MONO; + break; + } + newnicam = 1; + } else { + newnicam = 0; + rxsubchans = V4L2_TUNER_SUB_MONO; + } + break; + case MSP_MODE_BTSC: + val = msp_read_dem(client, 0x200); + v4l_dbg(2, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n", + val, + (val & 0x0002) ? "no" : "yes", + (val & 0x0004) ? "no" : "yes", + (val & 0x0040) ? "stereo" : "mono", + (val & 0x0080) ? ", nicam 2nd mono" : "", + (val & 0x0100) ? ", bilingual/SAP" : ""); + rxsubchans = V4L2_TUNER_SUB_MONO; + if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO; + if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; + break; + } + if (rxsubchans != state->rxsubchans) { + update = 1; + v4l_dbg(1, client, "watch: rxsubchans %d => %d\n", + state->rxsubchans,rxsubchans); + state->rxsubchans = rxsubchans; + } + if (newnicam != state->nicam_on) { + update = 1; + v4l_dbg(1, client, "watch: nicam %d => %d\n", + state->nicam_on,newnicam); + state->nicam_on = newnicam; + } + return update; +} + +/* + * A kernel thread for msp3400 control -- we don't want to block the + * in the ioctl while doing the sound carrier & stereo detect + */ +/* stereo/multilang monitoring */ +static void watch_stereo(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + if (autodetect_stereo(client)) { + if (state->stereo & V4L2_TUNER_MODE_STEREO) + msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO); + else if (state->stereo & VIDEO_SOUND_LANG1) + msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1); + else + msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + } + + if (once) + state->watch_stereo = 0; +} + +int msp3400c_thread(void *data) +{ + struct i2c_client *client = data; + struct msp_state *state = i2c_get_clientdata(client); + struct msp3400c_carrier_detect *cd; + int count, max1,max2,val1,val2, val,this; + + + v4l_dbg(1, client, "msp3400 daemon started\n"); + for (;;) { + v4l_dbg(2, client, "msp3400 thread: sleep\n"); + msp_sleep(state, -1); + v4l_dbg(2, client, "msp3400 thread: wakeup\n"); + + restart: + v4l_dbg(1, client, "thread: restart scan\n"); + state->restart = 0; + if (kthread_should_stop()) + break; + + if (VIDEO_MODE_RADIO == state->norm || + MSP_MODE_EXTERN == state->mode) { + /* no carrier scan, just unmute */ + v4l_dbg(1, client, "thread: no carrier scan\n"); + msp_set_audio(client); + continue; + } + + /* mute */ + msp_set_mute(client); + msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); + val1 = val2 = 0; + max1 = max2 = -1; + state->watch_stereo = 0; + + /* some time for the tuner to sync */ + if (msp_sleep(state,200)) + goto restart; + + /* carrier detect pass #1 -- main carrier */ + cd = msp3400c_carrier_detect_main; + count = ARRAY_SIZE(msp3400c_carrier_detect_main); + + if (amsound && (state->norm == VIDEO_MODE_SECAM)) { + /* autodetect doesn't work well with AM ... */ + max1 = 3; + count = 0; + v4l_dbg(1, client, "AM sound override\n"); + } + + for (this = 0; this < count; this++) { + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); + if (msp_sleep(state,100)) + goto restart; + val = msp_read_dsp(client, 0x1b); + if (val > 32767) + val -= 65536; + if (val1 < val) + val1 = val, max1 = this; + v4l_dbg(1, client, "carrier1 val: %5d / %s\n", val,cd[this].name); + } + + /* carrier detect pass #2 -- second (stereo) carrier */ + switch (max1) { + case 1: /* 5.5 */ + cd = msp3400c_carrier_detect_55; + count = ARRAY_SIZE(msp3400c_carrier_detect_55); + break; + case 3: /* 6.5 */ + cd = msp3400c_carrier_detect_65; + count = ARRAY_SIZE(msp3400c_carrier_detect_65); + break; + case 0: /* 4.5 */ + case 2: /* 6.0 */ + default: + cd = NULL; + count = 0; + break; + } + + if (amsound && (state->norm == VIDEO_MODE_SECAM)) { + /* autodetect doesn't work well with AM ... */ + cd = NULL; + count = 0; + max2 = 0; + } + for (this = 0; this < count; this++) { + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); + if (msp_sleep(state,100)) + goto restart; + val = msp_read_dsp(client, 0x1b); + if (val > 32767) + val -= 65536; + if (val2 < val) + val2 = val, max2 = this; + v4l_dbg(1, client, "carrier2 val: %5d / %s\n", val,cd[this].name); + } + + /* program the msp3400 according to the results */ + state->main = msp3400c_carrier_detect_main[max1].cdo; + switch (max1) { + case 1: /* 5.5 */ + if (max2 == 0) { + /* B/G FM-stereo */ + state->second = msp3400c_carrier_detect_55[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + state->nicam_on = 0; + msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + state->watch_stereo = 1; + } else if (max2 == 1 && HAVE_NICAM(state)) { + /* B/G NICAM */ + state->second = msp3400c_carrier_detect_55[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + state->nicam_on = 1; + msp3400c_setcarrier(client, state->second, state->main); + state->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 2: /* 6.0 */ + /* PAL I NICAM */ + state->second = MSP_CARRIER(6.552); + msp3400c_setmode(client, MSP_MODE_FM_NICAM2); + state->nicam_on = 1; + msp3400c_setcarrier(client, state->second, state->main); + state->watch_stereo = 1; + break; + case 3: /* 6.5 */ + if (max2 == 1 || max2 == 2) { + /* D/K FM-stereo */ + state->second = msp3400c_carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + state->nicam_on = 0; + msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + state->watch_stereo = 1; + } else if (max2 == 0 && + state->norm == VIDEO_MODE_SECAM) { + /* L NICAM or AM-mono */ + state->second = msp3400c_carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_AM_NICAM); + state->nicam_on = 0; + msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + msp3400c_setcarrier(client, state->second, state->main); + /* volume prescale for SCART (AM mono input) */ + msp_write_dsp(client, 0x000d, 0x1900); + state->watch_stereo = 1; + } else if (max2 == 0 && HAVE_NICAM(state)) { + /* D/K NICAM */ + state->second = msp3400c_carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + state->nicam_on = 1; + msp3400c_setcarrier(client, state->second, state->main); + state->watch_stereo = 1; + } else { + goto no_second; + } + break; + case 0: /* 4.5 */ + default: + no_second: + state->second = msp3400c_carrier_detect_main[max1].cdo; + msp3400c_setmode(client, MSP_MODE_FM_TERRA); + state->nicam_on = 0; + msp3400c_setcarrier(client, state->second, state->main); + state->rxsubchans = V4L2_TUNER_SUB_MONO; + msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + break; + } + + /* unmute */ + msp_set_audio(client); + + if (debug) + msp3400c_print_mode(client); + + /* monitor tv audio mode */ + while (state->watch_stereo) { + if (msp_sleep(state,5000)) + goto restart; + watch_stereo(client); + } + } + v4l_dbg(1, client, "thread: exit\n"); + return 0; +} + + +int msp3410d_thread(void *data) +{ + struct i2c_client *client = data; + struct msp_state *state = i2c_get_clientdata(client); + int mode,val,i,std; + + v4l_dbg(1, client, "msp3410 daemon started\n"); + + for (;;) { + v4l_dbg(2, client, "msp3410 thread: sleep\n"); + msp_sleep(state,-1); + v4l_dbg(2, client, "msp3410 thread: wakeup\n"); + + restart: + v4l_dbg(1, client, "thread: restart scan\n"); + state->restart = 0; + if (kthread_should_stop()) + break; + + if (state->mode == MSP_MODE_EXTERN) { + /* no carrier scan needed, just unmute */ + v4l_dbg(1, client, "thread: no carrier scan\n"); + msp_set_audio(client); + continue; + } + + /* put into sane state (and mute) */ + msp_reset(client); + + /* some time for the tuner to sync */ + if (msp_sleep(state,200)) + goto restart; + + /* start autodetect */ + mode = msp_modus(client, state->norm); + std = msp_standard(state->norm); + msp_write_dem(client, 0x30, mode); + msp_write_dem(client, 0x20, std); + state->watch_stereo = 0; + + if (debug) + v4l_dbg(1, client, "setting mode: %s (0x%04x)\n", + msp_standard_mode_name(std), std); + + if (std != 1) { + /* programmed some specific mode */ + val = std; + } else { + /* triggered autodetect */ + for (;;) { + if (msp_sleep(state,100)) + goto restart; + + /* check results */ + val = msp_read_dem(client, 0x7e); + if (val < 0x07ff) + break; + v4l_dbg(1, client, "detection still in progress\n"); + } + } + for (i = 0; msp_modelist[i].name != NULL; i++) + if (msp_modelist[i].retval == val) + break; + v4l_dbg(1, client, "current mode: %s (0x%04x)\n", + msp_standard_mode_name(val), val); + state->main = msp_modelist[i].main; + state->second = msp_modelist[i].second; + + if (amsound && (state->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { + /* autodetection has failed, let backup */ + v4l_dbg(1, client, "autodetection failed," + " switching to backup mode: %s (0x%04x)\n", + msp_modelist[8].name ? msp_modelist[8].name : "unknown",val); + val = 0x0009; + msp_write_dem(client, 0x20, val); + } + + /* set various prescales */ + msp_write_dsp(client, 0x0d, 0x1900); /* scart */ + msp_write_dsp(client, 0x0e, 0x2403); /* FM */ + msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ + + /* set stereo */ + switch (val) { + case 0x0008: /* B/G NICAM */ + case 0x000a: /* I NICAM */ + if (val == 0x0008) + state->mode = MSP_MODE_FM_NICAM1; + else + state->mode = MSP_MODE_FM_NICAM2; + /* just turn on stereo */ + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->nicam_on = 1; + state->watch_stereo = 1; + msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); + break; + case 0x0009: + state->mode = MSP_MODE_AM_NICAM; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + state->nicam_on = 1; + msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO); + state->watch_stereo = 1; + break; + case 0x0020: /* BTSC */ + /* just turn on stereo */ + state->mode = MSP_MODE_BTSC; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->nicam_on = 0; + state->watch_stereo = 1; + msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); + break; + case 0x0040: /* FM radio */ + state->mode = MSP_MODE_FM_RADIO; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + state->audmode = V4L2_TUNER_MODE_STEREO; + state->nicam_on = 0; + state->watch_stereo = 0; + /* not needed in theory if HAVE_RADIO(), but + short programming enables carrier mute */ + msp3400c_setmode(client,MSP_MODE_FM_RADIO); + msp3400c_setcarrier(client, MSP_CARRIER(10.7), + MSP_CARRIER(10.7)); + /* scart routing */ + msp_set_scart(client,SCART_IN2,0); + /* msp34xx does radio decoding */ + msp_write_dsp(client, 0x08, 0x0020); + msp_write_dsp(client, 0x09, 0x0020); + msp_write_dsp(client, 0x0b, 0x0020); + break; + case 0x0003: + case 0x0004: + case 0x0005: + state->mode = MSP_MODE_FM_TERRA; + state->rxsubchans = V4L2_TUNER_SUB_MONO; + state->audmode = V4L2_TUNER_MODE_MONO; + state->nicam_on = 0; + state->watch_stereo = 1; + break; + } + + /* unmute, restore misc registers */ + msp_set_audio(client); + msp_write_dsp(client, 0x13, state->acb); + msp_write_dem(client, 0x40, state->i2s_mode); + + /* monitor tv audio mode */ + while (state->watch_stereo) { + if (msp_sleep(state,5000)) + goto restart; + watch_stereo(client); + } + } + v4l_dbg(1, client, "thread: exit\n"); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* msp34xxG + (autoselect no-thread) */ +/* this one uses both automatic standard detection and automatic sound */ +/* select which are available in the newer G versions */ +/* struct msp: only norm, acb and source are really used in this mode */ + +/* set the same 'source' for the loudspeaker, scart and quasi-peak detector + * the value for source is the same as bit 15:8 of DSP registers 0x08, + * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B + * + * this function replaces msp3400c_setstereo + */ +static void msp34xxg_set_source(struct i2c_client *client, int source) +{ + struct msp_state *state = i2c_get_clientdata(client); + + /* fix matrix mode to stereo and let the msp choose what + * to output according to 'source', as recommended + * for MONO (source==0) downmixing set bit[7:0] to 0x30 + */ + int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20); + + v4l_dbg(1, client, "set source to %d (0x%x)\n", source, value); + /* Loudspeaker Output */ + msp_write_dsp(client, 0x08, value); + /* SCART1 DA Output */ + msp_write_dsp(client, 0x0a, value); + /* Quasi-peak detector */ + msp_write_dsp(client, 0x0c, value); + /* + * set identification threshold. Personally, I + * I set it to a higher value that the default + * of 0x190 to ignore noisy stereo signals. + * this needs tuning. (recommended range 0x00a0-0x03c0) + * 0x7f0 = forced mono mode + */ + /* a2 threshold for stereo/bilingual */ + msp_write_dem(client, 0x22, stereo_threshold); + state->source = source; +} + +/* (re-)initialize the msp34xxg, according to the current norm in state->norm + * return 0 if it worked, -1 if it failed + */ +static int msp34xxg_reset(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + int modus, std; + + if (msp_reset(client)) + return -1; + + /* make sure that input/output is muted (paranoid mode) */ + /* ACB, mute DSP input, mute SCART 1 */ + if (msp_write_dsp(client, 0x13, 0x0f20)) + return -1; + + msp_write_dem(client, 0x40, state->i2s_mode); + + /* step-by-step initialisation, as described in the manual */ + modus = msp_modus(client, state->norm); + std = msp_standard(state->norm); + modus &= ~0x03; /* STATUS_CHANGE = 0 */ + modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ + if (msp_write_dem(client, 0x30, modus)) + return -1; + if (msp_write_dem(client, 0x20, std)) + return -1; + + /* write the dsps that may have an influence on + standard/audio autodetection right now */ + msp34xxg_set_source(client, state->source); + + /* AM/FM Prescale [15:8] 75khz deviation */ + if (msp_write_dsp(client, 0x0e, 0x3000)) + return -1; + + /* NICAM Prescale 9db gain (as recommended) */ + if (msp_write_dsp(client, 0x10, 0x5a00)) + return -1; + + return 0; +} + +int msp34xxg_thread(void *data) +{ + struct i2c_client *client = data; + struct msp_state *state = i2c_get_clientdata(client); + int val, std, i; + + v4l_dbg(1, client, "msp34xxg daemon started\n"); + + state->source = 1; /* default */ + for (;;) { + v4l_dbg(2, client, "msp34xxg thread: sleep\n"); + msp_sleep(state, -1); + v4l_dbg(2, client, "msp34xxg thread: wakeup\n"); + + restart: + v4l_dbg(1, client, "thread: restart scan\n"); + state->restart = 0; + if (kthread_should_stop()) + break; + + /* setup the chip*/ + msp34xxg_reset(client); + std = standard; + if (std != 0x01) + goto unmute; + + /* watch autodetect */ + v4l_dbg(1, client, "triggered autodetect, waiting for result\n"); + for (i = 0; i < 10; i++) { + if (msp_sleep(state, 100)) + goto restart; + + /* check results */ + val = msp_read_dem(client, 0x7e); + if (val < 0x07ff) { + std = val; + break; + } + v4l_dbg(2, client, "detection still in progress\n"); + } + if (std == 1) { + v4l_dbg(1, client, "detection still in progress after 10 tries. giving up.\n"); + continue; + } + + unmute: + state->mode = std; + v4l_dbg(1, client, "current mode: %s (0x%04x)\n", + msp_standard_mode_name(std), std); + + /* unmute: dispatch sound to scart output, set scart volume */ + msp_set_audio(client); + + /* restore ACB */ + if (msp_write_dsp(client, 0x13, state->acb)) + return -1; + + msp_write_dem(client, 0x40, state->i2s_mode); + } + v4l_dbg(1, client, "thread: exit\n"); + return 0; +} + +void msp34xxg_detect_stereo(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + int status = msp_read_dem(client, 0x0200); + int is_bilingual = status & 0x100; + int is_stereo = status & 0x40; + + state->rxsubchans = 0; + if (is_stereo) + state->rxsubchans |= V4L2_TUNER_SUB_STEREO; + else + state->rxsubchans |= V4L2_TUNER_SUB_MONO; + if (is_bilingual) { + state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + /* I'm supposed to check whether it's SAP or not + * and set only LANG2/SAP in this case. Yet, the MSP + * does a lot of work to hide this and handle everything + * the same way. I don't want to work around it so unless + * this is a problem, I'll handle SAP just like lang1/lang2. + */ + } + v4l_dbg(1, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", + status, is_stereo, is_bilingual, state->rxsubchans); +} + +void msp34xxg_set_audmode(struct i2c_client *client, int audmode) +{ + struct msp_state *state = i2c_get_clientdata(client); + int source; + + switch (audmode) { + case V4L2_TUNER_MODE_MONO: + source = 0; /* mono only */ + break; + case V4L2_TUNER_MODE_STEREO: + source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ + /* problem: that could also mean 2 (scart input) */ + break; + case V4L2_TUNER_MODE_LANG1: + source = 3; /* stereo or A */ + break; + case V4L2_TUNER_MODE_LANG2: + source = 4; /* stereo or B */ + break; + default: + audmode = 0; + source = 1; + break; + } + state->audmode = audmode; + msp34xxg_set_source(client, source); +} + diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 33d64ac75d37..a88a22e37e64 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -6,40 +6,6 @@ /* ---------------------------------------------------------------------- */ -#define msp_err(fmt, arg...) \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg) -#define msp_warn(fmt, arg...) \ - printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg) -#define msp_info(fmt, arg...) \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg) - -/* level 1 debug. */ -#define msp_dbg1(fmt, arg...) \ - do { \ - if (debug) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -/* level 2 debug. */ -#define msp_dbg2(fmt, arg...) \ - do { \ - if (debug >= 2) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -/* level 3 debug. Use with care. */ -#define msp_dbg3(fmt, arg...) \ - do { \ - if (debug >= 16) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - struct msp_matrix { int input; int output; diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 9ee616261d66..c5ca993679ec 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -26,6 +26,57 @@ #ifndef V4L2_COMMON_H_ #define V4L2_COMMON_H_ +/* v4l debugging and diagnostics */ + +/* Common printk constucts for v4l-i2c drivers. These macros create a unique + prefix consisting of the driver name, the adapter number and the i2c + address. */ +#define v4l_printk(level, name, adapter, addr, fmt, arg...) \ + printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg) + +#define v4l_client_printk(level, client, fmt, arg...) \ + v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \ + (client)->addr, fmt , ## arg) + +#define v4l_err(client, fmt, arg...) \ + v4l_client_printk(KERN_ERR, client, fmt , ## arg) + +#define v4l_warn(client, fmt, arg...) \ + v4l_client_printk(KERN_WARNING, client, fmt , ## arg) + +#define v4l_info(client, fmt, arg...) \ + v4l_client_printk(KERN_INFO, client, fmt , ## arg) + +/* These three macros assume that the debug level is set with a module + parameter called 'debug'. */ +#define v4l_dbg(level, client, fmt, arg...) \ + do { \ + if (debug >= (level)) \ + v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \ + } while (0) + +/* Prints the ioctl in a human-readable format */ +extern void v4l_printk_ioctl(unsigned int cmd); + +/* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */ +#define v4l_print_ioctl(name, cmd) \ + do { \ + printk(KERN_DEBUG "%s: ", name); \ + v4l_printk_ioctl(cmd); \ + } while (0) + +/* Use this macro in I2C drivers where 'client' is the struct i2c_client + pointer */ +#define v4l_i2c_print_ioctl(client, cmd) \ + do { \ + v4l_client_printk(KERN_DEBUG, client, ""); \ + v4l_printk_ioctl(cmd); \ + } while (0) + +/* ------------------------------------------------------------------------- */ + +/* Internal ioctls */ + /* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */ struct v4l2_register { u32 i2c_id; /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */ @@ -122,16 +173,4 @@ enum v4l2_chip_ident { If the frequency is not supported, then -EINVAL is returned. */ #define VIDIOC_INT_I2S_CLOCK_FREQ _IOW ('d', 108, u32) -/* Prints used ioctl */ -extern void v4l_printk_ioctl(unsigned int cmd); - -#define v4l_print_ioctl(name,cmd) do {\ - printk(KERN_DEBUG "%s: ", name); \ - v4l_printk_ioctl(cmd); } while (0) - -#define v4l_i2c_print_ioctl(client,cmd) do {\ - printk(KERN_DEBUG "%s %d-%04x: ", (client)->driver->name, \ - i2c_adapter_id((client)->adapter),(client)->addr); \ - v4l_printk_ioctl(cmd); } while (0) - #endif /* V4L2_COMMON_H_ */ -- cgit v1.2.3 From 0e7072ef6623c3dc58faf3f7310aba77b0a5845e Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:32:40 -0200 Subject: V4L/DVB (3277): Fix incorrect filename reference in top comments - Fix incorrect filename reference in top comments Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index f99ee8eb5577..33de9d846af5 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -1,5 +1,5 @@ /* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices + em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices Copyright (C) 2005 Markus Rechberger Ludovico Cavedon -- cgit v1.2.3 From fac9e89999a12f378112fe93764b30196bc03f46 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:40 -0200 Subject: V4L/DVB (3278): convert diagnostics over to the new v4l2-common.h macros. - Convert diagnostics over to the new v4l2-common.h macros. - deprecated tuner_debug option, the new option is debug. - renamed cx25840_debug to debug. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs53l32a.c | 29 +++------ drivers/media/video/cx25840/cx25840-core.c | 70 ++++++++++----------- drivers/media/video/cx25840/cx25840-firmware.c | 13 ++-- drivers/media/video/cx25840/cx25840.h | 16 ----- drivers/media/video/msp3400-driver.c | 6 +- drivers/media/video/mt20xx.c | 9 ++- drivers/media/video/saa7115.c | 87 +++++++++++--------------- drivers/media/video/saa7127.c | 78 ++++++++--------------- drivers/media/video/tea5767.c | 5 +- drivers/media/video/tuner-core.c | 16 +++-- drivers/media/video/tvaudio.c | 81 ++++++++++-------------- drivers/media/video/tveeprom.c | 17 +++-- drivers/media/video/wm8775.c | 20 ++---- include/media/tuner.h | 4 +- include/media/v4l2-common.h | 1 + 15 files changed, 186 insertions(+), 266 deletions(-) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index 7d997aeda63e..b421068f7ea3 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); @@ -39,21 +39,6 @@ module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); -#define cs53l32a_dbg(fmt, arg...) \ - do { \ - if (debug) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -#define cs53l32a_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define cs53l32a_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; @@ -84,7 +69,7 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, the second goes through the PGA. Hence there are three possible inputs to choose from. */ if (input->index > 2) { - cs53l32a_err("Invalid input %d.\n", input->index); + v4l_err(client, "Invalid input %d.\n", input->index); return -EINVAL; } cs53l32a_write(client, 0x01, 0x01 + (input->index << 4)); @@ -124,9 +109,9 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, u8 m = cs53l32a_read(client, 0x03); s8 vol = cs53l32a_read(client, 0x04); - cs53l32a_info("Input: %d%s\n", (v >> 4) & 3, + v4l_info(client, "Input: %d%s\n", (v >> 4) & 3, (m & 0xC0) ? " (muted)" : ""); - cs53l32a_info("Volume: %d dB\n", vol); + v4l_info(client, "Volume: %d dB\n", vol); break; } @@ -166,12 +151,12 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); - cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); - cs53l32a_dbg("Read Reg %d %02x\n", i, v); + v4l_dbg(1, client, "Read Reg %d %02x\n", i, v); } /* Set cs53l32a internal register for Adaptec 2010/2410 setup */ @@ -189,7 +174,7 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); - cs53l32a_dbg("Read Reg %d %02x\n", i, v); + v4l_dbg(1, client, "Read Reg %d %02x\n", i, v); } i2c_attach_client(client); diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 07607264bd41..2bf057ec626c 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -43,11 +43,11 @@ MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; -int cx25840_debug = 0; +int debug = 0; -module_param(cx25840_debug, bool, 0644); +module_param(debug, bool, 0644); -MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]"); +MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); I2C_CLIENT_INSMOD; @@ -265,7 +265,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input <= CX25840_COMPOSITE8); u8 reg; - cx25840_dbg("decoder set video input %d, audio input %d\n", + v4l_dbg(1, client, "decoder set video input %d, audio input %d\n", vid_input, aud_input); if (is_composite) { @@ -277,7 +277,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp if ((vid_input & ~0xff0) || luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { - cx25840_err("0x%04x is not a valid video input!\n", vid_input); + v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); return -EINVAL; } reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); @@ -301,7 +301,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; default: - cx25840_err("0x%04x is not a valid audio input!\n", aud_input); + v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); return -EINVAL; } @@ -396,7 +396,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) case V4L2_CID_BRIGHTNESS: if (ctrl->value < 0 || ctrl->value > 255) { - cx25840_err("invalid brightness setting %d\n", + v4l_err(client, "invalid brightness setting %d\n", ctrl->value); return -ERANGE; } @@ -406,7 +406,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) case V4L2_CID_CONTRAST: if (ctrl->value < 0 || ctrl->value > 127) { - cx25840_err("invalid contrast setting %d\n", + v4l_err(client, "invalid contrast setting %d\n", ctrl->value); return -ERANGE; } @@ -416,7 +416,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) case V4L2_CID_SATURATION: if (ctrl->value < 0 || ctrl->value > 127) { - cx25840_err("invalid saturation setting %d\n", + v4l_err(client, "invalid saturation setting %d\n", ctrl->value); return -ERANGE; } @@ -427,7 +427,7 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) case V4L2_CID_HUE: if (ctrl->value < -127 || ctrl->value > 127) { - cx25840_err("invalid hue setting %d\n", ctrl->value); + v4l_err(client, "invalid hue setting %d\n", ctrl->value); return -ERANGE; } @@ -515,7 +515,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - cx25840_err("%dx%d is not a valid size!\n", + v4l_err(client, "%dx%d is not a valid size!\n", pix->width, pix->height); return -ERANGE; } @@ -533,7 +533,7 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) else filter = 3; - cx25840_dbg("decoder set size %dx%d -> scale %ux%u\n", + v4l_dbg(1, client, "decoder set size %dx%d -> scale %ux%u\n", pix->width, pix->height, HSC, VSC); /* HSCALE=HSC */ @@ -602,13 +602,13 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, return cx25840_audio(client, cmd, arg); case VIDIOC_STREAMON: - cx25840_dbg("enable output\n"); + v4l_dbg(1, client, "enable output\n"); cx25840_write(client, 0x115, 0x8c); cx25840_write(client, 0x116, 0x07); break; case VIDIOC_STREAMOFF: - cx25840_dbg("disable output\n"); + v4l_dbg(1, client, "disable output\n"); cx25840_write(client, 0x115, 0x00); cx25840_write(client, 0x116, 0x00); break; @@ -774,7 +774,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, client->driver = &i2c_driver_cx25840; snprintf(client->name, sizeof(client->name) - 1, "cx25840"); - cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1); + v4l_dbg(1, client, "detecting cx25840 client on address 0x%x\n", address << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); @@ -782,12 +782,12 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, /* The high byte of the device ID should be * 0x84 if chip is present */ if ((device_id & 0xff00) != 0x8400) { - cx25840_dbg("cx25840 not found\n"); + v4l_dbg(1, client, "cx25840 not found\n"); kfree(client); return 0; } - cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n", + v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3, address << 1, adapter->name); @@ -891,9 +891,9 @@ static void log_status(struct i2c_client *client) int aud_input = state->aud_input; char *p; - cx25840_info("Video signal: %spresent\n", + v4l_info(client, "Video signal: %spresent\n", (microctrl_vidfmt & 0x10) ? "" : "not "); - cx25840_info("Detected format: %s\n", + v4l_info(client, "Detected format: %s\n", fmt_strs[gen_stat1 & 0xf]); switch (mod_det_stat0) { @@ -908,7 +908,7 @@ static void log_status(struct i2c_client *client) case 0xfe: p = "forced mode"; break; default: p = "not defined"; } - cx25840_info("Detected audio mode: %s\n", p); + v4l_info(client, "Detected audio mode: %s\n", p); switch (mod_det_stat1) { case 0x00: p = "not defined"; break; @@ -934,10 +934,10 @@ static void log_status(struct i2c_client *client) case 0xff: p = "no detected audio standard"; break; default: p = "not defined"; } - cx25840_info("Detected audio standard: %s\n", p); - cx25840_info("Audio muted: %s\n", + v4l_info(client, "Detected audio standard: %s\n", p); + v4l_info(client, "Audio muted: %s\n", (mute_ctl & 0x2) ? "yes" : "no"); - cx25840_info("Audio microcontroller: %s\n", + v4l_info(client, "Audio microcontroller: %s\n", (download_ctl & 0x10) ? "running" : "stopped"); switch (audio_config >> 4) { @@ -959,7 +959,7 @@ static void log_status(struct i2c_client *client) case 0x0f: p = "automatic detection"; break; default: p = "undefined"; } - cx25840_info("Configured audio standard: %s\n", p); + v4l_info(client, "Configured audio standard: %s\n", p); if ((audio_config >> 4) < 0xF) { switch (audio_config & 0xF) { @@ -976,7 +976,7 @@ static void log_status(struct i2c_client *client) case 0x0a: p = "SAP"; break; default: p = "undefined"; } - cx25840_info("Configured audio mode: %s\n", p); + v4l_info(client, "Configured audio mode: %s\n", p); } else { switch (audio_config & 0xF) { case 0x00: p = "BG"; break; @@ -992,27 +992,27 @@ static void log_status(struct i2c_client *client) case 0x0f: p = "automatic standard and mode detection"; break; default: p = "undefined"; } - cx25840_info("Configured audio system: %s\n", p); + v4l_info(client, "Configured audio system: %s\n", p); } - cx25840_info("Specified standard: %s\n", + v4l_info(client, "Specified standard: %s\n", vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); if (vid_input >= CX25840_COMPOSITE1 && vid_input <= CX25840_COMPOSITE8) { - cx25840_info("Specified video input: Composite %d\n", + v4l_info(client, "Specified video input: Composite %d\n", vid_input - CX25840_COMPOSITE1 + 1); } else { - cx25840_info("Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); } if (aud_input) { - cx25840_info("Specified audio input: Tuner (In%d)\n", aud_input); + v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); } else { - cx25840_info("Specified audio input: External\n"); + v4l_info(client, "Specified audio input: External\n"); } - cx25840_info("Specified audioclock freq: %d Hz\n", state->audclk_freq); + v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); switch (pref_mode & 0xf) { case 0: p = "mono/language A"; break; @@ -1025,7 +1025,7 @@ static void log_status(struct i2c_client *client) case 7: p = "language AB"; break; default: p = "undefined"; } - cx25840_info("Preferred audio mode: %s\n", p); + v4l_info(client, "Preferred audio mode: %s\n", p); if ((audio_config & 0xf) == 0xf) { switch ((afc0 >> 3) & 0x3) { @@ -1034,7 +1034,7 @@ static void log_status(struct i2c_client *client) case 2: p = "autodetect"; break; default: p = "undefined"; } - cx25840_info("Selected 65 MHz format: %s\n", p); + v4l_info(client, "Selected 65 MHz format: %s\n", p); switch (afc0 & 0x7) { case 0: p = "chroma"; break; @@ -1044,6 +1044,6 @@ static void log_status(struct i2c_client *client) case 4: p = "autodetect"; break; default: p = "undefined"; } - cx25840_info("Selected 45 MHz format: %s\n", p); + v4l_info(client, "Selected 45 MHz format: %s\n", p); } } diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index f43024f2aaef..12a73e64f756 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -83,11 +83,11 @@ static inline int check_fw_load(struct i2c_client *client, int size) s |= cx25840_read(client, 0x800); if (size != s) { - cx25840_err("firmware %s load failed\n", firmware); + v4l_err(client, "firmware %s load failed\n", firmware); return -EINVAL; } - cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size); + v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size); return 0; } @@ -98,7 +98,7 @@ static inline int fw_write(struct i2c_client *client, u8 * data, int size) if ((sent = i2c_master_send(client, data, size)) < size) { if (fastfw) { - cx25840_err("333MHz i2c firmware load failed\n"); + v4l_err(client, "333MHz i2c firmware load failed\n"); fastfw = 0; set_i2c_delay(client, 10); @@ -111,13 +111,12 @@ static inline int fw_write(struct i2c_client *client, u8 * data, int size) } if (i2c_master_send(client, data, size) < size) { - cx25840_err - ("100MHz i2c firmware load failed\n"); + v4l_err(client, "100MHz i2c firmware load failed\n"); return -ENOSYS; } } else { - cx25840_err("firmware load i2c failure\n"); + v4l_err(client, "firmware load i2c failure\n"); return -ENOSYS; } @@ -133,7 +132,7 @@ int cx25840_loadfw(struct i2c_client *client) int size, send, retval; if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { - cx25840_err("unable to open firmware %s\n", firmware); + v4l_err(client, "unable to open firmware %s\n", firmware); return -EINVAL; } diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index dc58d4292a34..4260c3faa37a 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -20,25 +20,9 @@ #ifndef _CX25840_H_ #define _CX25840_H_ - #include #include -extern int cx25840_debug; - -#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - -#define cx25840_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - -#define cx25840_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is present in Hauppauge PVR-150 (and possibly PVR-500) cards that have certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 4c0c7bed2edf..eece5fe46cbe 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -80,12 +80,12 @@ int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual module_param(opmode, int, 0444); /* read-write */ -module_param(once, int, 0644); +module_param(once, bool, 0644); module_param(debug, int, 0644); module_param(stereo_threshold, int, 0644); module_param(standard, int, 0644); -module_param(amsound, int, 0644); -module_param(dolby, int, 0644); +module_param(amsound, bool, 0644); +module_param(dolby, bool, 0644); MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index e2df722ebaeb..2c19c9588c02 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -20,6 +20,9 @@ module_param(tv_antenna, int, 0644); static unsigned int radio_antenna = 0; module_param(radio_antenna, int, 0644); +/* from tuner-core.c */ +extern int debug; + /* ---------------------------------------------------------------------- */ #define MT2032 0x04 @@ -401,7 +404,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned div2a=(lo2/8)-1; div2b=lo2-(div2a+1)*8; - if (tuner_debug > 1) { + if (debug > 1) { tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", num1,num2,div1a,div1b,div2a,div2b); @@ -417,7 +420,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned buf[5]=div2a; if(num2!=0) buf[5]=buf[5]|0x40; - if (tuner_debug > 1) { + if (debug > 1) { int i; tuner_dbg("bufs is: "); for(i=0;i<6;i++) @@ -505,7 +508,7 @@ int microtune_init(struct i2c_client *c) i2c_master_send(c,buf,1); i2c_master_recv(c,buf,21); - if (tuner_debug) { + if (debug) { int i; tuner_dbg("MT20xx hexdump:"); for(i=0;i<21;i++) { diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index cf530b94cd12..6cc13311bc2c 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -47,25 +47,10 @@ MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); MODULE_LICENSE("GPL"); static int debug = 0; -module_param(debug, int, 0644); +module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -#define saa7115_dbg(fmt,arg...) \ - do { \ - if (debug) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -#define saa7115_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define saa7115_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END }; @@ -564,7 +549,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) u32 hz; u64 f; - saa7115_dbg("set audio clock freq: %d\n", freq); + v4l_dbg(1, client, "set audio clock freq: %d\n", freq); /* sanity check */ if (freq < 32000 || freq > 48000) @@ -599,7 +584,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: if (ctrl->value < 0 || ctrl->value > 255) { - saa7115_err("invalid brightness setting %d\n", ctrl->value); + v4l_err(client, "invalid brightness setting %d\n", ctrl->value); return -ERANGE; } @@ -609,7 +594,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c case V4L2_CID_CONTRAST: if (ctrl->value < 0 || ctrl->value > 127) { - saa7115_err("invalid contrast setting %d\n", ctrl->value); + v4l_err(client, "invalid contrast setting %d\n", ctrl->value); return -ERANGE; } @@ -619,7 +604,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c case V4L2_CID_SATURATION: if (ctrl->value < 0 || ctrl->value > 127) { - saa7115_err("invalid saturation setting %d\n", ctrl->value); + v4l_err(client, "invalid saturation setting %d\n", ctrl->value); return -ERANGE; } @@ -629,7 +614,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c case V4L2_CID_HUE: if (ctrl->value < -127 || ctrl->value > 127) { - saa7115_err("invalid hue setting %d\n", ctrl->value); + v4l_err(client, "invalid hue setting %d\n", ctrl->value); return -ERANGE; } @@ -685,10 +670,10 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) // This works for NTSC-M, SECAM-L and the 50Hz PAL variants. if (std & V4L2_STD_525_60) { - saa7115_dbg("decoder set standard 60 Hz\n"); + v4l_dbg(1, client, "decoder set standard 60 Hz\n"); saa7115_writeregs(client, saa7115_cfg_60hz_video); } else { - saa7115_dbg("decoder set standard 50 Hz\n"); + v4l_dbg(1, client, "decoder set standard 50 Hz\n"); saa7115_writeregs(client, saa7115_cfg_50hz_video); } @@ -717,13 +702,13 @@ static void saa7115_log_status(struct i2c_client *client) int signalOk; int vcr; - saa7115_info("Audio frequency: %d Hz\n", state->audclk_freq); + v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq); if (client->name[6] == '4') { /* status for the saa7114 */ reg1f = saa7115_read(client, 0x1f); signalOk = (reg1f & 0xc1) == 0x81; - saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad"); - saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); + v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad"); + v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); return; } @@ -735,25 +720,25 @@ static void saa7115_log_status(struct i2c_client *client) vcr = !(reg1f & 0x10); if (state->input >= 6) { - saa7115_info("Input: S-Video %d\n", state->input - 6); + v4l_info(client, "Input: S-Video %d\n", state->input - 6); } else { - saa7115_info("Input: Composite %d\n", state->input); + v4l_info(client, "Input: Composite %d\n", state->input); } - saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); - saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); + v4l_info(client, "Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); + v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz"); switch (reg1e & 0x03) { case 1: - saa7115_info("Detected format: NTSC\n"); + v4l_info(client, "Detected format: NTSC\n"); break; case 2: - saa7115_info("Detected format: PAL\n"); + v4l_info(client, "Detected format: PAL\n"); break; case 3: - saa7115_info("Detected format: SECAM\n"); + v4l_info(client, "Detected format: SECAM\n"); break; default: - saa7115_info("Detected format: BW/No color\n"); + v4l_info(client, "Detected format: BW/No color\n"); break; } } @@ -878,7 +863,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt pix = &(fmt->fmt.pix); - saa7115_dbg("decoder set size\n"); + v4l_dbg(1, client, "decoder set size\n"); /* FIXME need better bounds checking here */ if ((pix->width < 1) || (pix->width > 1440)) @@ -904,7 +889,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt HPSC = HPSC ? HPSC : 1; HFSC = (int)((1024 * 720) / (HPSC * pix->width)); - saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); + v4l_dbg(1, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); /* FIXME hardcodes to "Task B" * write H prescaler integer */ saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f)); @@ -918,10 +903,10 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff)); } else { if (is_50hz) { - saa7115_dbg("Setting full 50hz width\n"); + v4l_dbg(1, client, "Setting full 50hz width\n"); saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x); } else { - saa7115_dbg("Setting full 60hz width\n"); + v4l_dbg(1, client, "Setting full 60hz width\n"); saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); } } @@ -930,7 +915,7 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt if (pix->height != Vsrc) { VSCY = (int)((1024 * Vsrc) / pix->height); - saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); + v4l_dbg(1, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); /* Correct Contrast and Luminance */ saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY)); @@ -944,10 +929,10 @@ static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff)); } else { if (is_50hz) { - saa7115_dbg("Setting full 50Hz height\n"); + v4l_dbg(1, client, "Setting full 50Hz height\n"); saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y); } else { - saa7115_dbg("Setting full 60hz height\n"); + v4l_dbg(1, client, "Setting full 60hz height\n"); saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); } } @@ -1052,7 +1037,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar break; status = saa7115_read(client, 0x1f); - saa7115_dbg("status: 0x%02x\n", status); + v4l_dbg(1, client, "status: 0x%02x\n", status); vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0; break; } @@ -1085,7 +1070,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar break; case VIDIOC_S_INPUT: - saa7115_dbg("decoder set input %d\n", *iarg); + v4l_dbg(1, client, "decoder set input %d\n", *iarg); /* inputs from 0-9 are available */ if (*iarg < 0 || *iarg > 9) { return -EINVAL; @@ -1093,7 +1078,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar if (state->input == *iarg) break; - saa7115_dbg("now setting %s input\n", + v4l_dbg(1, client, "now setting %s input\n", *iarg >= 6 ? "S-Video" : "Composite"); state->input = *iarg; @@ -1110,7 +1095,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar case VIDIOC_STREAMON: case VIDIOC_STREAMOFF: - saa7115_dbg("%s output\n", + v4l_dbg(1, client, "%s output\n", (cmd == VIDIOC_STREAMON) ? "enable" : "disable"); if (state->enable != (cmd == VIDIOC_STREAMON)) { @@ -1124,7 +1109,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar break; case VIDIOC_INT_RESET: - saa7115_dbg("decoder RESET\n"); + v4l_dbg(1, client, "decoder RESET\n"); saa7115_writeregs(client, saa7115_cfg_reset_scaler); break; @@ -1218,19 +1203,19 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) client->driver = &i2c_driver_saa7115; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); - saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1); + v4l_dbg(1, client, "detecting saa7115 client on address 0x%x\n", address << 1); saa7115_write(client, 0, 5); chip_id = saa7115_read(client, 0) & 0x0f; if (chip_id != 4 && chip_id != 5) { - saa7115_dbg("saa7115 not found\n"); + v4l_dbg(1, client, "saa7115 not found\n"); kfree(client); return 0; } if (chip_id == 4) { snprintf(client->name, sizeof(client->name) - 1, "saa7114"); } - saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name); + v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name); state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL); i2c_set_clientdata(client, state); @@ -1250,7 +1235,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; state->audclk_freq = 48000; - saa7115_dbg("writing init values\n"); + v4l_dbg(1, client, "writing init values\n"); /* init to 60hz/48khz */ saa7115_writeregs(client, saa7115_init_auto_input); @@ -1263,7 +1248,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) i2c_attach_client(client); - saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n", + v4l_dbg(1, client, "status: (1E) 0x%02x, (1F) 0x%02x\n", saa7115_read(client, 0x1e), saa7115_read(client, 0x1f)); return 0; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index aee0f2d73da3..2009c1bc4720 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -66,30 +66,6 @@ module_param(test_image, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_PARM_DESC(test_image, "test_image (0-1)"); -#define saa7127_dbg(fmt, arg...) \ - do { \ - if (debug >= 1) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -/* High volume debug. Use with care. */ -#define saa7127_dbg_highvol(fmt, arg...) \ - do { \ - if (debug == 2) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, \ - client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); \ - } while (0) - -#define saa7127_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define saa7127_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; @@ -336,7 +312,7 @@ static int saa7127_write(struct i2c_client *client, u8 reg, u8 val) if (i2c_smbus_write_byte_data(client, reg, val) == 0) return 0; } - saa7127_err("I2C Write Problem\n"); + v4l_err(client, "I2C Write Problem\n"); return -1; } @@ -362,7 +338,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (enable && (data->field != 0 || data->line != 16)) return -EINVAL; if (state->vps_enable != enable) { - saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off"); + v4l_dbg(1, client, "Turn VPS Signal %s\n", enable ? "on" : "off"); saa7127_write(client, 0x54, enable << 7); state->vps_enable = enable; } @@ -374,7 +350,7 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat state->vps_data[2] = data->data[11]; state->vps_data[3] = data->data[12]; state->vps_data[4] = data->data[13]; - saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n", + v4l_dbg(1, client, "Set VPS data %02x %02x %02x %02x %02x\n", state->vps_data[0], state->vps_data[1], state->vps_data[2], state->vps_data[3], state->vps_data[4]); @@ -397,7 +373,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data if (enable && (data->field != 0 || data->line != 21)) return -EINVAL; if (state->cc_enable != enable) { - saa7127_dbg("Turn CC %s\n", enable ? "on" : "off"); + v4l_dbg(1, client, "Turn CC %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, (state->xds_enable << 7) | (enable << 6) | 0x11); state->cc_enable = enable; @@ -405,7 +381,7 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data if (!enable) return 0; - saa7127_dbg_highvol("CC data: %04x\n", cc); + v4l_dbg(2, client, "CC data: %04x\n", cc); saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8); state->cc_data = cc; @@ -423,7 +399,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (enable && (data->field != 1 || data->line != 21)) return -EINVAL; if (state->xds_enable != enable) { - saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off"); + v4l_dbg(1, client, "Turn XDS %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, (enable << 7) | (state->cc_enable << 6) | 0x11); state->xds_enable = enable; @@ -431,7 +407,7 @@ static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (!enable) return 0; - saa7127_dbg_highvol("XDS data: %04x\n", xds); + v4l_dbg(2, client, "XDS data: %04x\n", xds); saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff); saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8); state->xds_data = xds; @@ -448,7 +424,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat if (enable && (data->field != 0 || data->line != 23)) return -EINVAL; if (state->wss_enable != enable) { - saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off"); + v4l_dbg(1, client, "Turn WSS %s\n", enable ? "on" : "off"); saa7127_write(client, 0x27, enable << 7); state->wss_enable = enable; } @@ -457,7 +433,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat saa7127_write(client, 0x26, data->data[0]); saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f)); - saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); + v4l_dbg(1, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; return 0; } @@ -469,11 +445,11 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable) struct saa7127_state *state = i2c_get_clientdata(client); if (enable) { - saa7127_dbg("Enable Video Output\n"); + v4l_dbg(1, client, "Enable Video Output\n"); saa7127_write(client, 0x2d, state->reg_2d); saa7127_write(client, 0x61, state->reg_61); } else { - saa7127_dbg("Disable Video Output\n"); + v4l_dbg(1, client, "Disable Video Output\n"); saa7127_write(client, 0x2d, (state->reg_2d & 0xf0)); saa7127_write(client, 0x61, (state->reg_61 | 0xc0)); } @@ -489,11 +465,11 @@ static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std) const struct i2c_reg_value *inittab; if (std & V4L2_STD_525_60) { - saa7127_dbg("Selecting 60 Hz video Standard\n"); + v4l_dbg(1, client, "Selecting 60 Hz video Standard\n"); inittab = saa7127_init_config_60hz; state->reg_61 = SAA7127_60HZ_DAC_CONTROL; } else { - saa7127_dbg("Selecting 50 Hz video Standard\n"); + v4l_dbg(1, client, "Selecting 50 Hz video Standard\n"); inittab = saa7127_init_config_50hz; state->reg_61 = SAA7127_50HZ_DAC_CONTROL; } @@ -544,7 +520,7 @@ static int saa7127_set_output_type(struct i2c_client *client, int output) default: return -EINVAL; } - saa7127_dbg("Selecting %s output type\n", output_strs[output]); + v4l_dbg(1, client, "Selecting %s output type\n", output_strs[output]); /* Configure Encoder */ saa7127_write(client, 0x2d, state->reg_2d); @@ -561,12 +537,12 @@ static int saa7127_set_input_type(struct i2c_client *client, int input) switch (input) { case SAA7127_INPUT_TYPE_NORMAL: /* avia */ - saa7127_dbg("Selecting Normal Encoder Input\n"); + v4l_dbg(1, client, "Selecting Normal Encoder Input\n"); state->reg_3a_cb = 0; break; case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ - saa7127_dbg("Selecting Color Bar generator\n"); + v4l_dbg(1, client, "Selecting Color Bar generator\n"); state->reg_3a_cb = 0x80; break; @@ -633,14 +609,14 @@ static int saa7127_command(struct i2c_client *client, break; case VIDIOC_LOG_STATUS: - saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); - saa7127_info("Input: %s\n", state->input_type ? "color bars" : "normal"); - saa7127_info("Output: %s\n", state->video_enable ? + v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); + v4l_info(client, "Input: %s\n", state->input_type ? "color bars" : "normal"); + v4l_info(client, "Output: %s\n", state->video_enable ? output_strs[state->output_type] : "disabled"); - saa7127_info("WSS: %s\n", state->wss_enable ? + v4l_info(client, "WSS: %s\n", state->wss_enable ? wss_strs[state->wss_mode] : "disabled"); - saa7127_info("VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); - saa7127_info("CC: %s\n", state->cc_enable ? "enabled" : "disabled"); + v4l_info(client, "VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); + v4l_info(client, "CC: %s\n", state->cc_enable ? "enabled" : "disabled"); break; #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -723,7 +699,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) client->driver = &i2c_driver_saa7127; snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1); + v4l_dbg(1, client, "detecting saa7127 client on address 0x%x\n", address << 1); /* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0. @@ -732,7 +708,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) 0x1d after a reset and not expected to ever change. */ if ((saa7127_read(client, 0) & 0xe4) != 0 || (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { - saa7127_dbg("saa7127 not found\n"); + v4l_dbg(1, client, "saa7127 not found\n"); kfree(client); return 0; } @@ -748,7 +724,7 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) /* Configure Encoder */ - saa7127_dbg("Configuring encoder\n"); + v4l_dbg(1, client, "Configuring encoder\n"); saa7127_write_inittab(client, saa7127_init_config_common); saa7127_set_std(client, V4L2_STD_NTSC); saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH); @@ -769,12 +745,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); saa7127_write_inittab(client, saa7129_init_config_extra); state->ident = V4L2_IDENT_SAA7129; } else { - saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); state->ident = V4L2_IDENT_SAA7127; } diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 4647db66ba68..261b7a3c0417 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -17,6 +17,9 @@ #define PREFIX "TEA5767 " +/* from tuner-core.c */ +extern int debug; + /*****************************************************************************/ /****************************** @@ -246,7 +249,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) if (5 != (rc = i2c_master_send(c, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - if (tuner_debug) { + if (debug) { if (5 != (rc = i2c_master_recv(c, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index fd18a882668e..a727c3ae62c3 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -23,8 +23,6 @@ #include #include -#include "msp3400.h" - #define UNSET (-1U) /* standard i2c insmod options */ @@ -43,7 +41,8 @@ static unsigned int no_autodetect = 0; static unsigned int show_i2c = 0; /* insmod options used at runtime => read/write */ -unsigned int tuner_debug = 0; +static unsigned int tuner_debug = 0; +int debug = 0; static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; @@ -55,7 +54,9 @@ static char ntsc[] = "-"; module_param(addr, int, 0444); module_param(no_autodetect, int, 0444); module_param(show_i2c, int, 0444); -module_param(tuner_debug, int, 0644); +/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */ +module_param(tuner_debug, int, 0444); +module_param(debug, int, 0644); module_param_string(pal, pal, sizeof(pal), 0644); module_param_string(secam, secam, sizeof(secam), 0644); @@ -419,6 +420,11 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ t->audmode = V4L2_TUNER_MODE_STEREO; t->mode_mask = T_UNINITIALIZED; + if (tuner_debug) { + debug = tuner_debug; + printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n"); + printk(KERN_ERR "tuner: use the debug option instead.\n"); + } if (show_i2c) { unsigned char buffer[16]; @@ -546,7 +552,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); - if (tuner_debug>1) + if (debug>1) v4l_i2c_print_ioctl(&(t->i2c),cmd); switch (cmd) { diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index fec620073aa3..9f6b6d855f00 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -47,19 +47,6 @@ MODULE_LICENSE("GPL"); #define UNSET (-1U) -#define tvaudio_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, chip->c.driver->name, \ - i2c_adapter_id(chip->c.adapter), chip->c.addr , ## arg); } while (0) -#define tvaudio_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, chip->c.driver->name, \ - i2c_adapter_id(chip->c.adapter), chip->c.addr , ## arg); } while (0) -#define tvaudio_dbg(fmt, arg...) \ - do { \ - if (debug) \ - printk(KERN_INFO "%s debug %d-%04x: " fmt, chip->c.driver->name, \ - i2c_adapter_id(chip->c.adapter), chip->c.addr , ## arg); \ - } while (0) - /* ---------------------------------------------------------------------- */ /* our structs */ @@ -172,23 +159,23 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - tvaudio_dbg("%s: chip_write: 0x%x\n", + v4l_dbg(1, &chip->c, "%s: chip_write: 0x%x\n", chip->c.name, val); chip->shadow.bytes[1] = val; buffer[0] = val; if (1 != i2c_master_send(&chip->c,buffer,1)) { - tvaudio_warn("%s: I/O error (write 0x%x)\n", + v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n", chip->c.name, val); return -1; } } else { - tvaudio_dbg("%s: chip_write: reg%d=0x%x\n", + v4l_dbg(1, &chip->c, "%s: chip_write: reg%d=0x%x\n", chip->c.name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(&chip->c,buffer,2)) { - tvaudio_warn("%s: I/O error (write reg%d=0x%x)\n", + v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n", chip->c.name, subaddr, val); return -1; } @@ -213,11 +200,11 @@ static int chip_read(struct CHIPSTATE *chip) unsigned char buffer; if (1 != i2c_master_recv(&chip->c,&buffer,1)) { - tvaudio_warn("%s: I/O error (read)\n", + v4l_warn(&chip->c, "%s: I/O error (read)\n", chip->c.name); return -1; } - tvaudio_dbg("%s: chip_read: 0x%x\n",chip->c.name, buffer); + v4l_dbg(1, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer); return buffer; } @@ -232,10 +219,10 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) write[0] = subaddr; if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { - tvaudio_warn("%s: I/O error (read2)\n", chip->c.name); + v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name); return -1; } - tvaudio_dbg("%s: chip_read2: reg%d=0x%x\n", + v4l_dbg(1, &chip->c, "%s: chip_read2: reg%d=0x%x\n", chip->c.name, subaddr,read[0]); return read[0]; } @@ -248,7 +235,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - tvaudio_dbg("%s: chip_cmd(%s): reg=%d, data:", + v4l_dbg(1, &chip->c, "%s: chip_cmd(%s): reg=%d, data:", chip->c.name, name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { if (debug) @@ -260,7 +247,7 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) /* send data to the chip */ if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - tvaudio_warn("%s: I/O error (%s)\n", chip->c.name, name); + v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name); return -1; } return 0; @@ -287,7 +274,7 @@ static int chip_thread(void *data) daemonize("%s", chip->c.name); allow_signal(SIGTERM); - tvaudio_dbg("%s: thread started\n", chip->c.name); + v4l_dbg(1, &chip->c, "%s: thread started\n", chip->c.name); for (;;) { add_wait_queue(&chip->wq, &wait); @@ -299,7 +286,7 @@ static int chip_thread(void *data) try_to_freeze(); if (chip->done || signal_pending(current)) break; - tvaudio_dbg("%s: thread wakeup\n", chip->c.name); + v4l_dbg(1, &chip->c, "%s: thread wakeup\n", chip->c.name); /* don't do anything for radio or if mode != auto */ if (chip->radio || chip->mode != 0) @@ -312,7 +299,7 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+2*HZ); } - tvaudio_dbg("%s: thread exiting\n", chip->c.name); + v4l_dbg(1, &chip->c, "%s: thread exiting\n", chip->c.name); complete_and_exit(&chip->texit, 0); return 0; } @@ -325,7 +312,7 @@ static void generic_checkmode(struct CHIPSTATE *chip) if (mode == chip->prevmode) return; - tvaudio_dbg("%s: thread checkmode\n", chip->c.name); + v4l_dbg(1, &chip->c, "%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; if (mode & VIDEO_SOUND_STEREO) @@ -372,7 +359,7 @@ static int tda9840_getmode(struct CHIPSTATE *chip) if (val & TDA9840_ST_STEREO) mode |= VIDEO_SOUND_STEREO; - tvaudio_dbg ("tda9840_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -668,7 +655,7 @@ static int tda9873_getmode(struct CHIPSTATE *chip) mode |= VIDEO_SOUND_STEREO; if (val & TDA9873_DUAL) mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - tvaudio_dbg ("tda9873_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -679,12 +666,12 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - tvaudio_dbg("tda9873_setmode(): external input\n"); + v4l_dbg(1, &chip->c, "tda9873_setmode(): external input\n"); return; } - tvaudio_dbg("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - tvaudio_dbg("tda9873_setmode(): sw_data = %d\n", sw_data); + v4l_dbg(1, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + v4l_dbg(1, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { case VIDEO_SOUND_MONO: @@ -705,7 +692,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - tvaudio_dbg("tda9873_setmode(): req. mode %d; chip_write: %d\n", + v4l_dbg(1, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -844,7 +831,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip) chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - tvaudio_dbg("tda9874a_setup(): %s [0x%02X].\n", + v4l_dbg(1, &chip->c, "tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -887,7 +874,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } - tvaudio_dbg("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + v4l_dbg(1, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -933,7 +920,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - tvaudio_dbg("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ @@ -968,7 +955,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - tvaudio_dbg("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + v4l_dbg(1, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -982,10 +969,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - tvaudio_dbg("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + v4l_dbg(1, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - tvaudio_info("found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1197,7 +1184,7 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) }else if (!(val & TA8874Z_B0)){ mode |= VIDEO_SOUND_STEREO; } - /* tvaudio_dbg ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ + /* v4l_dbg(1, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1210,7 +1197,7 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - tvaudio_dbg("ta8874z_setmode(): mode: 0x%02x\n", mode); + v4l_dbg(1, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ case VIDEO_SOUND_MONO: @@ -1491,7 +1478,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&chip->c, chip); /* find description for the chip */ - tvaudio_dbg("chip found @ 0x%x\n", addr<<1); + v4l_dbg(1, &chip->c, "chip found @ 0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; @@ -1503,12 +1490,12 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) break; } if (desc->name == NULL) { - tvaudio_dbg("no matching chip description found\n"); + v4l_dbg(1, &chip->c, "no matching chip description found\n"); return -EIO; } - tvaudio_info("%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); + v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); if (desc->flags) { - tvaudio_dbg("matches:%s%s%s.\n", + v4l_dbg(1, &chip->c, "matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); @@ -1551,7 +1538,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) init_completion(&chip->texit); chip->tpid = kernel_thread(chip_thread,(void *)chip,0); if (chip->tpid < 0) - tvaudio_warn("%s: kernel_thread() failed\n", + v4l_warn(&chip->c, "%s: kernel_thread() failed\n", chip->c.name); wake_up_interruptible(&chip->wq); } @@ -1596,7 +1583,7 @@ static int chip_command(struct i2c_client *client, struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - tvaudio_dbg("%s: chip_command 0x%x\n", chip->c.name, cmd); + v4l_dbg(1, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd); switch (cmd) { case AUDC_SET_INPUT: diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 9bb367863a6f..fd0acc5da667 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -40,6 +40,7 @@ #include #include +#include #include MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); @@ -52,16 +53,14 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") -#define tveeprom_info(fmt, arg...) do {\ - printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ - c->adapter->nr, c->addr , ##arg); } while (0) -#define tveeprom_warn(fmt, arg...) do {\ - printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \ - c->adapter->nr, c->addr , ##arg); } while (0) -#define tveeprom_dbg(fmt, arg...) do {\ +#define tveeprom_info(fmt, arg...) \ + v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) +#define tveeprom_warn(fmt, arg...) \ + v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) +#define tveeprom_dbg(fmt, arg...) do { \ if (debug) \ - printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ - c->adapter->nr, c->addr , ##arg); } while (0) + v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \ + } while (0) /* * The Hauppauge eeprom uses an 8bit field to determine which diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index a1b6a427ab74..20b4ec93d7c9 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -32,20 +32,12 @@ #include #include #include -#include +#include MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); MODULE_LICENSE("GPL"); -#define wm8775_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) -#define wm8775_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ - i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) - - static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END }; @@ -69,7 +61,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) int i; if (reg < 0 || reg >= TOT_REGS) { - wm8775_err("Invalid register R%d\n", reg); + v4l_err(client, "Invalid register R%d\n", reg); return -1; } @@ -79,7 +71,7 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) return 0; } } - wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg); + v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } @@ -98,7 +90,7 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, If only one input is active (the normal case) then the input values 1, 2, 4 or 8 should be used. */ if (input->index > 15) { - wm8775_err("Invalid input %d.\n", input->index); + v4l_err(client, "Invalid input %d.\n", input->index); return -EINVAL; } state->input = input->index; @@ -133,7 +125,7 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_LOG_STATUS: - wm8775_info("Input: %d%s\n", state->input, + v4l_info(client, "Input: %d%s\n", state->input, state->muted ? " (muted)" : ""); break; @@ -184,7 +176,7 @@ static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "wm8775"); - wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); if (state == NULL) { diff --git a/include/media/tuner.h b/include/media/tuner.h index 6a8ef189e5fa..584f3ab1fcf7 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -202,7 +202,6 @@ struct tuner { void (*standby)(struct i2c_client *c); }; -extern unsigned int tuner_debug; extern unsigned const int tuner_count; extern int microtune_init(struct i2c_client *c); @@ -220,7 +219,8 @@ extern int tea5767_autodetection(struct i2c_client *c); printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) #define tuner_dbg(fmt, arg...) do {\ - if (tuner_debug) \ + extern int debug; \ + if (debug) \ printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index c5ca993679ec..51cdca8365c9 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -51,6 +51,7 @@ parameter called 'debug'. */ #define v4l_dbg(level, client, fmt, arg...) \ do { \ + extern int debug; \ if (debug >= (level)) \ v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \ } while (0) -- cgit v1.2.3 From d92c20e0a5b560bbe46d7e68bb47df2366cddf8f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:41 -0200 Subject: V4L/DVB (3279): Added VIDIOC_QUERYCTRL to cx25840. - Added VIDIOC_QUERYCTRL - Removed unnecessary inlines. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 20 ++--- drivers/media/video/cx25840/cx25840-core.c | 102 ++++++++++++++++++++++++- drivers/media/video/cx25840/cx25840-firmware.c | 10 +-- drivers/media/video/cx25840/cx25840-vbi.c | 4 +- 4 files changed, 117 insertions(+), 19 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index fe6bc411d71f..cb9a7981e408 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -170,7 +170,7 @@ void cx25840_audio_set_path(struct i2c_client *client) set_audclk_freq(client, state->audclk_freq); } -inline static int get_volume(struct i2c_client *client) +static int get_volume(struct i2c_client *client) { /* Volume runs +18dB to -96dB in 1/2dB steps * change to fit the msp3400 -114dB to +12dB range */ @@ -181,7 +181,7 @@ inline static int get_volume(struct i2c_client *client) return vol << 9; } -inline static void set_volume(struct i2c_client *client, int volume) +static void set_volume(struct i2c_client *client, int volume) { /* First convert the volume to msp3400 values (0-127) */ int vol = volume >> 9; @@ -198,7 +198,7 @@ inline static void set_volume(struct i2c_client *client, int volume) cx25840_write(client, 0x8d4, 228 - (vol * 2)); } -inline static int get_bass(struct i2c_client *client) +static int get_bass(struct i2c_client *client) { /* bass is 49 steps +12dB to -12dB */ @@ -208,13 +208,13 @@ inline static int get_bass(struct i2c_client *client) return bass; } -inline static void set_bass(struct i2c_client *client, int bass) +static void set_bass(struct i2c_client *client, int bass) { /* PATH1_EQ_BASS_VOL */ cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); } -inline static int get_treble(struct i2c_client *client) +static int get_treble(struct i2c_client *client) { /* treble is 49 steps +12dB to -12dB */ @@ -224,13 +224,13 @@ inline static int get_treble(struct i2c_client *client) return treble; } -inline static void set_treble(struct i2c_client *client, int treble) +static void set_treble(struct i2c_client *client, int treble) { /* PATH1_EQ_TREBLE_VOL */ cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); } -inline static int get_balance(struct i2c_client *client) +static int get_balance(struct i2c_client *client) { /* balance is 7 bit, 0 to -96dB */ @@ -244,7 +244,7 @@ inline static int get_balance(struct i2c_client *client) return balance << 8; } -inline static void set_balance(struct i2c_client *client, int balance) +static void set_balance(struct i2c_client *client, int balance) { int bal = balance >> 8; if (bal > 0x80) { @@ -260,13 +260,13 @@ inline static void set_balance(struct i2c_client *client, int balance) } } -inline static int get_mute(struct i2c_client *client) +static int get_mute(struct i2c_client *client) { /* check SRC1_MUTE_EN */ return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; } -inline static void set_mute(struct i2c_client *client, int mute) +static void set_mute(struct i2c_client *client, int mute) { struct cx25840_state *state = i2c_get_clientdata(client); diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 2bf057ec626c..d7ece6eecb5c 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -121,7 +121,7 @@ static void log_status(struct i2c_client *client); /* ----------------------------------------------------------------------- */ -static inline void init_dll1(struct i2c_client *client) +static void init_dll1(struct i2c_client *client) { /* This is the Hauppauge sequence used to * initialize the Delay Lock Loop 1 (ADC DLL). */ @@ -135,7 +135,7 @@ static inline void init_dll1(struct i2c_client *client) cx25840_write(client, 0x15b, 0x10); } -static inline void init_dll2(struct i2c_client *client) +static void init_dll2(struct i2c_client *client) { /* This is the Hauppauge sequence used to * initialize the Delay Lock Loop 2 (ADC DLL). */ @@ -562,6 +562,91 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) /* ----------------------------------------------------------------------- */ +static struct v4l2_queryctrl cx25840_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + .flags = 0, + }, { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64, + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64, + .flags = 0, + }, { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 58880, + .flags = 0, + }, { + .id = V4L2_CID_AUDIO_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Balance", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .flags = 0, + }, { + .id = V4L2_CID_AUDIO_MUTE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, { + .id = V4L2_CID_AUDIO_BASS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Bass", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + }, { + .id = V4L2_CID_AUDIO_TREBLE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Treble", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + }, +}; + +/* ----------------------------------------------------------------------- */ + static int cx25840_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -623,6 +708,19 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_S_CTRL: return set_v4lctrl(client, (struct v4l2_control *)arg); + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++) + if (qc->id && qc->id == cx25840_qctrl[i].id) { + memcpy(qc, &cx25840_qctrl[i], sizeof(*qc)); + return 0; + } + return -EINVAL; + } + case VIDIOC_G_STD: *(v4l2_std_id *)arg = cx25840_get_v4lstd(client); break; diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index 12a73e64f756..e1a7823d82cd 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -37,7 +37,7 @@ module_param(firmware, charp, 0444); MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]"); MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]"); -static inline void set_i2c_delay(struct i2c_client *client, int delay) +static void set_i2c_delay(struct i2c_client *client, int delay) { struct i2c_algo_bit_data *algod = client->adapter->algo_data; @@ -51,7 +51,7 @@ static inline void set_i2c_delay(struct i2c_client *client, int delay) } } -static inline void start_fw_load(struct i2c_client *client) +static void start_fw_load(struct i2c_client *client) { /* DL_ADDR_LB=0 DL_ADDR_HB=0 */ cx25840_write(client, 0x800, 0x00); @@ -65,7 +65,7 @@ static inline void start_fw_load(struct i2c_client *client) set_i2c_delay(client, 3); } -static inline void end_fw_load(struct i2c_client *client) +static void end_fw_load(struct i2c_client *client) { if (fastfw) set_i2c_delay(client, 10); @@ -76,7 +76,7 @@ static inline void end_fw_load(struct i2c_client *client) cx25840_write(client, 0x803, 0x03); } -static inline int check_fw_load(struct i2c_client *client, int size) +static int check_fw_load(struct i2c_client *client, int size) { /* DL_ADDR_HB DL_ADDR_LB */ int s = cx25840_read(client, 0x801) << 8; @@ -91,7 +91,7 @@ static inline int check_fw_load(struct i2c_client *client, int size) return 0; } -static inline int fw_write(struct i2c_client *client, u8 * data, int size) +static int fw_write(struct i2c_client *client, u8 * data, int size) { int sent; diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index 13ba4e15ddea..04d879da7d63 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -22,7 +22,7 @@ #include "cx25840.h" -static inline int odd_parity(u8 c) +static int odd_parity(u8 c) { c ^= (c >> 4); c ^= (c >> 2); @@ -31,7 +31,7 @@ static inline int odd_parity(u8 c) return c & 1; } -static inline int decode_vps(u8 * dst, u8 * p) +static int decode_vps(u8 * dst, u8 * p) { static const u8 biphase_tbl[] = { 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, -- cgit v1.2.3 From da4ae5a72b2a9de351ec8f98543b7c666ec97005 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:41 -0200 Subject: V4L/DVB (3280): Added VIDIOC_QUERYCTRL to saa7115 - Added VIDIOC_QUERYCTRL to saa7115 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 55 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 6cc13311bc2c..4a4bc69fb0e9 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1012,6 +1012,48 @@ static void saa7115_decode_vbi_line(struct i2c_client *client, /* ============ SAA7115 AUDIO settings (end) ============= */ +static struct v4l2_queryctrl saa7115_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + .flags = 0, + }, { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64, + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64, + .flags = 0, + }, { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 1, + .default_value = 0, + .flags = 0, + }, +}; + +/* ----------------------------------------------------------------------- */ + static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa7115_state *state = i2c_get_clientdata(client); @@ -1052,6 +1094,19 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar case VIDIOC_S_CTRL: return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg); + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++) + if (qc->id && qc->id == saa7115_qctrl[i].id) { + memcpy(qc, &saa7115_qctrl[i], sizeof(*qc)); + return 0; + } + return -EINVAL; + } + case VIDIOC_G_STD: *(v4l2_std_id *)arg = saa7115_get_v4lstd(client); break; -- cgit v1.2.3 From 66190a275246c8c5be140a224e021f8f5eb85ab6 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 9 Jan 2006 15:32:42 -0200 Subject: V4L/DVB (3281): av7110 driver: improved recovery from ARM crash and crash detection - Improved recovery from ARM crash and the way a crash is detected. Minor white space clean-up, debug output fixed. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 94 ++++++++++++++++++++++++++----------- drivers/media/dvb/ttpci/av7110.h | 9 ++++ drivers/media/dvb/ttpci/av7110_hw.c | 3 ++ 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index eabd4fcaf246..39b4bfa0ab7b 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -196,17 +196,15 @@ static void recover_arm(struct av7110 *av7110) av7110_bootarm(av7110); msleep(100); - restart_feeds(av7110); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); -} -static void arm_error(struct av7110 *av7110) -{ - dprintk(4, "%p\n",av7110); + init_av7110_av(av7110); + + /* card-specific recovery */ + if (av7110->recover) + av7110->recover(av7110); - av7110->arm_errors++; - av7110->arm_ready = 0; - recover_arm(av7110); + restart_feeds(av7110); + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); } static void av7110_arm_sync(struct av7110 *av7110) @@ -246,26 +244,22 @@ static int arm_thread(void *data) if (down_interruptible(&av7110->dcomlock)) break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); up(&av7110->dcomlock); - if (newloops == av7110->arm_loops) { + if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", av7110->dvb_adapter.num); - arm_error(av7110); - av7710_set_video_mode(av7110, vidmode); - - init_av7110_av(av7110); + recover_arm(av7110); if (down_interruptible(&av7110->dcomlock)) break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; up(&av7110->dcomlock); } av7110->arm_loops = newloops; + av7110->arm_errors = 0; } av7110->arm_thread = NULL; @@ -516,10 +510,6 @@ static void gpioirq(unsigned long data) iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); av7110->video_size.h = h_ar & 0xfff; - dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", - av7110->video_size.w, - av7110->video_size.h, - av7110->video_size.aspect_ratio); event.type = VIDEO_EVENT_SIZE_CHANGED; event.u.size.w = av7110->video_size.w; @@ -541,6 +531,11 @@ static void gpioirq(unsigned long data) event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; av7110->videostate.video_format = VIDEO_FORMAT_4_3; } + + dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", + av7110->video_size.w, av7110->video_size.h, + av7110->video_size.aspect_ratio); + dvb_video_add_event(av7110, &event); break; } @@ -1054,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110) struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux_feed *feed; int mode; - int i; + int i, j; dprintk(4, "%p\n", av7110); @@ -1062,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110) av7110->playing = 0; av7110->rec_mode = 0; - for (i = 0; i < dvbdmx->filternum; i++) { + for (i = 0; i < dvbdmx->feednum; i++) { feed = &dvbdmx->feed[i]; - if (feed->state == DMX_STATE_GO) + if (feed->state == DMX_STATE_GO) { + if (feed->type == DMX_TYPE_SEC) { + for (j = 0; j < dvbdmx->filternum; j++) { + if (dvbdmx->filter[j].type != DMX_TYPE_SEC) + continue; + if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) + continue; + if (dvbdmx->filter[j].state == DMX_STATE_GO) + dvbdmx->filter[j].state = DMX_STATE_READY; + } + } av7110_start_feed(feed); + } } if (mode) @@ -2121,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_fe_params = *params; ret = av7110->fe_set_frontend(fe, params); + } return ret; } @@ -2164,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_master_cmd = *cmd; ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + } return ret; } @@ -2174,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_minicmd = minicmd; ret = av7110->fe_diseqc_send_burst(fe, minicmd); + } return ret; } @@ -2184,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_tone = tone; ret = av7110->fe_set_tone(fe, tone); + } return ret; } @@ -2194,8 +2208,10 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_voltage = voltage; ret = av7110->fe_set_voltage(fe, voltage); + } return ret; } @@ -2209,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un return ret; } +static void dvb_s_recover(struct av7110* av7110) +{ + av7110_fe_init(av7110->fe); + + av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); + if (av7110->saved_master_cmd.msg_len) { + msleep(20); + av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); + } + msleep(20); + av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); + msleep(20); + av7110_fe_set_tone(av7110->fe, av7110->saved_tone); + + av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params); +} + static u8 read_pwm(struct av7110* av7110) { u8 b = 0xff; @@ -2246,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; break; } @@ -2255,6 +2289,7 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; break; } @@ -2264,6 +2299,7 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; break; } @@ -2300,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; } break; @@ -2328,6 +2365,7 @@ static int frontend_init(struct av7110 *av7110) if (av7110->fe) { av7110->fe->ops->set_voltage = lnbp21_set_voltage; av7110->fe->ops->dishnetwork_send_legacy_command = NULL; + av7110->recover = dvb_s_recover; } break; } diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index d5550f462062..a817664f13e0 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -246,6 +246,15 @@ struct av7110 { struct dvb_frontend* fe; fe_status_t fe_status; + + /* crash recovery */ + void (*recover)(struct av7110* av7110); + struct dvb_frontend_parameters saved_fe_params; + fe_sec_voltage_t saved_voltage; + fe_sec_tone_mode_t saved_tone; + struct dvb_diseqc_master_cmd saved_master_cmd; + fe_sec_mini_cmd_t saved_minicmd; + int (*fe_init)(struct dvb_frontend* fe); int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 54279aaa4828..cb377452b57d 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110) dprintk(4, "%p\n", av7110); + av7110->arm_ready = 0; + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); /* Disable DEBI and GPIO irq */ @@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) break; if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); + av7110->arm_errors++; return -ETIMEDOUT; } msleep(1); -- cgit v1.2.3 From e71bb548e52d6a0f4934a2dfd7f29a569c94ad53 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:32:42 -0200 Subject: V4L/DVB (3282): rename cxusb_bluebird_atsc_properties to cxusb_bluebird_lgh064f_properties - This property set is for the LG-H064F (FusionHDTV5 USB Gold) - There may, in the future, be a bluebird device using a different NIM, so renaming the struct to somehting NIM-specific is appropriate. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 1a67ed598d97..2c1b1e5992a3 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -222,13 +222,13 @@ static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d) /* DVB USB Driver stuff */ static struct dvb_usb_properties cxusb_medion_properties; -static struct dvb_usb_properties cxusb_bluebird_atsc_properties; +static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_atsc_properties,THIS_MODULE,NULL) == 0) { + dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0) { return 0; } @@ -279,7 +279,7 @@ static struct dvb_usb_properties cxusb_medion_properties = { } }; -static struct dvb_usb_properties cxusb_bluebird_atsc_properties = { +static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, -- cgit v1.2.3 From d8e6acf2ec120f3dc7929581d87b5b8b3ff21627 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 9 Jan 2006 15:32:42 -0200 Subject: V4L/DVB (3287): Add DViCO Bluebird firmware to dvb_get_firmware script - Add DViCO Bluebird firmware to dvb_get_firmware script, for FusionHDTV USB devices. - Use usb alt setting 0 for EP4 transfer (dvb-t), - Use usb alt setting 7 for EP2 transfer (atsc) - Added comment to lgdt330x.c to indicate support for DViCO FusionHDTV5 USB Gold. Thanks to: Jeff Lee Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/dvb/get_dvb_firmware | 15 ++++++++++++++- drivers/media/dvb/frontends/lgdt330x.c | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 4e5e6a979fe7..e339a180a6ab 100644 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -23,7 +23,7 @@ use IO::Handle; @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", - "or51211", "or51132_qam", "or51132_vsb"); + "or51211", "or51132_qam", "or51132_vsb", "bluebird"); # Check args syntax() if (scalar(@ARGV) != 1); @@ -312,6 +312,19 @@ sub or51132_vsb { $fwfile; } +sub bluebird { + my $url = "http://www.linuxtv.org/~mkrufky/dvb-usb-bluebird-01.fw"; + my $outfile = "dvb-usb-bluebird-01.fw"; + my $hash = "658397cb9eba9101af9031302671f49d"; + + checkstandard(); + + wgetfile($outfile, $url); + verify($outfile,$hash); + + $outfile; +} + # --------------------------------------------------------------- # Utilities diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 56fcb9e97b57..9d214643b87a 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -27,6 +27,7 @@ * DViCO FusionHDTV 3 Gold-T * DViCO FusionHDTV 5 Gold * DViCO FusionHDTV 5 Lite + * DViCO FusionHDTV 5 USB Gold * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) * * TODO: -- cgit v1.2.3 From 400b7083fbcc8e7a1157a82aa126977179873268 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Mon, 9 Jan 2006 15:32:43 -0200 Subject: V4L/DVB (3194): Revert one 64-bit fix and improved other 64-bit fixes - Reverted objectionable fix in saa7146_hlp.c - Merged in improved dvb 64-bit fixes from Peter Beutner. Signed-off-by: Peter Beutner Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_hlp.c | 2 +- drivers/media/dvb/dvb-core/dvb_frontend.c | 6 +++--- drivers/media/dvb/dvb-core/dvb_frontend.h | 4 ++-- drivers/media/dvb/dvb-core/dvb_net.c | 2 +- drivers/media/dvb/frontends/stv0299.c | 4 ++-- drivers/media/dvb/ttpci/av7110.c | 2 +- drivers/media/dvb/ttpci/av7110.h | 2 +- drivers/media/dvb/ttpci/budget.c | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index be34ec430470..ec52dff8cb69 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -562,7 +562,7 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int int b_depth = vv->ov_fmt->depth; int b_bpl = vv->ov_fb.fmt.bytesperline; - u32 base = (u32)(unsigned long)vv->ov_fb.base; + u32 base = (u32)vv->ov_fb.base; struct saa7146_video_dma vdma1; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a53e95f35a53..4a08c4ab6730 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -104,7 +104,7 @@ struct dvb_frontend_private { unsigned int exit; unsigned int wakeup; fe_status_t status; - unsigned int tune_mode_flags; + unsigned long tune_mode_flags; unsigned int delay; /* swzigzag values */ @@ -808,13 +808,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned int cmd = ((unsigned long) parg) << 1; + unsigned long cmd = ((unsigned long) parg) << 1; struct timeval nexttime; struct timeval tv[10]; int i; u8 last = 1; if (dvb_frontend_debug) - printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd); + printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd); do_gettimeofday(&nexttime); if (dvb_frontend_debug) memcpy(&tv[0], &nexttime, sizeof(struct timeval)); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f40ee4efbe31..70a6d14efda7 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -83,8 +83,8 @@ struct dvb_frontend_ops { int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); - int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); + int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); + int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); }; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 95d991febea6..6711eb6a058c 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) return if_num; } -static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num) +static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) { struct net_device *net = dvbnet->device[num]; struct dvb_net_priv *priv; diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 1085bd15d56d..5bcd00f792e6 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -394,7 +394,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag }; } -static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) +static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd) { struct stv0299_state* state = fe->demodulator_priv; u8 reg0x08; @@ -414,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) cmd = cmd << 1; if (debug_legacy_dish_switch) - printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd); do_gettimeofday (&nexttime); if (debug_legacy_dish_switch) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 39b4bfa0ab7b..8ce4146f55f1 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2215,7 +2215,7 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta return ret; } -static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd) +static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) { struct av7110* av7110 = fe->dvb->priv; diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index a817664f13e0..6cf395e01d34 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -262,7 +262,7 @@ struct av7110 { int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 746aad373293..238c77b52f89 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -212,7 +212,7 @@ static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) return 0; } -static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg) +static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg) { struct budget* budget = (struct budget*) fe->dvb->priv; u8 buf; -- cgit v1.2.3 From 82a1c359e8cc15d836c139626d747bfdfc408450 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:43 -0200 Subject: V4L/DVB (3195): Fix for 64-bit compile warning - Add the fix for the saa7146 64-bit compile warning (again). This time with comments and checked by Johannes Stezenbach. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_hlp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index ec52dff8cb69..33bec8a6843b 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -562,19 +562,26 @@ static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int int b_depth = vv->ov_fmt->depth; int b_bpl = vv->ov_fb.fmt.bytesperline; - u32 base = (u32)vv->ov_fb.base; + /* The unsigned long cast is to remove a 64-bit compile warning since + it looks like a 64-bit address is cast to a 32-bit value, even + though the base pointer is really a 32-bit physical address that + goes into a 32-bit DMA register. + FIXME: might not work on some 64-bit platforms, but see the FIXME + in struct v4l2_framebuffer (videodev2.h) for that. + */ + u32 base = (u32)(unsigned long)vv->ov_fb.base; struct saa7146_video_dma vdma1; /* calculate memory offsets for picture, look if we shall top-down-flip */ vdma1.pitch = 2*b_bpl; if ( 0 == vv->vflip ) { - vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); + vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2); vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2)); } else { - vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); + vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2); vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2)); } -- cgit v1.2.3 From c5099a6481d2d0f9455abd15c91f73c2ced57a40 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:43 -0200 Subject: V4L/DVB (3291): Fix signed/unsigned bug in hue handling - Fix signed/unsigned bug in hue handling (set to -127 and 129 was returned). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index d7ece6eecb5c..b93495b2a1fb 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -466,7 +466,7 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) ctrl->value = cx25840_read(client, 0x420) >> 1; break; case V4L2_CID_HUE: - ctrl->value = cx25840_read(client, 0x422); + ctrl->value = (s8)cx25840_read(client, 0x422); break; case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_BASS: -- cgit v1.2.3 From 0de71224d17f43101fa20696a8d7a78fb599557e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 15:32:44 -0200 Subject: V4L/DVB (3292): Fix signed/unsigned bug in brightness handling of cx25840 - Fix signed/unsigned bug in brightness handling (set to 0 and 128 was returned). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index b93495b2a1fb..29b378b6097d 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -457,7 +457,7 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) ctrl->value = state->pvr150_workaround; break; case V4L2_CID_BRIGHTNESS: - ctrl->value = cx25840_read(client, 0x414) + 128; + ctrl->value = (s8)cx25840_read(client, 0x414) + 128; break; case V4L2_CID_CONTRAST: ctrl->value = cx25840_read(client, 0x415) >> 1; -- cgit v1.2.3 From b7f355d23c34399ccfd54fd613c306ab4a788234 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:32:44 -0200 Subject: V4L/DVB (3293): Added digital support for cx88 (cx88-alsa) - This module is co-authored by Ricardo Cerqueira . - Added digital audio support for cx88-based boards that have function 01 enabled. These boards can be identified by having PCI id 1471:8801 or 1471:8811. - Increased DMA buffer from 512 to 4096 seems to fix audio distortion. - Existing audio DMA uses conflict with cx88-alsa. Should be disabled when cx88-alsa module is compiled. Signed-off-by: Ricardo Cerqueira Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/Kconfig | 15 + drivers/media/video/cx88/cx88-alsa.c | 848 ++++++++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-core.c | 11 +- drivers/media/video/cx88/cx88-tvaudio.c | 4 + 4 files changed, 872 insertions(+), 6 deletions(-) create mode 100644 drivers/media/video/cx88/cx88-alsa.c diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index ec6201a32aca..76fcb4e995c9 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -29,6 +29,21 @@ config VIDEO_CX88_DVB You must also select one or more DVB/ATSC demodulators. If you are unsure which you need, choose all of them. +config VIDEO_CX88_ALSA + tristate "ALSA DMA audio support" + depends on VIDEO_CX88 && SND + select SND_PCM_OSS + ---help--- + This is a video4linux driver for direct (DMA) audio on + Conexant 2388x based TV cards. + It only works with boards with function 01 enabled. + To check if your board supports, use lspci -n. + If supported, you should see 1471:8801 or 1471:8811 + PCI device. + + To compile this driver as a module, choose M here: the + module will be called cx88-alsa. + config VIDEO_CX88_DVB_ALL_FRONTENDS bool "Build all supported frontends for cx2388x based TV cards" default y diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c new file mode 100644 index 000000000000..7695b521eb35 --- /dev/null +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -0,0 +1,848 @@ +/* + * + * Support for audio capture + * PCI function #1 of the cx2388x. + * + * (c) 2005,2006 Ricardo Cerqueira + * (c) 2005 Mauro Carvalho Chehab + * Based on a dummy cx88 module by Gerd Knorr + * Based on dummy.c by Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cx88.h" +#include "cx88-reg.h" + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg) + +#define dprintk_core(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) + + +/**************************************************************************** + Data type declarations - Can be moded to a header file later + ****************************************************************************/ + +/* These can be replaced after done */ +#define MIXER_ADDR_LAST MAX_CX88_INPUT + +struct cx88_audio_dev { + struct cx88_core *core; + struct cx88_dmaqueue q; + + /* pci i/o */ + struct pci_dev *pci; + unsigned char pci_rev,pci_lat; + + /* audio controls */ + int irq; + + snd_card_t *card; + + spinlock_t reg_lock; + + unsigned int dma_size; + unsigned int period_size; + unsigned int num_periods; + + struct videobuf_dmabuf dma_risc; + + int mixer_volume[MIXER_ADDR_LAST+1][2]; + int capture_source[MIXER_ADDR_LAST+1][2]; + + long int read_count; + long int read_offset; + + struct cx88_buffer *buf; + + long opened; + snd_pcm_substream_t *substream; + +}; +typedef struct cx88_audio_dev snd_cx88_card_t; + + + +/**************************************************************************** + Module global static vars + ****************************************************************************/ + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; +static snd_card_t *snd_cx88_cards[SNDRV_CARDS]; + +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s)."); + + +/**************************************************************************** + Module macros + ****************************************************************************/ + +MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); +MODULE_AUTHOR("Ricardo Cerqueira"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Conexant,23881}," + "{{Conexant,23882}," + "{{Conexant,23883}"); +static unsigned int debug = 0; +module_param(debug,int,0644); +MODULE_PARM_DESC(debug,"enable debug messages"); + +/**************************************************************************** + Module specific funtions + ****************************************************************************/ + +/* + * BOARD Specific: Sets audio DMA + */ + +int _cx88_start_audio_dma(snd_cx88_card_t *chip) +{ + struct cx88_buffer *buf = chip->buf; + struct cx88_core *core=chip->core; + struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; + + + dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start); + + /* setup fifo + format - out channel */ + cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25], + buf->bpl, buf->risc.dma); + + /* sets bpl size */ + cx_write(MO_AUDD_LNGTH, buf->bpl); + + /* reset counter */ + cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET); + + dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02)); + /* enable irqs */ + cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02); + + + /* Enables corresponding bits at AUD_INT_STAT */ + cx_write(MO_AUD_INTMSK, + (1<<16)| + (1<<12)| + (1<<4)| + (1<<0) + ); + + /* start dma */ + cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ + cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ + + if (debug) + cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + + return 0; +} + +/* + * BOARD Specific: Resets audio DMA + */ +int _cx88_stop_audio_dma(snd_cx88_card_t *chip) +{ + struct cx88_core *core=chip->core; + dprintk(1, "Stopping audio DMA\n"); + + /* stop dma */ + cx_clear(MO_AUD_DMACNTRL, 0x11); + + /* disable irqs */ + cx_clear(MO_PCI_INTMSK, 0x02); + cx_clear(MO_AUD_INTMSK, + (1<<16)| + (1<<12)| + (1<<4)| + (1<<0) + ); + + if (debug) + cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + + return 0; +} + +#define MAX_IRQ_LOOP 10 + +/* + * BOARD Specific: IRQ dma bits + */ +static char *cx88_aud_irqs[32] = { + "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ + NULL, /* reserved */ + "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ + NULL, /* reserved */ + "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ + NULL, /* reserved */ + "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ + NULL, /* reserved */ + "opc_err", "par_err", "rip_err", /* 16-18 */ + "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ +}; + +/* + * BOARD Specific: Threats IRQ audio specific calls + */ +static void cx8801_aud_irq(snd_cx88_card_t *chip) +{ + struct cx88_core *core = chip->core; + u32 status, mask; + u32 count; + + status = cx_read(MO_AUD_INTSTAT); + mask = cx_read(MO_AUD_INTMSK); + if (0 == (status & mask)) { + spin_unlock(&chip->reg_lock); + return; + } + cx_write(MO_AUD_INTSTAT, status); + if (debug > 1 || (status & mask & ~0xff)) + cx88_print_irqbits(core->name, "irq aud", + cx88_aud_irqs, status, mask); + /* risc op code error */ + if (status & (1 << 16)) { + printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); + cx_clear(MO_AUD_DMACNTRL, 0x11); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); + } + + /* risc1 downstream */ + if (status & 0x01) { + spin_lock(&chip->reg_lock); + count = cx_read(MO_AUDD_GPCNT); + spin_unlock(&chip->reg_lock); + if (chip->read_count == 0) + chip->read_count += chip->dma_size; + } + + if (chip->read_count >= chip->period_size) { + dprintk(2, "Elapsing period\n"); + snd_pcm_period_elapsed(chip->substream); + } + + dprintk(3,"Leaving audio IRQ handler...\n"); + + /* FIXME: Any other status should deserve a special handling? */ +} + +/* + * BOARD Specific: Handles IRQ calls + */ +static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + snd_cx88_card_t *chip = dev_id; + struct cx88_core *core = chip->core; + u32 status; + int loop, handled = 0; + + for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { + status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02); + if (0 == status) + goto out; + dprintk( 3, "cx8801_irq\n" ); + dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); + dprintk( 3, " status: %d\n", status ); + handled = 1; + cx_write(MO_PCI_INTSTAT, status); + + if (status & 0x02) + { + dprintk( 2, " ALSA IRQ handling\n" ); + cx8801_aud_irq(chip); + } + }; + + if (MAX_IRQ_LOOP == loop) { + dprintk( 0, "clearing mask\n" ); + dprintk(1,"%s/0: irq loop -- clearing mask\n", + core->name); + cx_clear(MO_PCI_INTMSK,0x02); + } + + out: + return IRQ_RETVAL(handled); +} + + +static int dsp_buffer_free(snd_cx88_card_t *chip) +{ + BUG_ON(!chip->dma_size); + + dprintk(2,"Freeing buffer\n"); + videobuf_dma_pci_unmap(chip->pci, &chip->dma_risc); + videobuf_dma_free(&chip->dma_risc); + btcx_riscmem_free(chip->pci,&chip->buf->risc); + kfree(chip->buf); + + chip->dma_size = 0; + + return 0; +} + +/**************************************************************************** + ALSA PCM Interface + ****************************************************************************/ + +/* + * Digital hardware definition + */ +static snd_pcm_hardware_t snd_cx88_digital_hw = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (2*2048), + .period_bytes_min = 256, + .period_bytes_max = 2048, + .periods_min = 2, + .periods_max = 16, +}; + +/* + * audio pcm capture runtime free + */ +static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime) +{ +} +/* + * audio pcm capture open callback + */ +static int snd_cx88_pcm_open(snd_pcm_substream_t *substream) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + if (test_and_set_bit(0, &chip->opened)) + return -EBUSY; + + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + goto _error; + + chip->substream = substream; + + chip->read_count = 0; + chip->read_offset = 0; + + runtime->private_free = snd_card_cx88_runtime_free; + runtime->hw = snd_cx88_digital_hw; + + return 0; +_error: + dprintk(1,"Error opening PCM!\n"); + clear_bit(0, &chip->opened); + smp_mb__after_clear_bit(); + return err; +} + +/* + * audio close callback + */ +static int snd_cx88_close(snd_pcm_substream_t *substream) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + + clear_bit(0, &chip->opened); + smp_mb__after_clear_bit(); + + return 0; +} + +/* + * hw_params callback + */ +static int snd_cx88_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct cx88_buffer *buf; + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + + chip->period_size = params_period_bytes(hw_params); + chip->num_periods = params_periods(hw_params); + chip->dma_size = chip->period_size * params_periods(hw_params); + + BUG_ON(!chip->dma_size); + + dprintk(1,"Setting buffer\n"); + + buf = kmalloc(sizeof(*buf),GFP_KERNEL); + if (NULL == buf) + return -ENOMEM; + memset(buf,0,sizeof(*buf)); + + + buf->vb.memory = V4L2_MEMORY_MMAP; + buf->vb.width = chip->period_size; + buf->vb.height = chip->num_periods; + buf->vb.size = chip->dma_size; + buf->vb.field = V4L2_FIELD_NONE; + + videobuf_dma_init(&buf->vb.dma); + videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE, + (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT)); + + videobuf_dma_pci_map(chip->pci,&buf->vb.dma); + + + cx88_risc_databuffer(chip->pci, &buf->risc, + buf->vb.dma.sglist, + buf->vb.width, buf->vb.height); + + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + + buf->vb.state = STATE_PREPARED; + + buf->bpl = chip->period_size; + chip->buf = buf; + chip->dma_risc = buf->vb.dma; + + dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages); + substream->runtime->dma_area = chip->dma_risc.vmalloc; + return 0; +} + +/* + * hw free callback + */ +static int snd_cx88_hw_free(snd_pcm_substream_t * substream) +{ + + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + + if (substream->runtime->dma_area) { + dsp_buffer_free(chip); + substream->runtime->dma_area = NULL; + } + + return 0; +} + +/* + * prepare callback + */ +static int snd_cx88_prepare(snd_pcm_substream_t *substream) +{ + return 0; +} + + +/* + * trigger callback + */ +static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + int err; + + spin_lock(&chip->reg_lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err=_cx88_start_audio_dma(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + err=_cx88_stop_audio_dma(chip); + break; + default: + err=-EINVAL; + break; + } + + spin_unlock(&chip->reg_lock); + + return err; +} + +/* + * pointer callback + */ +static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream) +{ + snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + if (chip->read_count) { + chip->read_count -= snd_pcm_lib_period_bytes(substream); + chip->read_offset += snd_pcm_lib_period_bytes(substream); + if (chip->read_offset == chip->dma_size) + chip->read_offset = 0; + } + + dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count); + return bytes_to_frames(runtime, chip->read_offset); + +} + +/* + * operators + */ +static snd_pcm_ops_t snd_cx88_pcm_ops = { + .open = snd_cx88_pcm_open, + .close = snd_cx88_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cx88_hw_params, + .hw_free = snd_cx88_hw_free, + .prepare = snd_cx88_prepare, + .trigger = snd_cx88_card_trigger, + .pointer = snd_cx88_pointer, +}; + +/* + * create a PCM device + */ +static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name) +{ + int err; + snd_pcm_t *pcm; + + err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); + if (err < 0) + return err; + pcm->private_data = chip; + strcpy(pcm->name, name); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops); + + return 0; +} + +/**************************************************************************** + CONTROL INTERFACE + ****************************************************************************/ +static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 1; + info->value.integer.min = 0; + info->value.integer.max = 0x3f; + + return 0; +} + +/* OK - TODO: test it */ +static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core=chip->core; + + value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); + + return 0; +} + +/* OK - TODO: test it */ +static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value) +{ + snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_core *core=chip->core; + int v; + u32 old_control; + + spin_lock_irq(&chip->reg_lock); + old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f); + v = 0x3f - (value->value.integer.value[0] & 0x3f); + cx_andor(AUD_VOL_CTL, 0x3f, v); + spin_unlock_irq(&chip->reg_lock); + + return v != old_control; +} + +static snd_kcontrol_new_t snd_cx88_capture_volume = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Volume", + .info = snd_cx88_capture_volume_info, + .get = snd_cx88_capture_volume_get, + .put = snd_cx88_capture_volume_put, +}; + + +/**************************************************************************** + Basic Flow for Sound Devices + ****************************************************************************/ + +/* + * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio + * Only boards with eeprom and byte 1 at eeprom=1 have it + */ + +struct pci_device_id cx88_audio_pci_tbl[] = { + {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0, } +}; +MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); + +/* + * Chip-specific destructor + */ + +static int snd_cx88_free(snd_cx88_card_t *chip) +{ + + if (chip->irq >= 0){ + synchronize_irq(chip->irq); + free_irq(chip->irq, chip); + } + + cx88_core_put(chip->core,chip->pci); + + pci_disable_device(chip->pci); + return 0; +} + +/* + * Component Destructor + */ +static void snd_cx88_dev_free(snd_card_t * card) +{ + snd_cx88_card_t *chip = card->private_data; + + snd_cx88_free(chip); +} + + +/* + * Alsa Constructor - Component probe + */ + +static int devno=0; +static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci, + snd_cx88_card_t **rchip) +{ + snd_cx88_card_t *chip; + struct cx88_core *core; + int err; + + *rchip = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + pci_set_master(pci); + + chip = (snd_cx88_card_t *) card->private_data; + + core = cx88_core_get(pci); + + if (!pci_dma_supported(pci,0xffffffff)) { + dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); + err = -EIO; + cx88_core_put(core,pci); + return err; + } + + + /* pci init */ + chip->card = card; + chip->pci = pci; + chip->irq = -1; + spin_lock_init(&chip->reg_lock); + + cx88_reset(core); + if (NULL == core) { + err = -EINVAL; + kfree (chip); + return err; + } + chip->core = core; + + /* get irq */ + err = request_irq(chip->pci->irq, cx8801_irq, + SA_SHIRQ | SA_INTERRUPT, chip->core->name, chip); + if (err < 0) { + dprintk(0, "%s: can't get IRQ %d\n", + chip->core->name, chip->pci->irq); + return err; + } + + /* print pci info */ + pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev); + pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat); + + dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%lx\n", core->name, devno, + pci_name(pci), chip->pci_rev, pci->irq, + chip->pci_lat,pci_resource_start(pci,0)); + + chip->irq = pci->irq; + synchronize_irq(chip->irq); + + snd_card_set_dev(card, &pci->dev); + + *rchip = chip; + + return 0; +} + +static int __devinit cx88_audio_initdev(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + snd_card_t *card; + snd_cx88_card_t *chip; + int err; + + if (devno >= SNDRV_CARDS) + return (-ENODEV); + + if (!enable[devno]) { + ++devno; + return (-ENOENT); + } + + card = snd_card_new(index[devno], id[devno], THIS_MODULE, sizeof(snd_cx88_card_t)); + if (!card) + return (-ENOMEM); + + card->private_free = snd_cx88_dev_free; + + err = snd_cx88_create(card, pci, &chip); + if (err < 0) + return (err); + + err = snd_cx88_pcm(chip, 0, "CX88 Digital"); + + if (err < 0) { + snd_card_free(card); + return (err); + } + + err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip)); + if (err < 0) { + snd_card_free(card); + return (err); + } + + strcpy (card->driver, "CX88x"); + sprintf(card->shortname, "Conexant CX%x", pci->device); + sprintf(card->longname, "%s at %#lx", + card->shortname, pci_resource_start(pci, 0)); + strcpy (card->mixername, "CX88"); + + dprintk (0, "%s/%i: ALSA support for cx2388x boards\n", + card->driver,devno); + + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return (err); + } + snd_cx88_cards[devno] = card; + + pci_set_drvdata(pci,card); + + devno++; + return 0; +} +/* + * ALSA destructor + */ +static void __devexit cx88_audio_finidev(struct pci_dev *pci) +{ + struct cx88_audio_dev *card = pci_get_drvdata(pci); + + snd_card_free((void *)card); + + pci_set_drvdata(pci, NULL); + + devno--; +} + +/* + * PCI driver definition + */ + +static struct pci_driver cx88_audio_pci_driver = { + .name = "cx88_audio", + .id_table = cx88_audio_pci_tbl, + .probe = cx88_audio_initdev, + .remove = cx88_audio_finidev, + SND_PCI_PM_CALLBACKS +}; + +/**************************************************************************** + LINUX MODULE INIT + ****************************************************************************/ + +/* + * module init + */ +static int cx88_audio_init(void) +{ + printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx88_audio_pci_driver); +} + +/* + * module remove + */ +static void cx88_audio_fini(void) +{ + + pci_unregister_driver(&cx88_audio_pci_driver); +} + +module_init(cx88_audio_init); +module_exit(cx88_audio_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index fc814d198694..9975be1aca38 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -238,9 +238,9 @@ cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf) * channel 22 (u video) - 2.0k * channel 23 (v video) - 2.0k * channel 24 (vbi) - 4.0k - * channels 25+26 (audio) - 0.5k + * channels 25+26 (audio) - 4.0k * channel 28 (mpeg) - 4.0k - * TOTAL = 25.5k + * TOTAL = 29.0k * * Every channel has 160 bytes control data (64 bytes instruction * queue and 6 CDT entries), which is close to 2k total. @@ -306,7 +306,7 @@ struct sram_channel cx88_sram_channels[] = { .ctrl_start = 0x180680, .cdt = 0x180680 + 64, .fifo_start = 0x185400, - .fifo_size = 0x000200, + .fifo_size = 0x001000, .ptr1_reg = MO_DMA25_PTR1, .ptr2_reg = MO_DMA25_PTR2, .cnt1_reg = MO_DMA25_CNT1, @@ -318,7 +318,7 @@ struct sram_channel cx88_sram_channels[] = { .ctrl_start = 0x180720, .cdt = 0x180680 + 64, /* same as audio IN */ .fifo_start = 0x185400, /* same as audio IN */ - .fifo_size = 0x000200, /* same as audio IN */ + .fifo_size = 0x001000, /* same as audio IN */ .ptr1_reg = MO_DMA26_PTR1, .ptr2_reg = MO_DMA26_PTR2, .cnt1_reg = MO_DMA26_CNT1, @@ -329,7 +329,7 @@ struct sram_channel cx88_sram_channels[] = { .cmds_start = 0x180200, .ctrl_start = 0x1807C0, .cdt = 0x1807C0 + 64, - .fifo_start = 0x185600, + .fifo_start = 0x186400, .fifo_size = 0x001000, .ptr1_reg = MO_DMA28_PTR1, .ptr2_reg = MO_DMA28_PTR2, @@ -795,7 +795,6 @@ int cx88_start_audio_dma(struct cx88_core *core) /* start dma */ cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */ - return 0; } diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 00051a4c1dc2..24118e43e73a 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -132,10 +132,14 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) { u32 volume; +#ifndef USING_CX88_ALSA /* restart dma; This avoids buzz in NICAM and is good in others */ cx88_stop_audio_dma(core); +#endif cx_write(AUD_RATE_THRES_DMD, 0x000000C0); +#ifndef USING_CX88_ALSA cx88_start_audio_dma(core); +#endif if (cx88_boards[core->board].blackbird) { /* sets sound input from external adc */ -- cgit v1.2.3 From f39624fda00d2a30d31f0fa06153e9b460295676 Mon Sep 17 00:00:00 2001 From: Manenti Marco Date: Mon, 9 Jan 2006 15:32:45 -0200 Subject: V4L/DVB (3294): Add Kworld/Vstream Xpert DVB-T card with cx22702 tuner. - Add Kworld/Vstream Xpert DVB-T card with cx22702 tuner. Signed-off-by: Manenti Marco Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 1 + drivers/media/video/cx88/cx88-cards.c | 29 ++++++++++++++++++++++++++++- drivers/media/video/cx88/cx88-dvb.c | 1 + drivers/media/video/cx88/cx88.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 956cf833e931..3d02b1f27d28 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -41,3 +41,4 @@ 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402] 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802] 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025] + 43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6b17d1e1e520..ae2fdf62c8ba 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1009,6 +1009,29 @@ struct cx88_board cx88_boards[] = { }, .dvb = 1, }, + [CX88_BOARD_KWORLD_DVB_T_CX22702] = { + /* Kworld V-stream Xpert DVB-T with Thomson tuner */ + /* DTT 7579 Conexant CX22702-19 Conexant CX2388x */ + /* Manenti Marco */ + .name = "KWorld/VStream XPert DVB-T with cx22702", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + }}, + .dvb = 1, + }, + }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1196,7 +1219,11 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x1822, .subdevice = 0x0025, .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - }, + },{ + .subvendor = 0x17de, + .subdevice = 0x08a1, + .card = CX88_BOARD_KWORLD_DVB_T_CX22702, + } }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c63f20fdff48..dad8a0d564fb 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -439,6 +439,7 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: case CX88_BOARD_CONEXANT_DVB_T1: + case CX88_BOARD_KWORLD_DVB_T_CX22702: case CX88_BOARD_WINFAST_DTV1000: dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, &dev->core->i2c_adap); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 022ef13c45bc..120e5049a46f 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -185,6 +185,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_HAUPPAUGE_HVR1100 40 #define CX88_BOARD_HAUPPAUGE_HVR1100LP 41 #define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42 +#define CX88_BOARD_KWORLD_DVB_T_CX22702 43 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From 4aa6ba513e28884b56bac529553a47a6b160c310 Mon Sep 17 00:00:00 2001 From: Peter Missel Date: Mon, 9 Jan 2006 15:32:45 -0200 Subject: V4L/DVB (3295): Add analog support for LifeView FlyDVB Trio. - Add support for LifeView FlyDVB Trio. - all analog inputs are supported and working, including FM radio - TO DO: dvb & remote control Signed-off-by: Peter Missel Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 41 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 43 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 4573e52c1ced..cb3a59bbeb17 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -82,3 +82,4 @@ 81 -> Philips Tiger reference design [1131:2018] 82 -> MSI TV@Anywhere plus [1462:6231] 83 -> Terratec Cinergy 250 PCI TV [153b:1160] + 84 -> LifeView FlyDVB Trio [5168:0319] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 991829eb15da..77e5be98e4c6 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2584,6 +2584,41 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200000, }, }, + [SAA7134_BOARD_FLYDVB_TRIO] = { + /* LifeView LR319 FlyDVB Trio */ + /* Peter Missel */ + .name = "LifeView FlyDVB Trio", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x00200000, + .inputs = {{ + .name = name_tv, /* Analog broadcast/cable TV */ + .vmux = 1, + .amux = TV, + .gpio = 0x200000, /* GPIO21=High for TV input */ + .tv = 1, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, + .amux = LINE2, + },{ + .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3042,6 +3077,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x153b, .subdevice = 0x1160, .driver_data = SAA7134_BOARD_CINERGY250PCI, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA 7131E */ + .subvendor = 0x5168, + .subdevice = 0x0319, + .driver_data = SAA7134_BOARD_FLYDVB_TRIO, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 18978a484ddb..e70eae8d29bb 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -209,6 +209,7 @@ struct saa7134_format { #define SAA7134_BOARD_PHILIPS_TIGER 81 #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82 #define SAA7134_BOARD_CINERGY250PCI 83 +#define SAA7134_BOARD_FLYDVB_TRIO 84 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 009494effc129094a5dcbbf2bf0345307ffe4f9b Mon Sep 17 00:00:00 2001 From: Guy Martin Date: Mon, 9 Jan 2006 15:32:45 -0200 Subject: V4L/DVB (3296): Fixes a bug at compat_ioctl32 kernel module - There is a bug in the ioctl translations from 32bit userspace to 64bit kernelspace in do_set_window(). - The video window (vw) should be passed to native_ioctl() instead of the video clip. Signed-off-by: Guy Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/compat_ioctl32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index 27945e082195..6194b0125576 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -489,7 +489,7 @@ static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg) } } - return native_ioctl(file, VIDIOCSWIN, (unsigned long)p); + return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw); } static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -- cgit v1.2.3 From 565f49490556250383e976c7f3e04ee4b7f54788 Mon Sep 17 00:00:00 2001 From: George Gazurkoff Date: Mon, 9 Jan 2006 15:32:46 -0200 Subject: V4L/DVB (3303): Both AverTV Studio 303 cards #6 and #36 use the same IR programming. - Both AverTV Studio 303 cards, #6 and #36, use the same remote control programming. Signed-off-by: George Gazurkoff Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index f40f97026b84..286c85b6bdf9 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -538,6 +538,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->polling = 1; /* ms */ break; case CX88_BOARD_AVERTV_303: + case CX88_BOARD_AVERTV_STUDIO_303: ir_codes = ir_codes_avertv_303; ir->gpio_addr = MO_GP2_IO; ir->mask_keycode = 0xfb; -- cgit v1.2.3 From 0680481c8e6260e1780a0900990531f0193b0dd4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:32:46 -0200 Subject: V4L/DVB (3305): Replaces old debug msgs to newer ones - Replaces old debug msgs from bt832, tda743d and tda9875 to newer ones as defined under v4l2-common.h. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt832.c | 65 +++++++++++++++++++++++-------------------- drivers/media/video/tda7432.c | 36 ++++++++++-------------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index d2cb5ccff56b..dda4aa6bef27 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -30,8 +30,9 @@ #include #include #include - #include +#include + #include "bttv.h" #include "bt832.h" @@ -42,9 +43,10 @@ static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; -/* ---------------------------------------------------------------------- */ +int debug = 0; /* debug output */ +module_param(debug, int, 0644); -#define dprintk if (debug) printk +/* ---------------------------------------------------------------------- */ static int bt832_detach(struct i2c_client *client); @@ -61,23 +63,26 @@ int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf) int i,rc; buf[0]=0x80; // start at register 0 with auto-increment if (1 != (rc = i2c_master_send(i2c_client_s,buf,1))) - printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc); + v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc); for(i=0;i<65;i++) buf[i]=0; if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65))) - printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc); + v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc); // Note: On READ the first byte is the current index // (e.g. 0x80, what we just wrote) - if(1) { + if(debug>1) { int i; - printk("BT832 hexdump:\n"); + v4l_dbg(2,i2c_client_s,"hexdump:"); for(i=1;i<65;i++) { if(i!=1) { - if(((i-1)%8)==0) printk(" "); - if(((i-1)%16)==0) printk("\n"); + if(((i-1)%8)==0) printk(" "); + if(((i-1)%16)==0) { + printk("\n"); + v4l_dbg(2,i2c_client_s,"hexdump:"); + } } printk(" %02x",buf[i]); } @@ -96,56 +101,56 @@ int bt832_init(struct i2c_client *i2c_client_s) bt832_hexdump(i2c_client_s,buf); if(buf[0x40] != 0x31) { - printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]); + v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]); kfree(buf); return 0; } - printk("Write 0 tp VPSTATUS\n"); + v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n"); buf[0]=BT832_VP_STATUS; // Reg.52 buf[1]= 0x00; if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc); + v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc); bt832_hexdump(i2c_client_s,buf); // Leave low power mode: - printk("Bt832: leave low power mode.\n"); + v4l_err(i2c_client_s,"leave low power mode.\n"); buf[0]=BT832_CAM_SETUP0; //0x39 57 buf[1]=0x08; if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc); + v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc); bt832_hexdump(i2c_client_s,buf); - printk("Write 0 tp VPSTATUS\n"); + v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n"); buf[0]=BT832_VP_STATUS; // Reg.52 buf[1]= 0x00; if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc); + v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc); bt832_hexdump(i2c_client_s,buf); // Enable Output - printk("Enable Output\n"); + v4l_info(i2c_client_s,"Enable Output\n"); buf[0]=BT832_VP_CONTROL1; // Reg.40 buf[1]= 0x27 & (~0x01); // Default | !skip if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc); + v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc); bt832_hexdump(i2c_client_s,buf); // for testing (even works when no camera attached) - printk("bt832: *** Generate NTSC M Bars *****\n"); + v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n"); buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42 buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc); + v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc); - printk("Bt832: Camera Present: %s\n", + v4l_info(i2c_client_s,"Camera Present: %s\n", (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no"); bt832_hexdump(i2c_client_s,buf); @@ -159,13 +164,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind) { struct bt832 *t; - printk("bt832_attach\n"); - client_template.adapter = adap; client_template.addr = addr; - printk("bt832: chip found @ 0x%x\n", addr<<1); - if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL))) return -ENOMEM; memset(t,0,sizeof(*t)); @@ -173,6 +174,9 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&t->client, t); i2c_attach_client(&t->client); + v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1); + + if(! bt832_init(&t->client)) { bt832_detach(&t->client); return -1; @@ -192,7 +196,7 @@ static int bt832_detach(struct i2c_client *client) { struct bt832 *t = i2c_get_clientdata(client); - printk("bt832: detach.\n"); + v4l_info(&t->client,"dettach\n"); i2c_detach_client(client); kfree(t); return 0; @@ -203,7 +207,8 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct bt832 *t = i2c_get_clientdata(client); - printk("bt832: command %x\n",cmd); + if (debug>1) + v4l_i2c_print_ioctl(&t->client,cmd); switch (cmd) { case BT832_HEXDUMP: { @@ -214,7 +219,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg) } break; case BT832_REATTACH: - printk("bt832: re-attach\n"); + v4l_info(&t->client,"re-attach\n"); i2c_del_driver(&driver); i2c_add_driver(&driver); break; @@ -226,9 +231,9 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg) static struct i2c_driver driver = { .driver = { - .name = "i2c bt832 driver", + .name = "bt832", }, - .id = -1, /* FIXME */ + .id = 0, /* FIXME */ .attach_adapter = bt832_probe, .detach_client = bt832_detach, .command = bt832_command, diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 3bd7dfb8cc7c..c6efc9826ba5 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -50,6 +50,7 @@ #include "bttv.h" #include +#include #ifndef VIDEO_AUDIO_BALANCE # define VIDEO_AUDIO_BALANCE 32 @@ -90,9 +91,6 @@ struct tda7432 { static struct i2c_driver driver; static struct i2c_client client_template; -#define dprintk if (debug) printk -#define d2printk if (debug > 1) printk - /* The TDA7432 is made by STS-Thompson * http://www.st.com * http://us.st.com/stonline/books/pdf/docs/4056.pdf @@ -229,12 +227,12 @@ static struct i2c_client client_template; static int tda7432_write(struct i2c_client *client, int subaddr, int val) { unsigned char buffer[2]; - d2printk("tda7432: In tda7432_write\n"); - dprintk("tda7432: Writing %d 0x%x\n", subaddr, val); + v4l_dbg(2,client,"In tda7432_write\n"); + v4l_dbg(1,client,"Writing %d 0x%x\n", subaddr, val); buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n", + v4l_err(client,"I/O error, trying (write %d 0x%x)\n", subaddr, val); return -1; } @@ -247,9 +245,9 @@ static int tda7432_set(struct i2c_client *client) { struct tda7432 *t = i2c_get_clientdata(client); unsigned char buf[16]; - d2printk("tda7432: In tda7432_set\n"); + v4l_dbg(2,client,"In tda7432_set\n"); - dprintk(KERN_INFO + v4l_dbg(1,client, "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud); buf[0] = TDA7432_IN; @@ -263,7 +261,7 @@ static int tda7432_set(struct i2c_client *client) buf[8] = t->rr; buf[9] = t->loud; if (10 != i2c_master_send(client,buf,10)) { - printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n"); + v4l_err(client,"I/O error, trying tda7432_set\n"); return -1; } @@ -273,7 +271,7 @@ static int tda7432_set(struct i2c_client *client) static void do_tda7432_init(struct i2c_client *client) { struct tda7432 *t = i2c_get_clientdata(client); - d2printk("tda7432: In tda7432_init\n"); + v4l_dbg(2,client,"In tda7432_init\n"); t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ TDA7432_BASS_SYM | /* Symmetric bass cut */ @@ -301,7 +299,6 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind) { struct tda7432 *t; struct i2c_client *client; - d2printk("tda7432: In tda7432_attach\n"); t = kmalloc(sizeof *t,GFP_KERNEL); if (!t) @@ -315,9 +312,9 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(client, t); do_tda7432_init(client); - printk(KERN_INFO "tda7432: init\n"); - i2c_attach_client(client); + + v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name); return 0; } @@ -343,7 +340,9 @@ static int tda7432_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tda7432 *t = i2c_get_clientdata(client); - d2printk("tda7432: In tda7432_command\n"); + v4l_dbg(2,client,"In tda7432_command\n"); + if (debug>1) + v4l_i2c_print_ioctl(client,cmd); switch (cmd) { /* --- v4l ioctls --- */ @@ -354,7 +353,6 @@ static int tda7432_command(struct i2c_client *client, case VIDIOCGAUDIO: { struct video_audio *va = arg; - dprintk("tda7432: VIDIOCGAUDIO\n"); va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | @@ -409,7 +407,6 @@ static int tda7432_command(struct i2c_client *client, case VIDIOCSAUDIO: { struct video_audio *va = arg; - dprintk("tda7432: VIDEOCSAUDIO\n"); if(va->flags & VIDEO_AUDIO_VOLUME){ if(!maxvol){ /* max +20db */ @@ -485,11 +482,6 @@ static int tda7432_command(struct i2c_client *client, } /* end of VIDEOCSAUDIO case */ - default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ - - /* nothing */ - d2printk("tda7432: Default\n"); - } /* end of (cmd) switch */ return 0; @@ -514,7 +506,7 @@ static struct i2c_client client_template = static int __init tda7432_init(void) { if ( (loudness < 0) || (loudness > 15) ) { - printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n"); + printk(KERN_ERR "loudness parameter must be between 0 and 15\n"); return -EINVAL; } -- cgit v1.2.3 From 677517771b7b6efaf8617e70f655b16f3cafcc9b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jan 2006 22:19:16 +0300 Subject: [PATCH] rcu: uninline __rcu_pending() __rcu_pending() is rather fat and called twice from rcu_pending(). rcu_pending() has multiple callers, and not that small too. This patch uninlines both of them. Signed-off-by: Oleg Nesterov Acked-by: Paul E. McKenney Signed-off-by: Linus Torvalds --- include/linux/rcupdate.h | 31 +------------------------------ kernel/rcupdate.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 51747cd88d1a..a1d26cb28925 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -125,36 +125,7 @@ static inline void rcu_bh_qsctr_inc(int cpu) rdp->passed_quiesc = 1; } -static inline int __rcu_pending(struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - /* This cpu has pending rcu entries and the grace period - * for them has completed. - */ - if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) - return 1; - - /* This cpu has no pending entries, but there are new entries */ - if (!rdp->curlist && rdp->nxtlist) - return 1; - - /* This cpu has finished callbacks to invoke */ - if (rdp->donelist) - return 1; - - /* The rcu core waits for a quiescent state from the cpu */ - if (rdp->quiescbatch != rcp->cur || rdp->qs_pending) - return 1; - - /* nothing to do */ - return 0; -} - -static inline int rcu_pending(int cpu) -{ - return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || - __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); -} +extern int rcu_pending(int cpu); /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 30b0bba03859..ccc45d49ce71 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -429,6 +429,36 @@ static void rcu_process_callbacks(unsigned long unused) &__get_cpu_var(rcu_bh_data)); } +static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) +{ + /* This cpu has pending rcu entries and the grace period + * for them has completed. + */ + if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) + return 1; + + /* This cpu has no pending entries, but there are new entries */ + if (!rdp->curlist && rdp->nxtlist) + return 1; + + /* This cpu has finished callbacks to invoke */ + if (rdp->donelist) + return 1; + + /* The rcu core waits for a quiescent state from the cpu */ + if (rdp->quiescbatch != rcp->cur || rdp->qs_pending) + return 1; + + /* nothing to do */ + return 0; +} + +int rcu_pending(int cpu) +{ + return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || + __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); +} + void rcu_check_callbacks(int cpu, int user) { if (user || -- cgit v1.2.3 From 14591de147f7c9656fa2b9c05680d2b46e286c40 Mon Sep 17 00:00:00 2001 From: Kirill Korotaev Date: Mon, 9 Jan 2006 17:42:42 +0300 Subject: [PATCH] netlink oops fix due to incorrect error code Fixed oops after failed netlink socket creation. Wrong parathenses in if() statement caused err to be 1, instead of negative value. Trivial fix, not trivial to find though. Signed-Off-By: Dmitry Mishin Signed-Off-By: Kirill Korotaev Signed-Off-By: Linus Torvalds --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7849cac14d3a..a67f1b44c9a3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -402,7 +402,7 @@ static int netlink_create(struct socket *sock, int protocol) groups = nl_table[protocol].groups; netlink_unlock_table(); - if ((err = __netlink_create(sock, protocol) < 0)) + if ((err = __netlink_create(sock, protocol)) < 0) goto out_module; nlk = nlk_sk(sock->sk); -- cgit v1.2.3 From cab462f716cdd522edc71436482d8734e8258489 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 9 Jan 2006 15:53:26 -0200 Subject: V4L/DVB (3307): Some cleanups at I2C modules - i2c names shorten - removed obsoleted flags on newer modules - small cleanups Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-i2c.c | 4 ++-- drivers/media/video/cx25840/cx25840-core.c | 2 -- drivers/media/video/cx25840/cx25840.h | 1 + drivers/media/video/ir-kbd-i2c.c | 2 +- drivers/media/video/msp3400-driver.c | 4 ---- drivers/media/video/saa6588.c | 2 +- drivers/media/video/saa711x.c | 2 -- drivers/media/video/saa7134/saa6752hs.c | 8 +++++--- drivers/media/video/tda7432.c | 6 +++--- drivers/media/video/tda9875.c | 2 +- drivers/media/video/tda9887.c | 2 +- drivers/media/video/tuner-core.c | 8 ++++---- drivers/media/video/tvaudio.c | 3 +-- drivers/media/video/tvmixer.c | 6 +----- drivers/media/video/tvp5150.c | 13 ++++++------- drivers/media/video/wm8775.c | 8 +++----- include/media/tuner.h | 1 - include/media/v4l2-common.h | 2 +- 18 files changed, 31 insertions(+), 45 deletions(-) diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index fd66d386fa7d..748d630c7fe4 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -107,7 +107,7 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { static struct i2c_adapter bttv_i2c_adap_sw_template = { .owner = THIS_MODULE, .class = I2C_CLASS_TV_ANALOG, - .name = "bt848", + .name = "bttv", .id = I2C_HW_B_BT848, .client_register = attach_inform, }; @@ -274,7 +274,7 @@ static struct i2c_algorithm bttv_algo = { }; static struct i2c_adapter bttv_i2c_adap_hw_template = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .class = I2C_CLASS_TV_ANALOG, .name = "bt878", .id = I2C_HW_B_BT848 /* FIXME */, diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 29b378b6097d..d45237d508c4 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -939,9 +939,7 @@ static struct i2c_driver i2c_driver_cx25840 = { .driver = { .name = "cx25840", }, - .id = I2C_DRIVERID_CX25840, - .attach_adapter = cx25840_attach_adapter, .detach_client = cx25840_detach_client, .command = cx25840_command, diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index 4260c3faa37a..fd22f30dcc1b 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -20,6 +20,7 @@ #ifndef _CX25840_H_ #define _CX25840_H_ + #include #include diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index caa0f58d149e..58b0e6982822 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -279,7 +279,7 @@ static int ir_probe(struct i2c_adapter *adap); static struct i2c_driver driver = { .driver = { - .name = "ir remote kbd driver", + .name = "ir-kbd-i2c", }, .id = I2C_DRIVERID_INFRARED, .attach_adapter = ir_probe, diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index eece5fe46cbe..fbd85120c331 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -106,10 +106,8 @@ MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; - I2C_CLIENT_INSMOD; - /* ----------------------------------------------------------------------- */ /* functions for talking to the MSP3400C Sound processor */ @@ -975,7 +973,6 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) client->addr = address; client->adapter = adapter; client->driver = &i2c_driver; - client->flags = I2C_CLIENT_ALLOW_USE; snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { @@ -1119,7 +1116,6 @@ static struct i2c_driver i2c_driver = { .suspend = msp_suspend, .resume = msp_resume, }, - .owner = THIS_MODULE, }; static int __init msp3400_init_module(void) diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index ad582bd39819..e70b17ef36e9 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -486,7 +486,7 @@ static int saa6588_command(struct i2c_client *client, unsigned int cmd, static struct i2c_driver driver = { .driver = { - .name = "i2c saa6588 driver", + .name = "saa6588", }, .id = -1, /* FIXME */ .attach_adapter = saa6588_probe, diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c index 8008537391b5..f39a7be08588 100644 --- a/drivers/media/video/saa711x.c +++ b/drivers/media/video/saa711x.c @@ -567,9 +567,7 @@ static struct i2c_driver i2c_driver_saa711x = { .driver = { .name = "saa711x", }, - .id = I2C_DRIVERID_SAA711X, - .attach_adapter = saa711x_attach_adapter, .detach_client = saa711x_detach_client, .command = saa711x_command, diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 4615a982ac64..ad73c4a60f2b 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include @@ -509,7 +510,6 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) { struct saa6752hs_state *h; - printk("saa6752hs: chip found @ 0x%x\n", addr<<1); if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL))) return -ENOMEM; @@ -525,6 +525,8 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&h->client, h); i2c_attach_client(&h->client); + v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1); + return 0; } @@ -598,7 +600,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) static struct i2c_driver driver = { .driver = { - .name = "i2c saa6752hs MPEG encoder", + .name = "saa6752hs", }, .id = I2C_DRIVERID_SAA6752HS, .attach_adapter = saa6752hs_probe, diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index c6efc9826ba5..99261f15e66e 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -341,8 +341,8 @@ static int tda7432_command(struct i2c_client *client, { struct tda7432 *t = i2c_get_clientdata(client); v4l_dbg(2,client,"In tda7432_command\n"); - if (debug>1) - v4l_i2c_print_ioctl(client,cmd); + if (debug>1) + v4l_i2c_print_ioctl(client,cmd); switch (cmd) { /* --- v4l ioctls --- */ @@ -489,7 +489,7 @@ static int tda7432_command(struct i2c_client *client, static struct i2c_driver driver = { .driver = { - .name = "i2c tda7432 driver", + .name = "tda7432", }, .id = I2C_DRIVERID_TDA7432, .attach_adapter = tda7432_probe, diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 760ec3c2ac67..299393bf900a 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -368,7 +368,7 @@ static int tda9875_command(struct i2c_client *client, static struct i2c_driver driver = { .driver = { - .name = "i2c tda9875 driver", + .name = "tda9875", }, .id = I2C_DRIVERID_TDA9875, .attach_adapter = tda9875_probe, diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index f64baa4b0025..9cf47dc65579 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -882,7 +882,7 @@ static struct i2c_driver driver = { .detach_client = tda9887_detach, .command = tda9887_command, .driver = { - .name = "i2c tda9887 driver", + .name = "tda9887", .suspend = tda9887_suspend, .resume = tda9887_resume, }, diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index a727c3ae62c3..57bc585a6955 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -805,10 +805,10 @@ static struct i2c_driver driver = { .detach_client = tuner_detach, .command = tuner_command, .driver = { - .name = "tuner", - .suspend = tuner_suspend, - .resume = tuner_resume, - }, + .name = "tuner", + .suspend = tuner_suspend, + .resume = tuner_resume, + }, }; static struct i2c_client client_template = { .name = "(tuner unset)", diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 9f6b6d855f00..b582943a0d3e 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1744,10 +1744,9 @@ static int chip_command(struct i2c_client *client, return 0; } - static struct i2c_driver driver = { .driver = { - .name = "generic i2c audio driver", + .name = "tvaudio", }, .id = I2C_DRIVERID_TVAUDIO, .attach_adapter = chip_probe, diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index ce0da9c1a768..9e86caeb96a7 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -227,13 +227,9 @@ static int tvmixer_release(struct inode *inode, struct file *file) } static struct i2c_driver driver = { -#ifdef I2C_PEC .driver = { - .name = "tv card mixer driver", + .name = "tvmixer", }, -#else - .name = "tv card mixer driver", -#endif .id = I2C_DRIVERID_TVMIXER, .detach_adapter = tvmixer_adapters, .attach_adapter = tvmixer_adapters, diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 07ad675cd58e..c35b8042eee5 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -30,14 +30,15 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define tvp5150_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->name, \ + printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \ i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0) #define tvp5150_dbg(num, fmt, arg...) \ do { \ if (debug >= num) \ - printk(KERN_DEBUG "%s debug %d-%04x: " fmt, c->driver->name, \ - i2c_adapter_id(c->adapter), c->addr , ## arg); \ - } while (0) + printk(KERN_DEBUG "%s debug %d-%04x: " fmt,\ + c->driver->driver.name, \ + i2c_adapter_id(c->adapter), \ + c->addr , ## arg); } while (0) /* supported controls */ static struct v4l2_queryctrl tvp5150_qctrl[] = { @@ -1137,9 +1138,7 @@ static struct i2c_driver driver = { .driver = { .name = "tvp5150", }, - - /* FIXME */ - .id = I2C_DRIVERID_SAA7110, + .id = I2C_DRIVERID_TVP5150, .attach_adapter = tvp5150_attach_adapter, .detach_client = tvp5150_detach_client, diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 20b4ec93d7c9..c2e6d2e9f5f1 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -237,12 +237,10 @@ static struct i2c_driver i2c_driver = { .driver = { .name = "wm8775", }, - - .id = I2C_DRIVERID_WM8775, - + .id = I2C_DRIVERID_WM8775, .attach_adapter = wm8775_probe, - .detach_client = wm8775_detach, - .command = wm8775_command, + .detach_client = wm8775_detach, + .command = wm8775_command, }; diff --git a/include/media/tuner.h b/include/media/tuner.h index 584f3ab1fcf7..7674b121ce8b 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -214,7 +214,6 @@ extern int tea5767_autodetection(struct i2c_client *c); #define tuner_warn(fmt, arg...) do {\ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) - #define tuner_info(fmt, arg...) do {\ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 51cdca8365c9..3cc3132f391e 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -34,7 +34,7 @@ #define v4l_printk(level, name, adapter, addr, fmt, arg...) \ printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg) -#define v4l_client_printk(level, client, fmt, arg...) \ +#define v4l_client_printk(level, client, fmt, arg...) \ v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \ (client)->addr, fmt , ## arg) -- cgit v1.2.3 From 44637a12f80b80157d9c1bc5b7d6ef09c9e05713 Mon Sep 17 00:00:00 2001 From: Knut Petersen Date: Mon, 9 Jan 2006 15:04:20 +0100 Subject: [PATCH] Update cyblafb driver This is a major update to the cyblafb framebuffer driver. Most of the stuff has been tested in the mm tree. Main advantages: ============ - vxres > xres support - ywrap and xpan support - much faster for almost all modes (e.g. 1280x1024-16bpp draws more than 41 full screens of text instead of about 25 full screens of text per second on authors Epia 5000) - module init/exit code fixed - bugs triggered by console rotation fixed - lots of minor improvements - startup modes suitable for high performance scrolling in all directions This diff also contains a lot of white space fixes. No side effects are possible, only one single graphics core is affected. Signed-off-by: Knut Petersen Signed-off-by: Linus Torvalds --- Documentation/fb/cyblafb/bugs | 1 - Documentation/fb/cyblafb/fb.modes | 57 +- Documentation/fb/cyblafb/performance | 1 - Documentation/fb/cyblafb/todo | 5 +- Documentation/fb/cyblafb/usage | 33 +- Documentation/fb/cyblafb/whatsnew | 29 + drivers/video/Kconfig | 2 +- drivers/video/cyblafb.c | 1523 +++++++++++++++++++--------------- include/video/cyblafb.h | 4 + 9 files changed, 960 insertions(+), 695 deletions(-) create mode 100644 Documentation/fb/cyblafb/whatsnew diff --git a/Documentation/fb/cyblafb/bugs b/Documentation/fb/cyblafb/bugs index f90cc66ea919..9443a6d72cdd 100644 --- a/Documentation/fb/cyblafb/bugs +++ b/Documentation/fb/cyblafb/bugs @@ -11,4 +11,3 @@ Untested features All LCD stuff is untested. If it worked in tridentfb, it should work in cyblafb. Please test and report the results to Knut_Petersen@t-online.de. - diff --git a/Documentation/fb/cyblafb/fb.modes b/Documentation/fb/cyblafb/fb.modes index cf4351fc32ff..fe0e5223ba86 100644 --- a/Documentation/fb/cyblafb/fb.modes +++ b/Documentation/fb/cyblafb/fb.modes @@ -14,142 +14,141 @@ # mode "640x480-50" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 47619 4294967256 24 17 0 216 3 endmode mode "640x480-60" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 39682 4294967256 24 17 0 216 3 endmode mode "640x480-70" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 34013 4294967256 24 17 0 216 3 endmode mode "640x480-72" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 33068 4294967256 24 17 0 216 3 endmode mode "640x480-75" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 31746 4294967256 24 17 0 216 3 endmode mode "640x480-80" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 29761 4294967256 24 17 0 216 3 endmode mode "640x480-85" - geometry 640 480 640 3756 8 + geometry 640 480 2048 4096 8 timings 28011 4294967256 24 17 0 216 3 endmode mode "800x600-50" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 30303 96 24 14 0 136 11 endmode mode "800x600-60" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 25252 96 24 14 0 136 11 endmode mode "800x600-70" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 21645 96 24 14 0 136 11 endmode mode "800x600-72" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 21043 96 24 14 0 136 11 endmode mode "800x600-75" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 20202 96 24 14 0 136 11 endmode mode "800x600-80" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 18939 96 24 14 0 136 11 endmode mode "800x600-85" - geometry 800 600 800 3221 8 + geometry 800 600 2048 4096 8 timings 17825 96 24 14 0 136 11 endmode mode "1024x768-50" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 19054 144 24 29 0 120 3 endmode mode "1024x768-60" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 15880 144 24 29 0 120 3 endmode mode "1024x768-70" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 13610 144 24 29 0 120 3 endmode mode "1024x768-72" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 13232 144 24 29 0 120 3 endmode mode "1024x768-75" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 12703 144 24 29 0 120 3 endmode mode "1024x768-80" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 11910 144 24 29 0 120 3 endmode mode "1024x768-85" - geometry 1024 768 1024 2815 8 + geometry 1024 768 2048 4096 8 timings 11209 144 24 29 0 120 3 endmode mode "1280x1024-50" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 11114 232 16 39 0 160 3 endmode mode "1280x1024-60" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 9262 232 16 39 0 160 3 endmode mode "1280x1024-70" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 7939 232 16 39 0 160 3 endmode mode "1280x1024-72" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 7719 232 16 39 0 160 3 endmode mode "1280x1024-75" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 7410 232 16 39 0 160 3 endmode mode "1280x1024-80" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 6946 232 16 39 0 160 3 endmode mode "1280x1024-85" - geometry 1280 1024 1280 2662 8 + geometry 1280 1024 2048 4096 8 timings 6538 232 16 39 0 160 3 endmode - diff --git a/Documentation/fb/cyblafb/performance b/Documentation/fb/cyblafb/performance index eb4e47a9cea6..8d15d5dfc6b3 100644 --- a/Documentation/fb/cyblafb/performance +++ b/Documentation/fb/cyblafb/performance @@ -77,4 +77,3 @@ patch that speeds up kernel bitblitting a lot ( > 20%). | | | | | | | | | | +-----------+-----------------+-----------------+-----------------+ - diff --git a/Documentation/fb/cyblafb/todo b/Documentation/fb/cyblafb/todo index 80fb2f89b6c1..c5f6d0eae545 100644 --- a/Documentation/fb/cyblafb/todo +++ b/Documentation/fb/cyblafb/todo @@ -22,11 +22,10 @@ accelerated color blitting Who needs it? The console driver does use color everything else is done using color expanding blitting of 1bpp character bitmaps. -xpanning Who needs it? - ioctls Who needs it? -TV-out Will be done later +TV-out Will be done later. Use "vga= " at boot time + to set a suitable video mode. ??? Feel free to contact me if you have any feature requests diff --git a/Documentation/fb/cyblafb/usage b/Documentation/fb/cyblafb/usage index e627c8f54211..a39bb3d402a2 100644 --- a/Documentation/fb/cyblafb/usage +++ b/Documentation/fb/cyblafb/usage @@ -40,6 +40,16 @@ Selecting Modes None of the modes possible to select as startup modes are affected by the problems described at the end of the next subsection. + For all startup modes cyblafb chooses a virtual x resolution of 2048, + the only exception is mode 1280x1024 in combination with 32 bpp. This + allows ywrap scrolling for all those modes if rotation is 0 or 2, and + also fast scrolling if rotation is 1 or 3. The default virtual y reso- + lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32, + again with the only exception of 1280x1024 at 32 bpp. + + Please do set your video memory size to 8 Mb in the Bios setup. Other + values will work, but performace is decreased for a lot of modes. + Mode changes using fbset ======================== @@ -54,20 +64,26 @@ Selecting Modes - if a flat panel is found, cyblafb does not allow you to program a resolution higher than the physical resolution of the flat panel monitor - - cyblafb does not allow xres to differ from xres_virtual - cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp and (currently) 24 bit modes use a doubled vclk internally, the dotclock limit as seen by fbset is 115 MHz for those modes and 230 MHz for 8 and 16 bpp modes. + - cyblafb will allow you to select very high resolutions as + long as the hardware can be programmed to these modes. The + documented limit 1600x1200 is not enforced, but don't expect + perfect signal quality. - Any request that violates the rules given above will be ignored and - fbset will return an error. + Any request that violates the rules given above will be either changed + to something the hardware supports or an error value will be returned. If you program a virtual y resolution higher than the hardware limit, cyblafb will silently decrease that value to the highest possible - value. + value. The same is true for a virtual x resolution that is not + supported by the hardware. Cyblafb tries to adapt vyres first because + vxres decides if ywrap scrolling is possible or not. - Attempts to disable acceleration are ignored. + Attempts to disable acceleration are ignored, I believe that this is + safe. Some video modes that should work do not work as expected. If you use the standard fb.modes, fbset 640x480-60 will program that mode, but @@ -129,10 +145,6 @@ mode 640x480 or 800x600 or 1024x768 or 1280x1024 verbosity 0 is the default, increase to at least 2 for every bug report! -vesafb allows cyblafb to be loaded after vesafb has been - loaded. See sections "Module unloading ...". - - Development hints ================= @@ -195,7 +207,7 @@ a graphics mode. After booting, load cyblafb without any mode and bpp parameter and assign cyblafb to individual ttys using con2fb, e.g.: - modprobe cyblafb vesafb=1 + modprobe cyblafb con2fb /dev/fb1 /dev/tty1 Unloading cyblafb works without problems after you assign vesafb to all @@ -203,4 +215,3 @@ ttys again, e.g.: con2fb /dev/fb0 /dev/tty1 rmmod cyblafb - diff --git a/Documentation/fb/cyblafb/whatsnew b/Documentation/fb/cyblafb/whatsnew new file mode 100644 index 000000000000..76c07a26e044 --- /dev/null +++ b/Documentation/fb/cyblafb/whatsnew @@ -0,0 +1,29 @@ +0.62 +==== + + - the vesafb parameter has been removed as I decided to allow the + feature without any special parameter. + + - Cyblafb does not use the vga style of panning any longer, now the + "right view" register in the graphics engine IO space is used. Without + that change it was impossible to use all available memory, and without + access to all available memory it is impossible to ywrap. + + - The imageblit function now uses hardware acceleration for all font + widths. Hardware blitting across pixel column 2048 is broken in the + cyberblade/i1 graphics core, but we work around that hardware bug. + + - modes with vxres != xres are supported now. + + - ywrap scrolling is supported now and the default. This is a big + performance gain. + + - default video modes use vyres > yres and vxres > xres to allow + almost optimal scrolling speed for normal and rotated screens + + - some features mainly usefull for debugging the upper layers of the + framebuffer system have been added, have a look at the code + + - fixed: Oops after unloading cyblafb when reading /proc/io* + + - we work around some bugs of the higher framebuffer layers. diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index cc8e3bf5001b..3f04427c9026 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1151,7 +1151,7 @@ config FB_VOODOO1 config FB_CYBLA tristate "Cyberblade/i1 support" - depends on FB && PCI + depends on FB && PCI && X86_32 && !64BIT select FB_CFB_IMAGEBLIT select VIDEO_SELECT ---help--- diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c index 03fbe83d71a8..e9f5dee67e3c 100644 --- a/drivers/video/cyblafb.c +++ b/drivers/video/cyblafb.c @@ -7,11 +7,12 @@ * tridentfb.c by Jani Monoses * see files above for further credits * - * TODO: - * */ #define CYBLAFB_DEBUG 0 +#define CYBLAFB_KD_GRAPHICS_QUIRK 1 + +#define CYBLAFB_PIXMAPSIZE 8192 #include #include @@ -22,7 +23,7 @@ #include #include