Merge ../linux-2.6

This commit is contained in:
Paul Mackerras 2006-03-29 13:24:50 +11:00
commit bac30d1a78
779 changed files with 22983 additions and 7760 deletions

View file

@ -70,4 +70,6 @@ source "drivers/sn/Kconfig"
source "drivers/edac/Kconfig"
source "drivers/rtc/Kconfig"
endmenu

View file

@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_HWMON) += hwmon/

View file

@ -1972,7 +1972,7 @@ static int __devinit lanai_pci_start(struct lanai_dev *lanai)
"(itf %d): No suitable DMA available.\n", lanai->number);
return -EBUSY;
}
if (pci_set_consistent_dma_mask(pci, 0xFFFFFFFF) != 0) {
if (pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) != 0) {
printk(KERN_WARNING DEV_LABEL
"(itf %d): No suitable DMA available.\n", lanai->number);
return -EBUSY;

View file

@ -47,16 +47,16 @@ static struct kset_uevent_ops memory_uevent_ops = {
.uevent = memory_uevent,
};
static struct notifier_block *memory_chain;
static BLOCKING_NOTIFIER_HEAD(memory_chain);
int register_memory_notifier(struct notifier_block *nb)
{
return notifier_chain_register(&memory_chain, nb);
return blocking_notifier_chain_register(&memory_chain, nb);
}
void unregister_memory_notifier(struct notifier_block *nb)
{
notifier_chain_unregister(&memory_chain, nb);
blocking_notifier_chain_unregister(&memory_chain, nb);
}
/*
@ -140,7 +140,7 @@ static ssize_t show_mem_state(struct sys_device *dev, char *buf)
static inline int memory_notify(unsigned long val, void *v)
{
return notifier_call_chain(&memory_chain, val, v);
return blocking_notifier_call_chain(&memory_chain, val, v);
}
/*

View file

@ -41,6 +41,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/random.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@ -311,11 +312,10 @@ static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
CommandsRemaining = CommandAllocationGroupSize;
CommandGroupByteCount =
CommandsRemaining * CommandAllocationLength;
AllocationPointer = kmalloc(CommandGroupByteCount, GFP_ATOMIC);
AllocationPointer = kzalloc(CommandGroupByteCount, GFP_ATOMIC);
if (AllocationPointer == NULL)
return DAC960_Failure(Controller,
"AUXILIARY STRUCTURE CREATION");
memset(AllocationPointer, 0, CommandGroupByteCount);
}
Command = (DAC960_Command_T *) AllocationPointer;
AllocationPointer += CommandAllocationLength;
@ -2709,14 +2709,12 @@ DAC960_DetectController(struct pci_dev *PCI_Device,
void __iomem *BaseAddress;
int i;
Controller = (DAC960_Controller_T *)
kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
Controller = kzalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
if (Controller == NULL) {
DAC960_Error("Unable to allocate Controller structure for "
"Controller at\n", NULL);
return NULL;
}
memset(Controller, 0, sizeof(DAC960_Controller_T));
Controller->ControllerNumber = DAC960_ControllerCount;
DAC960_Controllers[DAC960_ControllerCount++] = Controller;
Controller->Bus = PCI_Device->bus->number;
@ -3657,8 +3655,8 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
(NewEnquiry->EventLogSequenceNumber !=
OldEnquiry->EventLogSequenceNumber) ||
Controller->MonitoringTimerCount == 0 ||
(jiffies - Controller->SecondaryMonitoringTime
>= DAC960_SecondaryMonitoringInterval))
time_after_eq(jiffies, Controller->SecondaryMonitoringTime
+ DAC960_SecondaryMonitoringInterval))
{
Controller->V1.NeedLogicalDriveInformation = true;
Controller->V1.NewEventLogSequenceNumber =
@ -5643,8 +5641,8 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
unsigned int StatusChangeCounter =
Controller->V2.HealthStatusBuffer->StatusChangeCounter;
boolean ForceMonitoringCommand = false;
if (jiffies - Controller->SecondaryMonitoringTime
> DAC960_SecondaryMonitoringInterval)
if (time_after(jiffies, Controller->SecondaryMonitoringTime
+ DAC960_SecondaryMonitoringInterval))
{
int LogicalDriveNumber;
for (LogicalDriveNumber = 0;
@ -5672,8 +5670,8 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
ControllerInfo->ConsistencyChecksActive +
ControllerInfo->RebuildsActive +
ControllerInfo->OnlineExpansionsActive == 0 ||
jiffies - Controller->PrimaryMonitoringTime
< DAC960_MonitoringTimerInterval) &&
time_before(jiffies, Controller->PrimaryMonitoringTime
+ DAC960_MonitoringTimerInterval)) &&
!ForceMonitoringCommand)
{
Controller->MonitoringTimer.expires =
@ -5810,8 +5808,8 @@ static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
Controller->ProgressBufferLength = Length;
if (Controller->EphemeralProgressMessage)
{
if (jiffies - Controller->LastProgressReportTime
>= DAC960_ProgressReportingInterval)
if (time_after_eq(jiffies, Controller->LastProgressReportTime
+ DAC960_ProgressReportingInterval))
{
printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
Controller->ControllerNumber, Buffer);

View file

@ -383,8 +383,9 @@ config BLK_DEV_RAM
thus say N here.
config BLK_DEV_RAM_COUNT
int "Default number of RAM disks" if BLK_DEV_RAM
int "Default number of RAM disks"
default "16"
depends on BLK_DEV_RAM
help
The default value is 16 RAM disks. Change this if you know what
are doing. If you boot from a filesystem that needs to be extracted

View file

@ -369,8 +369,6 @@ static ssize_t slm_read( struct file *file, char *buf, size_t count,
int length;
int end;
if (count < 0)
return( -EINVAL );
if (!(page = __get_free_page( GFP_KERNEL )))
return( -ENOMEM );

View file

@ -996,13 +996,11 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
status = -EINVAL;
goto cleanup1;
}
buff = (unsigned char **) kmalloc(MAXSGENTRIES *
sizeof(char *), GFP_KERNEL);
buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
if (!buff) {
status = -ENOMEM;
goto cleanup1;
}
memset(buff, 0, MAXSGENTRIES);
buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int),
GFP_KERNEL);
if (!buff_size) {
@ -2729,9 +2727,9 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev,
return;
}
}
default_int_mode:
#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;
}
@ -2940,13 +2938,12 @@ static void cciss_getgeometry(int cntl_num)
int block_size;
int total_size;
ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
if (ld_buff == NULL)
{
printk(KERN_ERR "cciss: out of memory\n");
return;
}
memset(ld_buff, 0, sizeof(ReportLunData_struct));
size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
if (size_buff == NULL)
{
@ -3060,10 +3057,9 @@ static int alloc_cciss_hba(void)
for(i=0; i< MAX_CTLR; i++) {
if (!hba[i]) {
ctlr_info_t *p;
p = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
if (!p)
goto Enomem;
memset(p, 0, sizeof(ctlr_info_t));
for (n = 0; n < NWD; n++)
p->gendisk[n] = disk[n];
hba[i] = p;

View file

@ -1027,12 +1027,11 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
int i;
c = (ctlr_info_t *) hba[cntl_num];
ld_buff = kmalloc(reportlunsize, GFP_KERNEL);
ld_buff = kzalloc(reportlunsize, GFP_KERNEL);
if (ld_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
return;
}
memset(ld_buff, 0, reportlunsize);
inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
if (inq_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");

View file

@ -170,6 +170,7 @@ static int print_unex = 1;
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/string.h>
#include <linux/jiffies.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
@ -747,7 +748,7 @@ static int disk_change(int drive)
{
int fdc = FDC(drive);
#ifdef FLOPPY_SANITY_CHECK
if (jiffies - UDRS->select_date < UDP->select_delay)
if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
DPRINT("WARNING disk change called early\n");
if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
(FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
@ -1075,7 +1076,7 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
return 1;
}
if ((signed)(jiffies - delay) < 0) {
if (time_before(jiffies, delay)) {
del_timer(&fd_timer);
fd_timer.function = function;
fd_timer.expires = delay;
@ -1535,7 +1536,7 @@ static void setup_rw_floppy(void)
* again just before spinup completion. Beware that
* after scandrives, we must again wait for selection.
*/
if ((signed)(ready_date - jiffies) > DP->select_delay) {
if (time_after(ready_date, jiffies + DP->select_delay)) {
ready_date -= DP->select_delay;
function = (timeout_fn) floppy_start;
} else
@ -3823,7 +3824,7 @@ static int check_floppy_change(struct gendisk *disk)
if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
return 1;
if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) {
if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
if (floppy_grab_irq_and_dma()) {
return 1;
}

View file

@ -224,10 +224,9 @@ static void bpck6_log_adapter( PIA *pi, char * scratch, int verbose )
static int bpck6_init_proto(PIA *pi)
{
Interface *p = kmalloc(sizeof(Interface), GFP_KERNEL);
Interface *p = kzalloc(sizeof(Interface), GFP_KERNEL);
if (p) {
memset(p, 0, sizeof(Interface));
pi->private = (unsigned long)p;
return 0;
}

View file

@ -151,6 +151,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
#include <linux/cdrom.h> /* for the eject ioctl */
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
@ -275,7 +276,7 @@ static void pd_print_error(struct pd_unit *disk, char *msg, int status)
int i;
printk("%s: %s: status = 0x%x =", disk->name, msg, status);
for (i = 0; i < 18; i++)
for (i = 0; i < ARRAY_SIZE(pd_errs); i++)
if (status & (1 << i))
printk(" %s", pd_errs[i]);
printk("\n");

View file

@ -643,7 +643,8 @@ static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t
static int __init pg_init(void)
{
int unit, err = 0;
int unit;
int err;
if (disable){
err = -1;
@ -657,16 +658,17 @@ static int __init pg_init(void)
goto out;
}
if (register_chrdev(major, name, &pg_fops)) {
err = register_chrdev(major, name, &pg_fops);
if (err < 0) {
printk("pg_init: unable to get major number %d\n", major);
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
if (dev->present)
pi_release(dev->pi);
}
err = -1;
goto out;
}
major = err; /* In case the user specified `major=0' (dynamic) */
pg_class = class_create(THIS_MODULE, "pg");
if (IS_ERR(pg_class)) {
err = PTR_ERR(pg_class);

View file

@ -943,7 +943,8 @@ static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count,
static int __init pt_init(void)
{
int unit, err = 0;
int unit;
int err;
if (disable) {
err = -1;
@ -955,14 +956,15 @@ static int __init pt_init(void)
goto out;
}
if (register_chrdev(major, name, &pt_fops)) {
err = register_chrdev(major, name, &pt_fops);
if (err < 0) {
printk("pt_init: unable to get major number %d\n", major);
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present)
pi_release(pt[unit].pi);
err = -1;
goto out;
}
major = err;
pt_class = class_create(THIS_MODULE, "pt");
if (IS_ERR(pt_class)) {
err = PTR_ERR(pt_class);

View file

@ -50,6 +50,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
@ -881,8 +882,8 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n",
card->card_number, dev->bus->number, dev->devfn);
if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) &&
pci_set_dma_mask(dev, 0xffffffffLL)) {
if (pci_set_dma_mask(dev, DMA_64BIT_MASK) &&
pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
return -ENOMEM;
}

View file

@ -713,7 +713,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM
---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

View file

@ -11,6 +11,7 @@
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <linux/mm.h>
#include <linux/jiffies.h>
#include "agp.h"
/* NVIDIA registers */
@ -256,7 +257,7 @@ static void nvidia_tlbflush(struct agp_memory *mem)
do {
pci_read_config_dword(nvidia_private.dev_1,
NVIDIA_1_WBC, &wbc_reg);
if ((signed)(end - jiffies) <= 0) {
if (time_before_eq(end, jiffies)) {
printk(KERN_ERR PFX
"TLB flush took more than 3 seconds.\n");
}

View file

@ -175,7 +175,7 @@ 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;
const struct file_operations *old_fops;
DRM_DEBUG("\n");

View file

@ -126,7 +126,7 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp)
drm_device_t *dev = priv->head->dev;
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
drm_i810_private_t *dev_priv = dev->dev_private;
struct file_operations *old_fops;
const struct file_operations *old_fops;
int retcode = 0;
if (buf_priv->currently_mapped == I810_BUF_MAPPED)

View file

@ -128,7 +128,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp)
drm_device_t *dev = priv->head->dev;
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
drm_i830_private_t *dev_priv = dev->dev_private;
struct file_operations *old_fops;
const struct file_operations *old_fops;
unsigned long virtual;
int retcode = 0;

View file

@ -3744,7 +3744,7 @@ static int ipmi_init_msghandler(void)
ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
add_timer(&ipmi_timer);
notifier_chain_register(&panic_notifier_list, &panic_block);
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
initialized = 1;
@ -3764,7 +3764,7 @@ static __exit void cleanup_ipmi(void)
if (!initialized)
return;
notifier_chain_unregister(&panic_notifier_list, &panic_block);
atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
/* This can't be called if any interfaces exist, so no worry about
shutting down the interfaces. */

View file

@ -237,10 +237,10 @@ struct smi_info
static int try_smi_init(struct smi_info *smi);
static struct notifier_block *xaction_notifier_list;
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
static int register_xaction_notifier(struct notifier_block * nb)
{
return notifier_chain_register(&xaction_notifier_list, nb);
return atomic_notifier_chain_register(&xaction_notifier_list, nb);
}
static void si_restart_short_timer(struct smi_info *smi_info);
@ -302,7 +302,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
do_gettimeofday(&t);
printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
err = notifier_call_chain(&xaction_notifier_list, 0, smi_info);
err = atomic_notifier_call_chain(&xaction_notifier_list,
0, smi_info);
if (err & NOTIFY_STOP_MASK) {
rv = SI_SM_CALL_WITHOUT_DELAY;
goto out;

View file

@ -1158,7 +1158,8 @@ static int __init ipmi_wdog_init(void)
}
register_reboot_notifier(&wdog_reboot_notifier);
notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
atomic_notifier_chain_register(&panic_notifier_list,
&wdog_panic_notifier);
printk(KERN_INFO PFX "driver initialized\n");
@ -1176,7 +1177,8 @@ static __exit void ipmi_unregister_watchdog(void)
release_nmi(&ipmi_nmi_handler);
#endif
notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier);
atomic_notifier_chain_unregister(&panic_notifier_list,
&wdog_panic_notifier);
unregister_reboot_notifier(&wdog_reboot_notifier);
if (! watchdog_user)

View file

@ -899,7 +899,7 @@ static const struct {
unsigned int minor;
char *name;
umode_t mode;
struct file_operations *fops;
const struct file_operations *fops;
} devlist[] = { /* list of minor devices */
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},

View file

@ -129,7 +129,7 @@ static int misc_open(struct inode * inode, struct file * file)
int minor = iminor(inode);
struct miscdevice *c;
int err = -ENODEV;
struct file_operations *old_fops, *new_fops = NULL;
const struct file_operations *old_fops, *new_fops = NULL;
down(&misc_sem);

View file

@ -118,7 +118,7 @@
// enable CTS interrupt
#define MOXA_MUST_IER_ECTSI 0x80
// eanble RTS interrupt
// enable RTS interrupt
#define MOXA_MUST_IER_ERTSI 0x40
// enable Xon/Xoff interrupt
#define MOXA_MUST_IER_XINT 0x20

View file

@ -941,17 +941,6 @@ static void* mgsl_get_text_ptr(void)
return mgsl_get_text_ptr;
}
/*
* tmp_buf is used as a temporary buffer by mgsl_write. We need to
* lock it in case the COPY_FROM_USER blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ioports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf;
static inline int mgsl_paranoia_check(struct mgsl_struct *info,
char *name, const char *routine)
{
@ -2150,7 +2139,7 @@ static int mgsl_write(struct tty_struct * tty,
if (mgsl_paranoia_check(info, tty->name, "mgsl_write"))
goto cleanup;
if (!tty || !info->xmit_buf || !tmp_buf)
if (!tty || !info->xmit_buf)
goto cleanup;
if ( info->params.mode == MGSL_MODE_HDLC ||
@ -3438,7 +3427,6 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
{
struct mgsl_struct *info;
int retval, line;
unsigned long page;
unsigned long flags;
/* verify range of specified line number */
@ -3472,18 +3460,6 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
goto cleanup;
}
if (!tmp_buf) {
page = get_zeroed_page(GFP_KERNEL);
if (!page) {
retval = -ENOMEM;
goto cleanup;
}
if (tmp_buf)
free_page(page);
else
tmp_buf = (unsigned char *) page;
}
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
spin_lock_irqsave(&info->netlock, flags);
@ -4502,11 +4478,6 @@ static void synclink_cleanup(void)
kfree(tmp);
}
if (tmp_buf) {
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
}
if (pci_registered)
pci_unregister_driver(&synclink_pci_driver);
}
@ -6025,7 +5996,7 @@ static void usc_set_async_mode( struct mgsl_struct *info )
* <15..8> ? RxFIFO IRQ Request Level
*
* Note: For async mode the receive FIFO level must be set
* to 0 to aviod the situation where the FIFO contains fewer bytes
* to 0 to avoid the situation where the FIFO contains fewer bytes
* than the trigger level and no more data is expected.
*
* <7> 0 Exited Hunt IA (Interrupt Arm)

View file

@ -1,5 +1,5 @@
/*
* $Id: synclink_gt.c,v 4.22 2006/01/09 20:16:06 paulkf Exp $
* $Id: synclink_gt.c,v 4.25 2006/02/06 21:20:33 paulkf Exp $
*
* Device driver for Microgate SyncLink GT serial adapters.
*
@ -92,7 +92,7 @@
* module identification
*/
static char *driver_name = "SyncLink GT";
static char *driver_version = "$Revision: 4.22 $";
static char *driver_version = "$Revision: 4.25 $";
static char *tty_driver_name = "synclink_gt";
static char *tty_dev_prefix = "ttySLG";
MODULE_LICENSE("GPL");
@ -187,6 +187,20 @@ static void hdlcdev_exit(struct slgt_info *info);
#define SLGT_MAX_PORTS 4
#define SLGT_REG_SIZE 256
/*
* conditional wait facility
*/
struct cond_wait {
struct cond_wait *next;
wait_queue_head_t q;
wait_queue_t wait;
unsigned int data;
};
static void init_cond_wait(struct cond_wait *w, unsigned int data);
static void add_cond_wait(struct cond_wait **head, struct cond_wait *w);
static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w);
static void flush_cond_wait(struct cond_wait **head);
/*
* DMA buffer descriptor and access macros
*/
@ -269,6 +283,9 @@ struct slgt_info {
struct timer_list tx_timer;
struct timer_list rx_timer;
unsigned int gpio_present;
struct cond_wait *gpio_wait_q;
spinlock_t lock; /* spinlock for synchronizing with ISR */
struct work_struct task;
@ -379,6 +396,11 @@ static MGSL_PARAMS default_params = {
#define MASK_OVERRUN BIT4
#define GSR 0x00 /* global status */
#define JCR 0x04 /* JTAG control */
#define IODR 0x08 /* GPIO direction */
#define IOER 0x0c /* GPIO interrupt enable */
#define IOVR 0x10 /* GPIO value */
#define IOSR 0x14 /* GPIO interrupt status */
#define TDR 0x80 /* tx data */
#define RDR 0x80 /* rx data */
#define TCR 0x82 /* tx control */
@ -503,6 +525,9 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
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);
static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
static int get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
/*
* driver functions
@ -1112,6 +1137,12 @@ static int ioctl(struct tty_struct *tty, struct file *file,
return get_interface(info, argp);
case MGSL_IOCSIF:
return set_interface(info,(int)arg);
case MGSL_IOCSGPIO:
return set_gpio(info, argp);
case MGSL_IOCGGPIO:
return get_gpio(info, argp);
case MGSL_IOCWAITGPIO:
return wait_gpio(info, argp);
case TIOCGICOUNT:
spin_lock_irqsave(&info->lock,flags);
cnow = info->icount;
@ -1762,10 +1793,6 @@ static void rx_async(struct slgt_info *info)
DBGDATA(info, p, count, "rx");
for(i=0 ; i < count; i+=2, p+=2) {
if (tty && chars) {
tty_flip_buffer_push(tty);
chars = 0;
}
ch = *p;
icount->rx++;
@ -2158,6 +2185,24 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
}
}
static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state)
{
struct cond_wait *w, *prev;
/* wake processes waiting for specific transitions */
for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) {
if (w->data & changed) {
w->data = state;
wake_up_interruptible(&w->q);
if (prev != NULL)
prev->next = w->next;
else
info->gpio_wait_q = w->next;
} else
prev = w;
}
}
/* interrupt service routine
*
* irq interrupt number
@ -2193,6 +2238,22 @@ static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
}
if (info->gpio_present) {
unsigned int state;
unsigned int changed;
while ((changed = rd_reg32(info, IOSR)) != 0) {
DBGISR(("%s iosr=%08x\n", info->device_name, changed));
/* read latched state of GPIO signals */
state = rd_reg32(info, IOVR);
/* clear pending GPIO interrupt bits */
wr_reg32(info, IOSR, changed);
for (i=0 ; i < info->port_count ; i++) {
if (info->port_array[i] != NULL)
isr_gpio(info->port_array[i], changed, state);
}
}
}
for(i=0; i < info->port_count ; i++) {
struct slgt_info *port = info->port_array[i];
@ -2276,6 +2337,8 @@ static void shutdown(struct slgt_info *info)
set_signals(info);
}
flush_cond_wait(&info->gpio_wait_q);
spin_unlock_irqrestore(&info->lock,flags);
if (info->tty)
@ -2650,6 +2713,175 @@ static int set_interface(struct slgt_info *info, int if_mode)
return 0;
}
/*
* set general purpose IO pin state and direction
*
* user_gpio fields:
* state each bit indicates a pin state
* smask set bit indicates pin state to set
* dir each bit indicates a pin direction (0=input, 1=output)
* dmask set bit indicates pin direction to set
*/
static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
{
unsigned long flags;
struct gpio_desc gpio;
__u32 data;
if (!info->gpio_present)
return -EINVAL;
if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
return -EFAULT;
DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n",
info->device_name, gpio.state, gpio.smask,
gpio.dir, gpio.dmask));
spin_lock_irqsave(&info->lock,flags);
if (gpio.dmask) {
data = rd_reg32(info, IODR);
data |= gpio.dmask & gpio.dir;
data &= ~(gpio.dmask & ~gpio.dir);
wr_reg32(info, IODR, data);
}
if (gpio.smask) {
data = rd_reg32(info, IOVR);
data |= gpio.smask & gpio.state;
data &= ~(gpio.smask & ~gpio.state);
wr_reg32(info, IOVR, data);
}
spin_unlock_irqrestore(&info->lock,flags);
return 0;
}
/*
* get general purpose IO pin state and direction
*/
static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
{
struct gpio_desc gpio;
if (!info->gpio_present)
return -EINVAL;
gpio.state = rd_reg32(info, IOVR);
gpio.smask = 0xffffffff;
gpio.dir = rd_reg32(info, IODR);
gpio.dmask = 0xffffffff;
if (copy_to_user(user_gpio, &gpio, sizeof(gpio)))
return -EFAULT;
DBGINFO(("%s get_gpio state=%08x dir=%08x\n",
info->device_name, gpio.state, gpio.dir));
return 0;
}
/*
* conditional wait facility
*/
static void init_cond_wait(struct cond_wait *w, unsigned int data)
{
init_waitqueue_head(&w->q);
init_waitqueue_entry(&w->wait, current);
w->data = data;
}
static void add_cond_wait(struct cond_wait **head, struct cond_wait *w)
{
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&w->q, &w->wait);
w->next = *head;
*head = w;
}
static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw)
{
struct cond_wait *w, *prev;
remove_wait_queue(&cw->q, &cw->wait);
set_current_state(TASK_RUNNING);
for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) {
if (w == cw) {
if (prev != NULL)
prev->next = w->next;
else
*head = w->next;
break;
}
}
}
static void flush_cond_wait(struct cond_wait **head)
{
while (*head != NULL) {
wake_up_interruptible(&(*head)->q);
*head = (*head)->next;
}
}
/*
* wait for general purpose I/O pin(s) to enter specified state
*
* user_gpio fields:
* state - bit indicates target pin state
* smask - set bit indicates watched pin
*
* The wait ends when at least one watched pin enters the specified
* state. When 0 (no error) is returned, user_gpio->state is set to the
* state of all GPIO pins when the wait ends.
*
* Note: Each pin may be a dedicated input, dedicated output, or
* configurable input/output. The number and configuration of pins
* varies with the specific adapter model. Only input pins (dedicated
* or configured) can be monitored with this function.
*/
static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
{
unsigned long flags;
int rc = 0;
struct gpio_desc gpio;
struct cond_wait wait;
u32 state;
if (!info->gpio_present)
return -EINVAL;
if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
return -EFAULT;
DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n",
info->device_name, gpio.state, gpio.smask));
/* ignore output pins identified by set IODR bit */
if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0)
return -EINVAL;
init_cond_wait(&wait, gpio.smask);
spin_lock_irqsave(&info->lock, flags);
/* enable interrupts for watched pins */
wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
/* get current pin states */
state = rd_reg32(info, IOVR);
if (gpio.smask & ~(state ^ gpio.state)) {
/* already in target state */
gpio.state = state;
} else {
/* wait for target state */
add_cond_wait(&info->gpio_wait_q, &wait);
spin_unlock_irqrestore(&info->lock, flags);
schedule();
if (signal_pending(current))
rc = -ERESTARTSYS;
else
gpio.state = wait.data;
spin_lock_irqsave(&info->lock, flags);
remove_cond_wait(&info->gpio_wait_q, &wait);
}
/* disable all GPIO interrupts if no waiting processes */
if (info->gpio_wait_q == NULL)
wr_reg32(info, IOER, 0);
spin_unlock_irqrestore(&info->lock,flags);
if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
rc = -EFAULT;
return rc;
}
static int modem_input_wait(struct slgt_info *info,int arg)
{
unsigned long flags;
@ -3166,8 +3398,10 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
} else {
port_array[0]->irq_requested = 1;
adapter_test(port_array[0]);
for (i=1 ; i < port_count ; i++)
for (i=1 ; i < port_count ; i++) {
port_array[i]->init_error = port_array[0]->init_error;
port_array[i]->gpio_present = port_array[0]->gpio_present;
}
}
}
}
@ -4301,7 +4535,7 @@ static int register_test(struct slgt_info *info)
break;
}
}
info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0;
info->init_error = rc ? 0 : DiagStatus_AddressFailure;
return rc;
}

View file

@ -52,9 +52,8 @@ static void handle_update(void *data);
* changes to devices when the CPU clock speed changes.
* The mutex locks both lists.
*/
static struct notifier_block *cpufreq_policy_notifier_list;
static struct notifier_block *cpufreq_transition_notifier_list;
static DECLARE_RWSEM (cpufreq_notifier_rwsem);
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
static LIST_HEAD(cpufreq_governor_list);
@ -247,8 +246,6 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
dprintk("notification %u of frequency transition to %u kHz\n",
state, freqs->new);
down_read(&cpufreq_notifier_rwsem);
policy = cpufreq_cpu_data[freqs->cpu];
switch (state) {
@ -266,20 +263,19 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
freqs->old = policy->cur;
}
}
notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs);
blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
policy->cur = freqs->new;
break;
}
up_read(&cpufreq_notifier_rwsem);
}
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
@ -1007,7 +1003,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
notifier_call_chain(&cpufreq_transition_notifier_list,
blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_SUSPENDCHANGE, &freqs);
adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
@ -1088,7 +1084,8 @@ static int cpufreq_resume(struct sys_device * sysdev)
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
notifier_call_chain(&cpufreq_transition_notifier_list,
blocking_notifier_call_chain(
&cpufreq_transition_notifier_list,
CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
@ -1125,24 +1122,24 @@ static struct sysdev_driver cpufreq_sysdev_driver = {
* changes in cpufreq policy.
*
* This function may sleep, and has the same return conditions as
* notifier_chain_register.
* blocking_notifier_chain_register.
*/
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
{
int ret;
down_write(&cpufreq_notifier_rwsem);
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb);
ret = blocking_notifier_chain_register(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb);
ret = blocking_notifier_chain_register(
&cpufreq_policy_notifier_list, nb);
break;
default:
ret = -EINVAL;
}
up_write(&cpufreq_notifier_rwsem);
return ret;
}
@ -1157,24 +1154,24 @@ EXPORT_SYMBOL(cpufreq_register_notifier);
* Remove a driver from the CPU frequency notifier list.
*
* This function may sleep, and has the same return conditions as
* notifier_chain_unregister.
* blocking_notifier_chain_unregister.
*/
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
{
int ret;
down_write(&cpufreq_notifier_rwsem);
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb);
ret = blocking_notifier_chain_unregister(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb);
ret = blocking_notifier_chain_unregister(
&cpufreq_policy_notifier_list, nb);
break;
default:
ret = -EINVAL;
}
up_write(&cpufreq_notifier_rwsem);
return ret;
}
@ -1346,29 +1343,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
if (ret)
goto error_out;
down_read(&cpufreq_notifier_rwsem);
/* adjust if necessary - all reasons */
notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST,
policy);
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_ADJUST, policy);
/* adjust if necessary - hardware incompatibility*/
notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE,
policy);
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_INCOMPATIBLE, policy);
/* verify the cpu speed can be set within this limit,
which might be different to the first one */
ret = cpufreq_driver->verify(policy);
if (ret) {
up_read(&cpufreq_notifier_rwsem);
if (ret)
goto error_out;
}
/* notification of the new policy */
notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY,
policy);
up_read(&cpufreq_notifier_rwsem);
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_NOTIFY, policy);
data->min = policy->min;
data->max = policy->max;

View file

@ -35,12 +35,7 @@
*/
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define MIN_FREQUENCY_UP_THRESHOLD (0)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
#define MIN_FREQUENCY_DOWN_THRESHOLD (0)
#define MAX_FREQUENCY_DOWN_THRESHOLD (100)
/*
* The polling frequency of this governor depends on the capability of
@ -53,10 +48,14 @@
* All times here are in uS.
*/
static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE (def_sampling_rate / 2)
#define MIN_SAMPLING_RATE_RATIO (2)
/* for correct statistics, we need at least 10 ticks between each measure */
#define MIN_STAT_SAMPLING_RATE (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (100000)
#define DEF_SAMPLING_DOWN_FACTOR (5)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
#define TRANSITION_LATENCY_LIMIT (10 * 1000)
static void do_dbs_timer(void *data);
@ -66,6 +65,8 @@ struct cpu_dbs_info_s {
unsigned int prev_cpu_idle_up;
unsigned int prev_cpu_idle_down;
unsigned int enable;
unsigned int down_skip;
unsigned int requested_freq;
};
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
@ -87,6 +88,8 @@ static struct dbs_tuners dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
.down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
.ignore_nice = 0,
.freq_step = 5,
};
static inline unsigned int get_cpu_idle_time(unsigned int cpu)
@ -136,7 +139,7 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
unsigned int input;
int ret;
ret = sscanf (buf, "%u", &input);
if (ret != 1 )
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
mutex_lock(&dbs_mutex);
@ -173,8 +176,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
ret = sscanf (buf, "%u", &input);
mutex_lock(&dbs_mutex);
if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
input < MIN_FREQUENCY_UP_THRESHOLD ||
if (ret != 1 || input > 100 || input < 0 ||
input <= dbs_tuners_ins.down_threshold) {
mutex_unlock(&dbs_mutex);
return -EINVAL;
@ -194,8 +196,7 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused,
ret = sscanf (buf, "%u", &input);
mutex_lock(&dbs_mutex);
if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD ||
input < MIN_FREQUENCY_DOWN_THRESHOLD ||
if (ret != 1 || input > 100 || input < 0 ||
input >= dbs_tuners_ins.up_threshold) {
mutex_unlock(&dbs_mutex);
return -EINVAL;
@ -297,31 +298,17 @@ static struct attribute_group dbs_attr_group = {
static void dbs_check_cpu(int cpu)
{
unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
unsigned int tmp_idle_ticks, total_idle_ticks;
unsigned int freq_step;
unsigned int freq_down_sampling_rate;
static int down_skip[NR_CPUS];
static int requested_freq[NR_CPUS];
static unsigned short init_flag = 0;
struct cpu_dbs_info_s *this_dbs_info;
struct cpu_dbs_info_s *dbs_info;
struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
struct cpufreq_policy *policy;
unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
if (!this_dbs_info->enable)
return;
policy = this_dbs_info->cur_policy;
if ( init_flag == 0 ) {
for_each_online_cpu(j) {
dbs_info = &per_cpu(cpu_dbs_info, j);
requested_freq[j] = dbs_info->cur_policy->cur;
}
init_flag = 1;
}
/*
* The default safe range is 20% to 80%
* Every sampling_rate, we check
@ -337,39 +324,29 @@ static void dbs_check_cpu(int cpu)
*/
/* Check for frequency increase */
idle_ticks = UINT_MAX;
for_each_cpu_mask(j, policy->cpus) {
unsigned int tmp_idle_ticks, total_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
/* Check for frequency increase */
total_idle_ticks = get_cpu_idle_time(j);
tmp_idle_ticks = total_idle_ticks -
j_dbs_info->prev_cpu_idle_up;
j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
/* Check for frequency increase */
total_idle_ticks = get_cpu_idle_time(cpu);
tmp_idle_ticks = total_idle_ticks -
this_dbs_info->prev_cpu_idle_up;
this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
}
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
/* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100;
up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
if (idle_ticks < up_idle_ticks) {
down_skip[cpu] = 0;
for_each_cpu_mask(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
this_dbs_info->down_skip = 0;
this_dbs_info->prev_cpu_idle_down =
this_dbs_info->prev_cpu_idle_up;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->prev_cpu_idle_down =
j_dbs_info->prev_cpu_idle_up;
}
/* if we are already at full speed then break out early */
if (requested_freq[cpu] == policy->max)
if (this_dbs_info->requested_freq == policy->max)
return;
freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
@ -378,49 +355,45 @@ static void dbs_check_cpu(int cpu)
if (unlikely(freq_step == 0))
freq_step = 5;
requested_freq[cpu] += freq_step;
if (requested_freq[cpu] > policy->max)
requested_freq[cpu] = policy->max;
this_dbs_info->requested_freq += freq_step;
if (this_dbs_info->requested_freq > policy->max)
this_dbs_info->requested_freq = policy->max;
__cpufreq_driver_target(policy, requested_freq[cpu],
__cpufreq_driver_target(policy, this_dbs_info->requested_freq,
CPUFREQ_RELATION_H);
return;
}
/* Check for frequency decrease */
down_skip[cpu]++;
if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
this_dbs_info->down_skip++;
if (this_dbs_info->down_skip < dbs_tuners_ins.sampling_down_factor)
return;
idle_ticks = UINT_MAX;
for_each_cpu_mask(j, policy->cpus) {
unsigned int tmp_idle_ticks, total_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
/* Check for frequency decrease */
total_idle_ticks = this_dbs_info->prev_cpu_idle_up;
tmp_idle_ticks = total_idle_ticks -
this_dbs_info->prev_cpu_idle_down;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
tmp_idle_ticks = total_idle_ticks -
j_dbs_info->prev_cpu_idle_down;
j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
}
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
/* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100;
down_skip[cpu] = 0;
this_dbs_info->down_skip = 0;
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor;
down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
usecs_to_jiffies(freq_down_sampling_rate);
usecs_to_jiffies(freq_down_sampling_rate);
if (idle_ticks > down_idle_ticks) {
/* if we are already at the lowest speed then break out early
/*
* if we are already at the lowest speed then break out early
* or if we 'cannot' reduce the speed as the user might want
* freq_step to be zero */
if (requested_freq[cpu] == policy->min
* freq_step to be zero
*/
if (this_dbs_info->requested_freq == policy->min
|| dbs_tuners_ins.freq_step == 0)
return;
@ -430,13 +403,12 @@ static void dbs_check_cpu(int cpu)
if (unlikely(freq_step == 0))
freq_step = 5;
requested_freq[cpu] -= freq_step;
if (requested_freq[cpu] < policy->min)
requested_freq[cpu] = policy->min;
this_dbs_info->requested_freq -= freq_step;
if (this_dbs_info->requested_freq < policy->min)
this_dbs_info->requested_freq = policy->min;
__cpufreq_driver_target(policy,
requested_freq[cpu],
CPUFREQ_RELATION_H);
__cpufreq_driver_target(policy, this_dbs_info->requested_freq,
CPUFREQ_RELATION_H);
return;
}
}
@ -493,11 +465,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(cpu);
j_dbs_info->prev_cpu_idle_down
= j_dbs_info->prev_cpu_idle_up;
}
this_dbs_info->enable = 1;
this_dbs_info->down_skip = 0;
this_dbs_info->requested_freq = policy->cur;
sysfs_create_group(&policy->kobj, &dbs_attr_group);
dbs_enable++;
/*
@ -507,16 +481,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if (dbs_enable == 1) {
unsigned int latency;
/* policy latency is in nS. Convert it to uS first */
latency = policy->cpuinfo.transition_latency / 1000;
if (latency == 0)
latency = 1;
latency = policy->cpuinfo.transition_latency;
if (latency < 1000)
latency = 1000;
def_sampling_rate = (latency / 1000) *
def_sampling_rate = 10 * latency *
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
dbs_tuners_ins.sampling_rate = def_sampling_rate;
dbs_tuners_ins.ignore_nice = 0;
dbs_tuners_ins.freq_step = 5;
dbs_timer_init();
}

View file

@ -84,6 +84,7 @@ struct dbs_tuners {
static struct dbs_tuners dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
.ignore_nice = 0,
};
static inline unsigned int get_cpu_idle_time(unsigned int cpu)
@ -350,6 +351,9 @@ static void dbs_check_cpu(int cpu)
freq_next = (freq_next * policy->cur) /
(dbs_tuners_ins.up_threshold - 10);
if (freq_next < policy->min)
freq_next = policy->min;
if (freq_next <= ((policy->cur * 95) / 100))
__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
}
@ -395,8 +399,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return -EINVAL;
if (policy->cpuinfo.transition_latency >
(TRANSITION_LATENCY_LIMIT * 1000))
(TRANSITION_LATENCY_LIMIT * 1000)) {
printk(KERN_WARNING "ondemand governor failed to load "
"due to too long transition latency\n");
return -EINVAL;
}
if (this_dbs_info->enable) /* Already enabled */
break;
@ -431,8 +438,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
dbs_tuners_ins.sampling_rate = def_sampling_rate;
dbs_tuners_ins.ignore_nice = 0;
dbs_timer_init();
}

View file

@ -2044,7 +2044,7 @@ static int __init edac_mc_init(void)
*/
clear_pci_parity_errors();
/* Create the MC sysfs entires */
/* Create the MC sysfs entries */
if (edac_sysfs_memctrl_setup()) {
edac_printk(KERN_ERR, EDAC_MC,
"Error initializing sysfs code\n");

View file

@ -484,26 +484,15 @@ static void dcdbas_host_control(void)
static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
void *unused)
{
static unsigned int notify_cnt = 0;
switch (code) {
case SYS_DOWN:
case SYS_HALT:
case SYS_POWER_OFF:
if (host_control_on_shutdown) {
/* firmware is going to perform host control action */
if (++notify_cnt == 2) {
printk(KERN_WARNING
"Please wait for shutdown "
"action to complete...\n");
dcdbas_host_control();
}
/*
* register again and initiate the host control
* action on the second notification to allow
* everyone that registered to be notified
*/
register_reboot_notifier(nb);
printk(KERN_WARNING "Please wait for shutdown "
"action to complete...\n");
dcdbas_host_control();
}
break;
}
@ -514,7 +503,7 @@ static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
static struct notifier_block dcdbas_reboot_nb = {
.notifier_call = dcdbas_reboot_notify,
.next = NULL,
.priority = 0
.priority = INT_MIN
};
static DCDBAS_BIN_ATTR_RW(smi_data);

View file

@ -65,15 +65,6 @@ config SENSORS_PCF8591
This driver can also be built as a module. If so, the module
will be called pcf8591.
config SENSORS_RTC8564
tristate "Epson 8564 RTC chip"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Epson 8564 RTC chip.
This driver can also be built as a module. If so, the module
will be called i2c-rtc8564.
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
@ -126,13 +117,4 @@ config SENSORS_MAX6875
This driver can also be built as a module. If so, the module
will be called max6875.
config RTC_X1205_I2C
tristate "Xicor X1205 RTC chip"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Xicor X1205 RTC chip.
This driver can also be built as a module. If so, the module
will be called x1205.
endmenu

View file

@ -10,10 +10,8 @@ obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_RTC_X1205_I2C) += x1205.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG

View file

@ -1,385 +0,0 @@
/*
* linux/drivers/i2c/chips/rtc8564.c
*
* Copyright (C) 2002-2004 Stefan Eletzhofer
*
* based on linux/drivers/acron/char/pcf8583.c
* 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 version 2 as
* published by the Free Software Foundation.
*
* Driver for system3's EPSON RTC 8564 chip
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/init.h>
#include "rtc8564.h"
#ifdef DEBUG
# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0);
#else
# define _DBG(x, fmt, args...) do { } while(0);
#endif
#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \
"mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \
(rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \
(rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl);
struct rtc8564_data {
struct i2c_client client;
u16 ctrl;
};
static inline u8 _rtc8564_ctrl1(struct i2c_client *client)
{
struct rtc8564_data *data = i2c_get_clientdata(client);
return data->ctrl & 0xff;
}
static inline u8 _rtc8564_ctrl2(struct i2c_client *client)
{
struct rtc8564_data *data = i2c_get_clientdata(client);
return (data->ctrl & 0xff00) >> 8;
}
#define CTRL1(c) _rtc8564_ctrl1(c)
#define CTRL2(c) _rtc8564_ctrl2(c)
static int debug;
module_param(debug, int, S_IRUGO | S_IWUSR);
static struct i2c_driver rtc8564_driver;
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_addr,
.probe = ignore,
.ignore = ignore,
};
static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem);
static int rtc8564_read(struct i2c_client *client, unsigned char adr,
unsigned char *buf, unsigned char len)
{
int ret = -EIO;
unsigned char addr[1] = { adr };
struct i2c_msg msgs[2] = {
{client->addr, 0, 1, addr},
{client->addr, I2C_M_RD, len, buf}
};
_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len);
if (!buf) {
ret = -EINVAL;
goto done;
}
ret = i2c_transfer(client->adapter, msgs, 2);
if (ret == 2) {
ret = 0;
}
done:
return ret;
}
static int rtc8564_write(struct i2c_client *client, unsigned char adr,
unsigned char *data, unsigned char len)
{
int ret = 0;
unsigned char _data[16];
struct i2c_msg wr;
int i;
if (!data || len > 15) {
ret = -EINVAL;
goto done;
}
_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len);
_data[0] = adr;
for (i = 0; i < len; i++) {
_data[i + 1] = data[i];
_DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]);
}
wr.addr = client->addr;
wr.flags = 0;
wr.len = len + 1;
wr.buf = _data;
ret = i2c_transfer(client->adapter, &wr, 1);
if (ret == 1) {
ret = 0;
}
done:
return ret;
}
static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind)
{
int ret;
struct i2c_client *new_client;
struct rtc8564_data *d;
unsigned char data[10];
unsigned char ad[1] = { 0 };
struct i2c_msg ctrl_wr[1] = {
{addr, 0, 2, data}
};
struct i2c_msg ctrl_rd[2] = {
{addr, 0, 1, ad},
{addr, I2C_M_RD, 2, data}
};
d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL);
if (!d) {
ret = -ENOMEM;
goto done;
}
new_client = &d->client;
strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
i2c_set_clientdata(new_client, d);
new_client->addr = addr;
new_client->adapter = adap;
new_client->driver = &rtc8564_driver;
_DBG(1, "client=%p", new_client);
/* init ctrl1 reg */
data[0] = 0;
data[1] = 0;
ret = i2c_transfer(new_client->adapter, ctrl_wr, 1);
if (ret != 1) {
printk(KERN_INFO "rtc8564: cant init ctrl1\n");
ret = -ENODEV;
goto done;
}
/* read back ctrl1 and ctrl2 */
ret = i2c_transfer(new_client->adapter, ctrl_rd, 2);
if (ret != 2) {
printk(KERN_INFO "rtc8564: cant read ctrl\n");
ret = -ENODEV;
goto done;
}
d->ctrl = data[0] | (data[1] << 8);
_DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x",
data[0], data[1]);
ret = i2c_attach_client(new_client);
done:
if (ret) {
kfree(d);
}
return ret;
}
static int rtc8564_probe(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, rtc8564_attach);
}
static int rtc8564_detach(struct i2c_client *client)
{
i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
return 0;
}
static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
{
int ret = -EIO;
unsigned char buf[15];
_DBG(1, "client=%p, dt=%p", client, dt);
if (!dt)
return -EINVAL;
memset(buf, 0, sizeof(buf));
ret = rtc8564_read(client, 0, buf, 15);
if (ret)
return ret;
/* century stored in minute alarm reg */
dt->year = BCD2BIN(buf[RTC8564_REG_YEAR]);
dt->year += 100 * BCD2BIN(buf[RTC8564_REG_AL_MIN] & 0x3f);
dt->mday = BCD2BIN(buf[RTC8564_REG_DAY] & 0x3f);
dt->wday = BCD2BIN(buf[RTC8564_REG_WDAY] & 7);
dt->mon = BCD2BIN(buf[RTC8564_REG_MON_CENT] & 0x1f);
dt->secs = BCD2BIN(buf[RTC8564_REG_SEC] & 0x7f);
dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80;
dt->mins = BCD2BIN(buf[RTC8564_REG_MIN] & 0x7f);
dt->hours = BCD2BIN(buf[RTC8564_REG_HR] & 0x3f);
_DBGRTCTM(2, *dt);
return 0;
}
static int
rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
{
int ret, len = 5;
unsigned char buf[15];
_DBG(1, "client=%p, dt=%p", client, dt);
if (!dt)
return -EINVAL;
_DBGRTCTM(2, *dt);
buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP;
buf[RTC8564_REG_CTRL2] = CTRL2(client);
buf[RTC8564_REG_SEC] = BIN2BCD(dt->secs);
buf[RTC8564_REG_MIN] = BIN2BCD(dt->mins);
buf[RTC8564_REG_HR] = BIN2BCD(dt->hours);
if (datetoo) {
len += 5;
buf[RTC8564_REG_DAY] = BIN2BCD(dt->mday);
buf[RTC8564_REG_WDAY] = BIN2BCD(dt->wday);
buf[RTC8564_REG_MON_CENT] = BIN2BCD(dt->mon) & 0x1f;
/* century stored in minute alarm reg */
buf[RTC8564_REG_YEAR] = BIN2BCD(dt->year % 100);
buf[RTC8564_REG_AL_MIN] = BIN2BCD(dt->year / 100);
}
ret = rtc8564_write(client, 0, buf, len);
if (ret) {
_DBG(1, "error writing data! %d", ret);
}
buf[RTC8564_REG_CTRL1] = CTRL1(client);
ret = rtc8564_write(client, 0, buf, 1);
if (ret) {
_DBG(1, "error writing data! %d", ret);
}
return ret;
}
static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl)
{
struct rtc8564_data *data = i2c_get_clientdata(client);
if (!ctrl)
return -1;
*ctrl = data->ctrl;
return 0;
}
static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl)
{
struct rtc8564_data *data = i2c_get_clientdata(client);
unsigned char buf[2];
if (!ctrl)
return -1;
buf[0] = *ctrl & 0xff;
buf[1] = (*ctrl & 0xff00) >> 8;
data->ctrl = *ctrl;
return rtc8564_write(client, 0, buf, 2);
}
static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem)
{
if (!mem)
return -EINVAL;
return rtc8564_read(client, mem->loc, mem->data, mem->nr);
}
static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem)
{
if (!mem)
return -EINVAL;
return rtc8564_write(client, mem->loc, mem->data, mem->nr);
}
static int
rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
_DBG(1, "cmd=%d", cmd);
switch (cmd) {
case RTC_GETDATETIME:
return rtc8564_get_datetime(client, arg);
case RTC_SETTIME:
return rtc8564_set_datetime(client, arg, 0);
case RTC_SETDATETIME:
return rtc8564_set_datetime(client, arg, 1);
case RTC_GETCTRL:
return rtc8564_get_ctrl(client, arg);
case RTC_SETCTRL:
return rtc8564_set_ctrl(client, arg);
case MEM_READ:
return rtc8564_read_mem(client, arg);
case MEM_WRITE:
return rtc8564_write_mem(client, arg);
default:
return -EINVAL;
}
}
static struct i2c_driver rtc8564_driver = {
.driver = {
.name = "RTC8564",
},
.id = I2C_DRIVERID_RTC8564,
.attach_adapter = rtc8564_probe,
.detach_client = rtc8564_detach,
.command = rtc8564_command
};
static __init int rtc8564_init(void)
{
return i2c_add_driver(&rtc8564_driver);
}
static __exit void rtc8564_exit(void)
{
i2c_del_driver(&rtc8564_driver);
}
MODULE_AUTHOR("Stefan Eletzhofer <[email protected]>");
MODULE_DESCRIPTION("EPSON RTC8564 Driver");
MODULE_LICENSE("GPL");
module_init(rtc8564_init);
module_exit(rtc8564_exit);

View file

@ -1,78 +0,0 @@
/*
* linux/drivers/i2c/chips/rtc8564.h
*
* Copyright (C) 2002-2004 Stefan Eletzhofer
*
* based on linux/drivers/acron/char/pcf8583.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 version 2 as
* published by the Free Software Foundation.
*/
struct rtc_tm {
unsigned char secs;
unsigned char mins;
unsigned char hours;
unsigned char mday;
unsigned char mon;
unsigned short year; /* xxxx 4 digits :) */
unsigned char wday;
unsigned char vl;
};
struct mem {
unsigned int loc;
unsigned int nr;
unsigned char *data;
};
#define RTC_GETDATETIME 0
#define RTC_SETTIME 1
#define RTC_SETDATETIME 2
#define RTC_GETCTRL 3
#define RTC_SETCTRL 4
#define MEM_READ 5
#define MEM_WRITE 6
#define RTC8564_REG_CTRL1 0x0 /* T 0 S 0 | T 0 0 0 */
#define RTC8564_REG_CTRL2 0x1 /* 0 0 0 TI/TP | AF TF AIE TIE */
#define RTC8564_REG_SEC 0x2 /* VL 4 2 1 | 8 4 2 1 */
#define RTC8564_REG_MIN 0x3 /* x 4 2 1 | 8 4 2 1 */
#define RTC8564_REG_HR 0x4 /* x x 2 1 | 8 4 2 1 */
#define RTC8564_REG_DAY 0x5 /* x x 2 1 | 8 4 2 1 */
#define RTC8564_REG_WDAY 0x6 /* x x x x | x 4 2 1 */
#define RTC8564_REG_MON_CENT 0x7 /* C x x 1 | 8 4 2 1 */
#define RTC8564_REG_YEAR 0x8 /* 8 4 2 1 | 8 4 2 1 */
#define RTC8564_REG_AL_MIN 0x9 /* AE 4 2 1 | 8 4 2 1 */
#define RTC8564_REG_AL_HR 0xa /* AE 4 2 1 | 8 4 2 1 */
#define RTC8564_REG_AL_DAY 0xb /* AE x 2 1 | 8 4 2 1 */
#define RTC8564_REG_AL_WDAY 0xc /* AE x x x | x 4 2 1 */
#define RTC8564_REG_CLKOUT 0xd /* FE x x x | x x FD1 FD0 */
#define RTC8564_REG_TCTL 0xe /* TE x x x | x x FD1 FD0 */
#define RTC8564_REG_TIMER 0xf /* 8 bit binary */
/* Control reg */
#define RTC8564_CTRL1_TEST1 (1<<3)
#define RTC8564_CTRL1_STOP (1<<5)
#define RTC8564_CTRL1_TEST2 (1<<7)
#define RTC8564_CTRL2_TIE (1<<0)
#define RTC8564_CTRL2_AIE (1<<1)
#define RTC8564_CTRL2_TF (1<<2)
#define RTC8564_CTRL2_AF (1<<3)
#define RTC8564_CTRL2_TI_TP (1<<4)
/* CLKOUT frequencies */
#define RTC8564_FD_32768HZ (0x0)
#define RTC8564_FD_1024HZ (0x1)
#define RTC8564_FD_32 (0x2)
#define RTC8564_FD_1HZ (0x3)
/* Timer CTRL */
#define RTC8564_TD_4096HZ (0x0)
#define RTC8564_TD_64HZ (0x1)
#define RTC8564_TD_1HZ (0x2)
#define RTC8564_TD_1_60HZ (0x3)
#define I2C_DRIVERID_RTC8564 0xf000

View file

@ -2143,6 +2143,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
req.data = (char *)&capbuf;
req.data_len = sizeof(capbuf);
req.flags |= REQ_QUIET;
stat = cdrom_queue_packet_command(drive, &req);
if (stat == 0) {

View file

@ -433,6 +433,7 @@
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/major.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/errno.h>
@ -2336,7 +2337,7 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
}
if (time_after(jiffies, tape->insert_time))
tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
if (jiffies - tape->avg_time >= HZ) {
if (time_after_eq(jiffies, tape->avg_time + HZ)) {
tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
tape->avg_size = 0;
tape->avg_time = jiffies;
@ -2497,7 +2498,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
} else {
return ide_do_reset(drive);
}
} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
} else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
idetape_postpone_request(drive);
return ide_stopped;

View file

@ -347,10 +347,8 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
break;
case AMD_UDMA_66:
pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
for (i = 24; i >= 0; i -= 8)
if ((u >> i) & 4)
amd_80w |= (1 << (1 - (i >> 4)));
/* no host side cable detection */
amd_80w = 0x03;
break;
}
@ -386,8 +384,6 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
if (amd_clock < 20000 || amd_clock > 50000) {
printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n",
amd_chipset->name, amd_clock);
printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n",
amd_chipset->name);
amd_clock = 33333;
}

View file

@ -41,14 +41,15 @@
static int ide_generic_all; /* Set to claim all devices */
#ifndef MODULE
static int __init ide_generic_all_on(char *unused)
{
ide_generic_all = 1;
printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
return 1;
}
__setup("all-generic-ide", ide_generic_all_on);
#endif
static void __devinit init_hwif_generic (ide_hwif_t *hwif)
{

View file

@ -112,6 +112,7 @@ static const struct {
{ "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 },
{ "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 },
{ "SiS5517", PCI_DEVICE_ID_SI_5517, ATA_16 },
{ "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 },
};
@ -524,6 +525,7 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
case 3: test1 = 0x30|0x03; break;
case 2: test1 = 0x40|0x04; break;
case 1: test1 = 0x60|0x07; break;
case 0: test1 = 0x00; break;
default: break;
}
pci_write_config_byte(dev, drive_pci, test1);

View file

@ -923,7 +923,7 @@ void input_unregister_handler(struct input_handler *handler)
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler = input_table[iminor(inode) >> 5];
struct file_operations *old_fops, *new_fops = NULL;
const struct file_operations *old_fops, *new_fops = NULL;
int err;
/* No load-on-demand here? */

View file

@ -1485,6 +1485,7 @@ static int __init capi_init(void)
{
char *p;
char *compileinfo;
int major_ret;
if ((p = strchr(revision, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
@ -1493,11 +1494,12 @@ static int __init capi_init(void)
} else
strcpy(rev, "1.0");
if (register_chrdev(capi_major, "capi20", &capi_fops)) {
major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
if (major_ret < 0) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
return -EIO;
return major_ret;
}
capi_major = major_ret;
capi_class = class_create(THIS_MODULE, "capi");
if (IS_ERR(capi_class)) {
unregister_chrdev(capi_major, "capi20");

View file

@ -233,7 +233,7 @@ static struct file_operations proc_applstats_ops = {
};
static void
create_seq_entry(char *name, mode_t mode, struct file_operations *f)
create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
{
struct proc_dir_entry *entry;
entry = create_proc_entry(name, mode, NULL);

View file

@ -81,7 +81,7 @@ static struct adb_driver *adb_driver_list[] = {
static struct class *adb_dev_class;
struct adb_driver *adb_controller;
struct notifier_block *adb_client_list = NULL;
BLOCKING_NOTIFIER_HEAD(adb_client_list);
static int adb_got_sleep;
static int adb_inited;
static pid_t adb_probe_task_pid;
@ -355,7 +355,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
/* Stop autopoll */
if (adb_controller->autopoll)
adb_controller->autopoll(0);
ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
ret = blocking_notifier_call_chain(&adb_client_list,
ADB_MSG_POWERDOWN, NULL);
if (ret & NOTIFY_STOP_MASK) {
up(&adb_probe_mutex);
return PBOOK_SLEEP_REFUSE;
@ -392,7 +393,8 @@ do_adb_reset_bus(void)
if (adb_controller->autopoll)
adb_controller->autopoll(0);
nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
nret = blocking_notifier_call_chain(&adb_client_list,
ADB_MSG_PRE_RESET, NULL);
if (nret & NOTIFY_STOP_MASK) {
if (adb_controller->autopoll)
adb_controller->autopoll(autopoll_devs);
@ -427,7 +429,8 @@ do_adb_reset_bus(void)
}
up(&adb_handler_sem);
nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
nret = blocking_notifier_call_chain(&adb_client_list,
ADB_MSG_POST_RESET, NULL);
if (nret & NOTIFY_STOP_MASK)
return -EBUSY;

View file

@ -1214,7 +1214,8 @@ static int __init adbhid_init(void)
adbhid_probe();
notifier_chain_register(&adb_client_list, &adbhid_adb_notifier);
blocking_notifier_chain_register(&adb_client_list,
&adbhid_adb_notifier);
return 0;
}

View file

@ -187,7 +187,7 @@ extern int disable_kernel_backlight;
int __fake_sleep;
int asleep;
struct notifier_block *sleep_notifier_list;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
#ifdef CONFIG_ADB
static int adb_dev_map = 0;

View file

@ -102,7 +102,7 @@ static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
int asleep;
struct notifier_block *sleep_notifier_list;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
static int pmu_probe(void);
static int pmu_init(void);
@ -913,7 +913,8 @@ int powerbook_sleep(void)
struct adb_request sleep_req;
/* Notify device drivers */
ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);
ret = blocking_notifier_call_chain(&sleep_notifier_list,
PBOOK_SLEEP, NULL);
if (ret & NOTIFY_STOP_MASK)
return -EBUSY;
@ -984,7 +985,7 @@ int powerbook_sleep(void)
enable_irq(i);
/* Notify drivers */
notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
/* reenable ADB autopoll */
pmu_adb_autopoll(adb_dev_map);

View file

@ -52,7 +52,7 @@
static LIST_HEAD(wf_controls);
static LIST_HEAD(wf_sensors);
static DEFINE_MUTEX(wf_lock);
static struct notifier_block *wf_client_list;
static BLOCKING_NOTIFIER_HEAD(wf_client_list);
static int wf_client_count;
static unsigned int wf_overtemp;
static unsigned int wf_overtemp_counter;
@ -68,7 +68,7 @@ static struct platform_device wf_platform_device = {
static inline void wf_notify(int event, void *param)
{
notifier_call_chain(&wf_client_list, event, param);
blocking_notifier_call_chain(&wf_client_list, event, param);
}
int wf_critical_overtemp(void)
@ -398,7 +398,7 @@ int wf_register_client(struct notifier_block *nb)
struct wf_sensor *sr;
mutex_lock(&wf_lock);
rc = notifier_chain_register(&wf_client_list, nb);
rc = blocking_notifier_chain_register(&wf_client_list, nb);
if (rc != 0)
goto bail;
wf_client_count++;
@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(wf_register_client);
int wf_unregister_client(struct notifier_block *nb)
{
mutex_lock(&wf_lock);
notifier_chain_unregister(&wf_client_list, nb);
blocking_notifier_chain_unregister(&wf_client_list, nb);
wf_client_count++;
if (wf_client_count == 0)
wf_stop_thread();

View file

@ -127,6 +127,32 @@ config MD_RAID5
If unsure, say Y.
config MD_RAID5_RESHAPE
bool "Support adding drives to a raid-5 array (experimental)"
depends on MD_RAID5 && EXPERIMENTAL
---help---
A RAID-5 set can be expanded by adding extra drives. This
requires "restriping" the array which means (almost) every
block must be written to a different place.
This option allows such restriping to be done while the array
is online. However it is still EXPERIMENTAL code. It should
work, but please be sure that you have backups.
You will need a version of mdadm newer than 2.3.1. During the
early stage of reshape there is a critical section where live data
is being over-written. A crash during this time needs extra care
for recovery. The newer mdadm takes a copy of the data in the
critical section and will restore it, if necessary, after a crash.
The mdadm usage is e.g.
mdadm --grow /dev/md1 --raid-disks=6
to grow '/dev/md1' to having 6 disks.
Note: The array can only be expanded, not contracted.
There should be enough spares already present to make the new
array workable.
config MD_RAID6
tristate "RAID-6 mode"
depends on BLK_DEV_MD

View file

@ -518,6 +518,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
char *ivopts;
unsigned int crypto_flags;
unsigned int key_size;
unsigned long long tmpll;
if (argc != 5) {
ti->error = PFX "Not enough arguments";
@ -633,15 +634,17 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad5;
}
if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
if (sscanf(argv[2], "%llu", &tmpll) != 1) {
ti->error = PFX "Invalid iv_offset sector";
goto bad5;
}
cc->iv_offset = tmpll;
if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) {
if (sscanf(argv[4], "%llu", &tmpll) != 1) {
ti->error = PFX "Invalid device sector";
goto bad5;
}
cc->start = tmpll;
if (dm_get_device(ti, argv[3], cc->start, ti->len,
dm_table_get_mode(ti->table), &cc->dev)) {
@ -885,8 +888,8 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
result[sz++] = '-';
}
DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT,
cc->iv_offset, cc->dev->name, cc->start);
DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
cc->dev->name, (unsigned long long)cc->start);
break;
}
return 0;

View file

@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/dm-ioctl.h>
#include <linux/hdreg.h>
#include <asm/uaccess.h>
@ -244,9 +245,9 @@ static void __hash_remove(struct hash_cell *hc)
dm_table_put(table);
}
dm_put(hc->md);
if (hc->new_map)
dm_table_put(hc->new_map);
dm_put(hc->md);
free_cell(hc);
}
@ -600,12 +601,22 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
*/
static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
{
struct mapped_device *md;
void *mdptr = NULL;
if (*param->uuid)
return __get_uuid_cell(param->uuid);
else if (*param->name)
if (*param->name)
return __get_name_cell(param->name);
else
return dm_get_mdptr(huge_decode_dev(param->dev));
md = dm_get_md(huge_decode_dev(param->dev));
if (md) {
mdptr = dm_get_mdptr(md);
dm_put(md);
}
return mdptr;
}
static struct mapped_device *find_device(struct dm_ioctl *param)
@ -690,6 +701,54 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
return dm_hash_rename(param->name, new_name);
}
static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
{
int r = -EINVAL, x;
struct mapped_device *md;
struct hd_geometry geometry;
unsigned long indata[4];
char *geostr = (char *) param + param->data_start;
md = find_device(param);
if (!md)
return -ENXIO;
if (geostr < (char *) (param + 1) ||
invalid_str(geostr, (void *) param + param_size)) {
DMWARN("Invalid geometry supplied.");
goto out;
}
x = sscanf(geostr, "%lu %lu %lu %lu", indata,
indata + 1, indata + 2, indata + 3);
if (x != 4) {
DMWARN("Unable to interpret geometry settings.");
goto out;
}
if (indata[0] > 65535 || indata[1] > 255 ||
indata[2] > 255 || indata[3] > ULONG_MAX) {
DMWARN("Geometry exceeds range limits.");
goto out;
}
geometry.cylinders = indata[0];
geometry.heads = indata[1];
geometry.sectors = indata[2];
geometry.start = indata[3];
r = dm_set_geometry(md, &geometry);
if (!r)
r = __dev_status(md, param);
param->data_size = 0;
out:
dm_put(md);
return r;
}
static int do_suspend(struct dm_ioctl *param)
{
int r = 0;
@ -975,33 +1034,43 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
int r;
struct hash_cell *hc;
struct dm_table *t;
struct mapped_device *md;
r = dm_table_create(&t, get_mode(param), param->target_count);
md = find_device(param);
if (!md)
return -ENXIO;
r = dm_table_create(&t, get_mode(param), param->target_count, md);
if (r)
return r;
goto out;
r = populate_table(t, param, param_size);
if (r) {
dm_table_put(t);
return r;
goto out;
}
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
if (!hc) {
DMWARN("device doesn't appear to be in the dev hash table.");
up_write(&_hash_lock);
hc = dm_get_mdptr(md);
if (!hc || hc->md != md) {
DMWARN("device has been removed from the dev hash table.");
dm_table_put(t);
return -ENXIO;
up_write(&_hash_lock);
r = -ENXIO;
goto out;
}
if (hc->new_map)
dm_table_put(hc->new_map);
hc->new_map = t;
param->flags |= DM_INACTIVE_PRESENT_FLAG;
r = __dev_status(hc->md, param);
up_write(&_hash_lock);
param->flags |= DM_INACTIVE_PRESENT_FLAG;
r = __dev_status(md, param);
out:
dm_put(md);
return r;
}
@ -1214,7 +1283,8 @@ static ioctl_fn lookup_ioctl(unsigned int cmd)
{DM_LIST_VERSIONS_CMD, list_versions},
{DM_TARGET_MSG_CMD, target_message}
{DM_TARGET_MSG_CMD, target_message},
{DM_DEV_SET_GEOMETRY_CMD, dev_set_geometry}
};
return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;

View file

@ -26,6 +26,7 @@ struct linear_c {
static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct linear_c *lc;
unsigned long long tmp;
if (argc != 2) {
ti->error = "dm-linear: Invalid argument count";
@ -38,10 +39,11 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return -ENOMEM;
}
if (sscanf(argv[1], SECTOR_FORMAT, &lc->start) != 1) {
if (sscanf(argv[1], "%llu", &tmp) != 1) {
ti->error = "dm-linear: Invalid device sector";
goto bad;
}
lc->start = tmp;
if (dm_get_device(ti, argv[0], lc->start, ti->len,
dm_table_get_mode(ti->table), &lc->dev)) {
@ -87,8 +89,8 @@ static int linear_status(struct dm_target *ti, status_type_t type,
break;
case STATUSTYPE_TABLE:
snprintf(result, maxlen, "%s " SECTOR_FORMAT, lc->dev->name,
lc->start);
snprintf(result, maxlen, "%s %llu", lc->dev->name,
(unsigned long long)lc->start);
break;
}
return 0;

View file

@ -402,9 +402,21 @@ static void rh_dec(struct region_hash *rh, region_t region)
spin_lock_irqsave(&rh->region_lock, flags);
if (atomic_dec_and_test(&reg->pending)) {
/*
* There is no pending I/O for this region.
* We can move the region to corresponding list for next action.
* At this point, the region is not yet connected to any list.
*
* If the state is RH_NOSYNC, the region should be kept off
* from clean list.
* The hash entry for RH_NOSYNC will remain in memory
* until the region is recovered or the map is reloaded.
*/
/* do nothing for RH_NOSYNC */
if (reg->state == RH_RECOVERING) {
list_add_tail(&reg->list, &rh->quiesced_regions);
} else {
} else if (reg->state == RH_DIRTY) {
reg->state = RH_CLEAN;
list_add(&reg->list, &rh->clean_regions);
}
@ -922,9 +934,9 @@ static inline int _check_region_size(struct dm_target *ti, uint32_t size)
static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
unsigned int mirror, char **argv)
{
sector_t offset;
unsigned long long offset;
if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) {
if (sscanf(argv[1], "%llu", &offset) != 1) {
ti->error = "dm-mirror: Invalid offset";
return -EINVAL;
}
@ -1191,16 +1203,17 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
for (m = 0; m < ms->nr_mirrors; m++)
DMEMIT("%s ", ms->mirror[m].dev->name);
DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT,
ms->rh.log->type->get_sync_count(ms->rh.log),
ms->nr_regions);
DMEMIT("%llu/%llu",
(unsigned long long)ms->rh.log->type->
get_sync_count(ms->rh.log),
(unsigned long long)ms->nr_regions);
break;
case STATUSTYPE_TABLE:
DMEMIT("%d ", ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++)
DMEMIT("%s " SECTOR_FORMAT " ",
ms->mirror[m].dev->name, ms->mirror[m].offset);
DMEMIT("%s %llu ", ms->mirror[m].dev->name,
(unsigned long long)ms->mirror[m].offset);
}
return 0;

View file

@ -49,11 +49,26 @@ struct pending_exception {
struct bio_list snapshot_bios;
/*
* Other pending_exceptions that are processing this
* chunk. When this list is empty, we know we can
* complete the origins.
* Short-term queue of pending exceptions prior to submission.
*/
struct list_head siblings;
struct list_head list;
/*
* The primary pending_exception is the one that holds
* the sibling_count and the list of origin_bios for a
* group of pending_exceptions. It is always last to get freed.
* These fields get set up when writing to the origin.
*/
struct pending_exception *primary_pe;
/*
* Number of pending_exceptions processing this chunk.
* When this drops to zero we must complete the origin bios.
* If incrementing or decrementing this, hold pe->snap->lock for
* the sibling concerned and not pe->primary_pe->snap->lock unless
* they are the same.
*/
atomic_t sibling_count;
/* Pointer back to snapshot context */
struct dm_snapshot *snap;
@ -377,6 +392,8 @@ static void read_snapshot_metadata(struct dm_snapshot *s)
down_write(&s->lock);
s->valid = 0;
up_write(&s->lock);
dm_table_event(s->table);
}
}
@ -542,8 +559,12 @@ static void snapshot_dtr(struct dm_target *ti)
{
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
/* Prevent further origin writes from using this snapshot. */
/* After this returns there can be no new kcopyd jobs. */
unregister_snapshot(s);
kcopyd_client_destroy(s->kcopyd_client);
exit_exception_table(&s->pending, pending_cache);
exit_exception_table(&s->complete, exception_cache);
@ -552,7 +573,7 @@ static void snapshot_dtr(struct dm_target *ti)
dm_put_device(ti, s->origin);
dm_put_device(ti, s->cow);
kcopyd_client_destroy(s->kcopyd_client);
kfree(s);
}
@ -586,78 +607,117 @@ static void error_bios(struct bio *bio)
}
}
static inline void error_snapshot_bios(struct pending_exception *pe)
{
error_bios(bio_list_get(&pe->snapshot_bios));
}
static struct bio *__flush_bios(struct pending_exception *pe)
{
struct pending_exception *sibling;
if (list_empty(&pe->siblings))
return bio_list_get(&pe->origin_bios);
sibling = list_entry(pe->siblings.next,
struct pending_exception, siblings);
list_del(&pe->siblings);
/* This is fine as long as kcopyd is single-threaded. If kcopyd
* becomes multi-threaded, we'll need some locking here.
/*
* If this pe is involved in a write to the origin and
* it is the last sibling to complete then release
* the bios for the original write to the origin.
*/
bio_list_merge(&sibling->origin_bios, &pe->origin_bios);
if (pe->primary_pe &&
atomic_dec_and_test(&pe->primary_pe->sibling_count))
return bio_list_get(&pe->primary_pe->origin_bios);
return NULL;
}
static void __invalidate_snapshot(struct dm_snapshot *s,
struct pending_exception *pe, int err)
{
if (!s->valid)
return;
if (err == -EIO)
DMERR("Invalidating snapshot: Error reading/writing.");
else if (err == -ENOMEM)
DMERR("Invalidating snapshot: Unable to allocate exception.");
if (pe)
remove_exception(&pe->e);
if (s->store.drop_snapshot)
s->store.drop_snapshot(&s->store);
s->valid = 0;
dm_table_event(s->table);
}
static void pending_complete(struct pending_exception *pe, int success)
{
struct exception *e;
struct pending_exception *primary_pe;
struct dm_snapshot *s = pe->snap;
struct bio *flush = NULL;
if (success) {
e = alloc_exception();
if (!e) {
DMWARN("Unable to allocate exception.");
down_write(&s->lock);
s->store.drop_snapshot(&s->store);
s->valid = 0;
flush = __flush_bios(pe);
up_write(&s->lock);
error_bios(bio_list_get(&pe->snapshot_bios));
goto out;
}
*e = pe->e;
/*
* Add a proper exception, and remove the
* in-flight exception from the list.
*/
down_write(&s->lock);
insert_exception(&s->complete, e);
remove_exception(&pe->e);
flush = __flush_bios(pe);
/* Submit any pending write bios */
up_write(&s->lock);
flush_bios(bio_list_get(&pe->snapshot_bios));
} else {
if (!success) {
/* Read/write error - snapshot is unusable */
down_write(&s->lock);
if (s->valid)
DMERR("Error reading/writing snapshot");
s->store.drop_snapshot(&s->store);
s->valid = 0;
remove_exception(&pe->e);
__invalidate_snapshot(s, pe, -EIO);
flush = __flush_bios(pe);
up_write(&s->lock);
error_bios(bio_list_get(&pe->snapshot_bios));
dm_table_event(s->table);
error_snapshot_bios(pe);
goto out;
}
e = alloc_exception();
if (!e) {
down_write(&s->lock);
__invalidate_snapshot(s, pe, -ENOMEM);
flush = __flush_bios(pe);
up_write(&s->lock);
error_snapshot_bios(pe);
goto out;
}
*e = pe->e;
/*
* Add a proper exception, and remove the
* in-flight exception from the list.
*/
down_write(&s->lock);
if (!s->valid) {
flush = __flush_bios(pe);
up_write(&s->lock);
free_exception(e);
error_snapshot_bios(pe);
goto out;
}
insert_exception(&s->complete, e);
remove_exception(&pe->e);
flush = __flush_bios(pe);
up_write(&s->lock);
/* Submit any pending write bios */
flush_bios(bio_list_get(&pe->snapshot_bios));
out:
free_pending_exception(pe);
primary_pe = pe->primary_pe;
/*
* Free the pe if it's not linked to an origin write or if
* it's not itself a primary pe.
*/
if (!primary_pe || primary_pe != pe)
free_pending_exception(pe);
/*
* Free the primary pe if nothing references it.
*/
if (primary_pe && !atomic_read(&primary_pe->sibling_count))
free_pending_exception(primary_pe);
if (flush)
flush_bios(flush);
@ -734,38 +794,45 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
if (e) {
/* cast the exception to a pending exception */
pe = container_of(e, struct pending_exception, e);
} else {
/*
* Create a new pending exception, we don't want
* to hold the lock while we do this.
*/
up_write(&s->lock);
pe = alloc_pending_exception();
down_write(&s->lock);
e = lookup_exception(&s->pending, chunk);
if (e) {
free_pending_exception(pe);
pe = container_of(e, struct pending_exception, e);
} else {
pe->e.old_chunk = chunk;
bio_list_init(&pe->origin_bios);
bio_list_init(&pe->snapshot_bios);
INIT_LIST_HEAD(&pe->siblings);
pe->snap = s;
pe->started = 0;
if (s->store.prepare_exception(&s->store, &pe->e)) {
free_pending_exception(pe);
s->valid = 0;
return NULL;
}
insert_exception(&s->pending, &pe->e);
}
goto out;
}
/*
* Create a new pending exception, we don't want
* to hold the lock while we do this.
*/
up_write(&s->lock);
pe = alloc_pending_exception();
down_write(&s->lock);
if (!s->valid) {
free_pending_exception(pe);
return NULL;
}
e = lookup_exception(&s->pending, chunk);
if (e) {
free_pending_exception(pe);
pe = container_of(e, struct pending_exception, e);
goto out;
}
pe->e.old_chunk = chunk;
bio_list_init(&pe->origin_bios);
bio_list_init(&pe->snapshot_bios);
pe->primary_pe = NULL;
atomic_set(&pe->sibling_count, 1);
pe->snap = s;
pe->started = 0;
if (s->store.prepare_exception(&s->store, &pe->e)) {
free_pending_exception(pe);
return NULL;
}
insert_exception(&s->pending, &pe->e);
out:
return pe;
}
@ -782,13 +849,15 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
{
struct exception *e;
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
int copy_needed = 0;
int r = 1;
chunk_t chunk;
struct pending_exception *pe;
struct pending_exception *pe = NULL;
chunk = sector_to_chunk(s, bio->bi_sector);
/* Full snapshots are not usable */
/* To get here the table must be live so s->active is always set. */
if (!s->valid)
return -EIO;
@ -806,36 +875,41 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
* to copy an exception */
down_write(&s->lock);
if (!s->valid) {
r = -EIO;
goto out_unlock;
}
/* If the block is already remapped - use that, else remap it */
e = lookup_exception(&s->complete, chunk);
if (e) {
remap_exception(s, e, bio);
up_write(&s->lock);
} else {
pe = __find_pending_exception(s, bio);
if (!pe) {
if (s->store.drop_snapshot)
s->store.drop_snapshot(&s->store);
s->valid = 0;
r = -EIO;
up_write(&s->lock);
} else {
remap_exception(s, &pe->e, bio);
bio_list_add(&pe->snapshot_bios, bio);
if (!pe->started) {
/* this is protected by snap->lock */
pe->started = 1;
up_write(&s->lock);
start_copy(pe);
} else
up_write(&s->lock);
r = 0;
}
goto out_unlock;
}
pe = __find_pending_exception(s, bio);
if (!pe) {
__invalidate_snapshot(s, pe, -ENOMEM);
r = -EIO;
goto out_unlock;
}
remap_exception(s, &pe->e, bio);
bio_list_add(&pe->snapshot_bios, bio);
if (!pe->started) {
/* this is protected by snap->lock */
pe->started = 1;
copy_needed = 1;
}
r = 0;
out_unlock:
up_write(&s->lock);
if (copy_needed)
start_copy(pe);
} else {
/*
* FIXME: this read path scares me because we
@ -847,6 +921,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
/* Do reads */
down_read(&s->lock);
if (!s->valid) {
up_read(&s->lock);
return -EIO;
}
/* See if it it has been remapped */
e = lookup_exception(&s->complete, chunk);
if (e)
@ -884,9 +963,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
snap->store.fraction_full(&snap->store,
&numerator,
&denominator);
snprintf(result, maxlen,
SECTOR_FORMAT "/" SECTOR_FORMAT,
numerator, denominator);
snprintf(result, maxlen, "%llu/%llu",
(unsigned long long)numerator,
(unsigned long long)denominator);
}
else
snprintf(result, maxlen, "Unknown");
@ -899,9 +978,10 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
* to make private copies if the output is to
* make sense.
*/
snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT,
snprintf(result, maxlen, "%s %s %c %llu",
snap->origin->name, snap->cow->name,
snap->type, snap->chunk_size);
snap->type,
(unsigned long long)snap->chunk_size);
break;
}
@ -911,40 +991,27 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
/*-----------------------------------------------------------------
* Origin methods
*---------------------------------------------------------------*/
static void list_merge(struct list_head *l1, struct list_head *l2)
{
struct list_head *l1_n, *l2_p;
l1_n = l1->next;
l2_p = l2->prev;
l1->next = l2;
l2->prev = l1;
l2_p->next = l1_n;
l1_n->prev = l2_p;
}
static int __origin_write(struct list_head *snapshots, struct bio *bio)
{
int r = 1, first = 1;
int r = 1, first = 0;
struct dm_snapshot *snap;
struct exception *e;
struct pending_exception *pe, *last = NULL;
struct pending_exception *pe, *next_pe, *primary_pe = NULL;
chunk_t chunk;
LIST_HEAD(pe_queue);
/* Do all the snapshots on this origin */
list_for_each_entry (snap, snapshots, list) {
down_write(&snap->lock);
/* Only deal with valid and active snapshots */
if (!snap->valid || !snap->active)
continue;
goto next_snapshot;
/* Nothing to do if writing beyond end of snapshot */
if (bio->bi_sector >= dm_table_get_size(snap->table))
continue;
down_write(&snap->lock);
goto next_snapshot;
/*
* Remember, different snapshots can have
@ -956,49 +1023,75 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
* Check exception table to see if block
* is already remapped in this snapshot
* and trigger an exception if not.
*
* sibling_count is initialised to 1 so pending_complete()
* won't destroy the primary_pe while we're inside this loop.
*/
e = lookup_exception(&snap->complete, chunk);
if (!e) {
pe = __find_pending_exception(snap, bio);
if (!pe) {
snap->store.drop_snapshot(&snap->store);
snap->valid = 0;
if (e)
goto next_snapshot;
} else {
if (last)
list_merge(&pe->siblings,
&last->siblings);
last = pe;
r = 0;
}
pe = __find_pending_exception(snap, bio);
if (!pe) {
__invalidate_snapshot(snap, pe, ENOMEM);
goto next_snapshot;
}
if (!primary_pe) {
/*
* Either every pe here has same
* primary_pe or none has one yet.
*/
if (pe->primary_pe)
primary_pe = pe->primary_pe;
else {
primary_pe = pe;
first = 1;
}
bio_list_add(&primary_pe->origin_bios, bio);
r = 0;
}
if (!pe->primary_pe) {
atomic_inc(&primary_pe->sibling_count);
pe->primary_pe = primary_pe;
}
if (!pe->started) {
pe->started = 1;
list_add_tail(&pe->list, &pe_queue);
}
next_snapshot:
up_write(&snap->lock);
}
if (!primary_pe)
goto out;
/*
* If this is the first time we're processing this chunk and
* sibling_count is now 1 it means all the pending exceptions
* got completed while we were in the loop above, so it falls to
* us here to remove the primary_pe and submit any origin_bios.
*/
if (first && atomic_dec_and_test(&primary_pe->sibling_count)) {
flush_bios(bio_list_get(&primary_pe->origin_bios));
free_pending_exception(primary_pe);
/* If we got here, pe_queue is necessarily empty. */
goto out;
}
/*
* Now that we have a complete pe list we can start the copying.
*/
if (last) {
pe = last;
do {
down_write(&pe->snap->lock);
if (first)
bio_list_add(&pe->origin_bios, bio);
if (!pe->started) {
pe->started = 1;
up_write(&pe->snap->lock);
start_copy(pe);
} else
up_write(&pe->snap->lock);
first = 0;
pe = list_entry(pe->siblings.next,
struct pending_exception, siblings);
} while (pe != last);
}
list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
start_copy(pe);
out:
return r;
}

View file

@ -49,9 +49,9 @@ static inline struct stripe_c *alloc_context(unsigned int stripes)
static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
unsigned int stripe, char **argv)
{
sector_t start;
unsigned long long start;
if (sscanf(argv[1], SECTOR_FORMAT, &start) != 1)
if (sscanf(argv[1], "%llu", &start) != 1)
return -EINVAL;
if (dm_get_device(ti, argv[0], start, sc->stripe_width,
@ -103,7 +103,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return -EINVAL;
}
if (((uint32_t)ti->len) & (chunk_size - 1)) {
if (ti->len & (chunk_size - 1)) {
ti->error = "dm-stripe: Target length not divisible by "
"chunk size";
return -EINVAL;
@ -201,10 +201,11 @@ static int stripe_status(struct dm_target *ti,
break;
case STATUSTYPE_TABLE:
DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1);
DMEMIT("%d %llu", sc->stripes,
(unsigned long long)sc->chunk_mask + 1);
for (i = 0; i < sc->stripes; i++)
DMEMIT(" %s " SECTOR_FORMAT, sc->stripe[i].dev->name,
sc->stripe[i].physical_start);
DMEMIT(" %s %llu", sc->stripe[i].dev->name,
(unsigned long long)sc->stripe[i].physical_start);
break;
}
return 0;

View file

@ -14,6 +14,7 @@
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <asm/atomic.h>
#define MAX_DEPTH 16
@ -22,6 +23,7 @@
#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
struct dm_table {
struct mapped_device *md;
atomic_t holders;
/* btree table */
@ -97,6 +99,8 @@ static void combine_restrictions_low(struct io_restrictions *lhs,
lhs->seg_boundary_mask =
min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask);
lhs->no_cluster |= rhs->no_cluster;
}
/*
@ -204,7 +208,8 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
return 0;
}
int dm_table_create(struct dm_table **result, int mode, unsigned num_targets)
int dm_table_create(struct dm_table **result, int mode,
unsigned num_targets, struct mapped_device *md)
{
struct dm_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
@ -227,6 +232,7 @@ int dm_table_create(struct dm_table **result, int mode, unsigned num_targets)
}
t->mode = mode;
t->md = md;
*result = t;
return 0;
}
@ -345,7 +351,7 @@ static struct dm_dev *find_device(struct list_head *l, dev_t dev)
/*
* Open a device so we can use it as a map destination.
*/
static int open_dev(struct dm_dev *d, dev_t dev)
static int open_dev(struct dm_dev *d, dev_t dev, struct mapped_device *md)
{
static char *_claim_ptr = "I belong to device-mapper";
struct block_device *bdev;
@ -357,7 +363,7 @@ static int open_dev(struct dm_dev *d, dev_t dev)
bdev = open_by_devnum(dev, d->mode);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
r = bd_claim(bdev, _claim_ptr);
r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
if (r)
blkdev_put(bdev);
else
@ -368,12 +374,12 @@ static int open_dev(struct dm_dev *d, dev_t dev)
/*
* Close a device that we've been using.
*/
static void close_dev(struct dm_dev *d)
static void close_dev(struct dm_dev *d, struct mapped_device *md)
{
if (!d->bdev)
return;
bd_release(d->bdev);
bd_release_from_disk(d->bdev, dm_disk(md));
blkdev_put(d->bdev);
d->bdev = NULL;
}
@ -394,7 +400,7 @@ static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
* careful to leave things as they were if we fail to reopen the
* device.
*/
static int upgrade_mode(struct dm_dev *dd, int new_mode)
static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md)
{
int r;
struct dm_dev dd_copy;
@ -404,9 +410,9 @@ static int upgrade_mode(struct dm_dev *dd, int new_mode)
dd->mode |= new_mode;
dd->bdev = NULL;
r = open_dev(dd, dev);
r = open_dev(dd, dev, md);
if (!r)
close_dev(&dd_copy);
close_dev(&dd_copy, md);
else
*dd = dd_copy;
@ -448,7 +454,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
dd->mode = mode;
dd->bdev = NULL;
if ((r = open_dev(dd, dev))) {
if ((r = open_dev(dd, dev, t->md))) {
kfree(dd);
return r;
}
@ -459,7 +465,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
list_add(&dd->list, &t->devices);
} else if (dd->mode != (mode | dd->mode)) {
r = upgrade_mode(dd, mode);
r = upgrade_mode(dd, mode, t->md);
if (r)
return r;
}
@ -523,6 +529,8 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
rs->seg_boundary_mask =
min_not_zero(rs->seg_boundary_mask,
q->seg_boundary_mask);
rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
}
return r;
@ -534,7 +542,7 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
{
if (atomic_dec_and_test(&dd->count)) {
close_dev(dd);
close_dev(dd, ti->table->md);
list_del(&dd->list);
kfree(dd);
}
@ -763,14 +771,14 @@ int dm_table_complete(struct dm_table *t)
return r;
}
static DECLARE_MUTEX(_event_lock);
static DEFINE_MUTEX(_event_lock);
void dm_table_event_callback(struct dm_table *t,
void (*fn)(void *), void *context)
{
down(&_event_lock);
mutex_lock(&_event_lock);
t->event_fn = fn;
t->event_context = context;
up(&_event_lock);
mutex_unlock(&_event_lock);
}
void dm_table_event(struct dm_table *t)
@ -781,10 +789,10 @@ void dm_table_event(struct dm_table *t)
*/
BUG_ON(in_interrupt());
down(&_event_lock);
mutex_lock(&_event_lock);
if (t->event_fn)
t->event_fn(t->event_context);
up(&_event_lock);
mutex_unlock(&_event_lock);
}
sector_t dm_table_get_size(struct dm_table *t)
@ -832,6 +840,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q)
q->hardsect_size = t->limits.hardsect_size;
q->max_segment_size = t->limits.max_segment_size;
q->seg_boundary_mask = t->limits.seg_boundary_mask;
if (t->limits.no_cluster)
q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER);
else
q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER);
}
unsigned int dm_table_get_num_targets(struct dm_table *t)
@ -943,12 +956,20 @@ int dm_table_flush_all(struct dm_table *t)
return ret;
}
struct mapped_device *dm_table_get_md(struct dm_table *t)
{
dm_get(t->md);
return t->md;
}
EXPORT_SYMBOL(dm_vcalloc);
EXPORT_SYMBOL(dm_get_device);
EXPORT_SYMBOL(dm_put_device);
EXPORT_SYMBOL(dm_table_event);
EXPORT_SYMBOL(dm_table_get_size);
EXPORT_SYMBOL(dm_table_get_mode);
EXPORT_SYMBOL(dm_table_get_md);
EXPORT_SYMBOL(dm_table_put);
EXPORT_SYMBOL(dm_table_get);
EXPORT_SYMBOL(dm_table_unplug_all);

View file

@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/moduleparam.h>
#include <linux/blkpg.h>
#include <linux/bio.h>
@ -17,6 +18,7 @@
#include <linux/mempool.h>
#include <linux/slab.h>
#include <linux/idr.h>
#include <linux/hdreg.h>
#include <linux/blktrace_api.h>
static const char *_name = DM_NAME;
@ -69,6 +71,7 @@ struct mapped_device {
request_queue_t *queue;
struct gendisk *disk;
char name[16];
void *interface_ptr;
@ -101,6 +104,9 @@ struct mapped_device {
*/
struct super_block *frozen_sb;
struct block_device *suspended_bdev;
/* forced geometry settings */
struct hd_geometry geometry;
};
#define MIN_IOS 256
@ -226,6 +232,13 @@ static int dm_blk_close(struct inode *inode, struct file *file)
return 0;
}
static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
struct mapped_device *md = bdev->bd_disk->private_data;
return dm_get_geometry(md, geo);
}
static inline struct dm_io *alloc_io(struct mapped_device *md)
{
return mempool_alloc(md->io_pool, GFP_NOIO);
@ -312,6 +325,33 @@ struct dm_table *dm_get_table(struct mapped_device *md)
return t;
}
/*
* Get the geometry associated with a dm device
*/
int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo)
{
*geo = md->geometry;
return 0;
}
/*
* Set the geometry of a device.
*/
int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo)
{
sector_t sz = (sector_t)geo->cylinders * geo->heads * geo->sectors;
if (geo->start > sz) {
DMWARN("Start sector is beyond the geometry limits.");
return -EINVAL;
}
md->geometry = *geo;
return 0;
}
/*-----------------------------------------------------------------
* CRUD START:
* A more elegant soln is in the works that uses the queue
@ -704,14 +744,14 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
/*-----------------------------------------------------------------
* An IDR is used to keep track of allocated minor numbers.
*---------------------------------------------------------------*/
static DECLARE_MUTEX(_minor_lock);
static DEFINE_MUTEX(_minor_lock);
static DEFINE_IDR(_minor_idr);
static void free_minor(unsigned int minor)
{
down(&_minor_lock);
mutex_lock(&_minor_lock);
idr_remove(&_minor_idr, minor);
up(&_minor_lock);
mutex_unlock(&_minor_lock);
}
/*
@ -724,7 +764,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor)
if (minor >= (1 << MINORBITS))
return -EINVAL;
down(&_minor_lock);
mutex_lock(&_minor_lock);
if (idr_find(&_minor_idr, minor)) {
r = -EBUSY;
@ -749,7 +789,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor)
}
out:
up(&_minor_lock);
mutex_unlock(&_minor_lock);
return r;
}
@ -758,7 +798,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor)
int r;
unsigned int m;
down(&_minor_lock);
mutex_lock(&_minor_lock);
r = idr_pre_get(&_minor_idr, GFP_KERNEL);
if (!r) {
@ -780,7 +820,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor)
*minor = m;
out:
up(&_minor_lock);
mutex_unlock(&_minor_lock);
return r;
}
@ -842,6 +882,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
md->disk->private_data = md;
sprintf(md->disk->disk_name, "dm-%d", minor);
add_disk(md->disk);
format_dev_t(md->name, MKDEV(_major, minor));
atomic_set(&md->pending, 0);
init_waitqueue_head(&md->wait);
@ -904,6 +945,13 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
sector_t size;
size = dm_table_get_size(t);
/*
* Wipe any geometry if the size of the table changed.
*/
if (size != get_capacity(md->disk))
memset(&md->geometry, 0, sizeof(md->geometry));
__set_size(md, size);
if (size == 0)
return 0;
@ -967,13 +1015,13 @@ static struct mapped_device *dm_find_md(dev_t dev)
if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
return NULL;
down(&_minor_lock);
mutex_lock(&_minor_lock);
md = idr_find(&_minor_idr, minor);
if (!md || (dm_disk(md)->first_minor != minor))
md = NULL;
up(&_minor_lock);
mutex_unlock(&_minor_lock);
return md;
}
@ -988,15 +1036,9 @@ struct mapped_device *dm_get_md(dev_t dev)
return md;
}
void *dm_get_mdptr(dev_t dev)
void *dm_get_mdptr(struct mapped_device *md)
{
struct mapped_device *md;
void *mdptr = NULL;
md = dm_find_md(dev);
if (md)
mdptr = md->interface_ptr;
return mdptr;
return md->interface_ptr;
}
void dm_set_mdptr(struct mapped_device *md, void *ptr)
@ -1011,18 +1053,18 @@ void dm_get(struct mapped_device *md)
void dm_put(struct mapped_device *md)
{
struct dm_table *map = dm_get_table(md);
struct dm_table *map;
if (atomic_dec_and_test(&md->holders)) {
map = dm_get_table(md);
if (!dm_suspended(md)) {
dm_table_presuspend_targets(map);
dm_table_postsuspend_targets(map);
}
__unbind(md);
dm_table_put(map);
free_dev(md);
}
dm_table_put(map);
}
/*
@ -1107,6 +1149,7 @@ int dm_suspend(struct mapped_device *md, int do_lockfs)
{
struct dm_table *map = NULL;
DECLARE_WAITQUEUE(wait, current);
struct bio *def;
int r = -EINVAL;
down(&md->suspend_lock);
@ -1166,9 +1209,11 @@ int dm_suspend(struct mapped_device *md, int do_lockfs)
/* were we interrupted ? */
r = -EINTR;
if (atomic_read(&md->pending)) {
clear_bit(DMF_BLOCK_IO, &md->flags);
def = bio_list_get(&md->deferred);
__flush_deferred_io(md, def);
up_write(&md->io_lock);
unlock_fs(md);
clear_bit(DMF_BLOCK_IO, &md->flags);
goto out;
}
up_write(&md->io_lock);
@ -1262,6 +1307,7 @@ int dm_suspended(struct mapped_device *md)
static struct block_device_operations dm_blk_dops = {
.open = dm_blk_open,
.release = dm_blk_close,
.getgeo = dm_blk_getgeo,
.owner = THIS_MODULE
};

View file

@ -14,6 +14,7 @@
#include <linux/device-mapper.h>
#include <linux/list.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#define DM_NAME "device-mapper"
#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
@ -23,16 +24,6 @@
#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
0 : scnprintf(result + sz, maxlen - sz, x))
/*
* FIXME: I think this should be with the definition of sector_t
* in types.h.
*/
#ifdef CONFIG_LBD
#define SECTOR_FORMAT "%llu"
#else
#define SECTOR_FORMAT "%lu"
#endif
#define SECTOR_SHIFT 9
/*
@ -57,7 +48,7 @@ struct mapped_device;
int dm_create(struct mapped_device **md);
int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
void dm_set_mdptr(struct mapped_device *md, void *ptr);
void *dm_get_mdptr(dev_t dev);
void *dm_get_mdptr(struct mapped_device *md);
struct mapped_device *dm_get_md(dev_t dev);
/*
@ -95,11 +86,18 @@ int dm_wait_event(struct mapped_device *md, int event_nr);
struct gendisk *dm_disk(struct mapped_device *md);
int dm_suspended(struct mapped_device *md);
/*
* Geometry functions.
*/
int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
/*-----------------------------------------------------------------
* Functions for manipulating a table. Tables are also reference
* counted.
*---------------------------------------------------------------*/
int dm_table_create(struct dm_table **result, int mode, unsigned num_targets);
int dm_table_create(struct dm_table **result, int mode,
unsigned num_targets, struct mapped_device *md);
void dm_table_get(struct dm_table *t);
void dm_table_put(struct dm_table *t);
@ -117,6 +115,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
unsigned int dm_table_get_num_targets(struct dm_table *t);
struct list_head *dm_table_get_devices(struct dm_table *t);
int dm_table_get_mode(struct dm_table *t);
struct mapped_device *dm_table_get_md(struct dm_table *t);
void dm_table_presuspend_targets(struct dm_table *t);
void dm_table_postsuspend_targets(struct dm_table *t);
void dm_table_resume_targets(struct dm_table *t);

View file

@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include "kcopyd.h"
@ -44,6 +45,9 @@ struct kcopyd_client {
struct page_list *pages;
unsigned int nr_pages;
unsigned int nr_free_pages;
wait_queue_head_t destroyq;
atomic_t nr_jobs;
};
static struct page_list *alloc_pl(void)
@ -292,10 +296,15 @@ static int run_complete_job(struct kcopyd_job *job)
int read_err = job->read_err;
unsigned int write_err = job->write_err;
kcopyd_notify_fn fn = job->fn;
struct kcopyd_client *kc = job->kc;
kcopyd_put_pages(job->kc, job->pages);
kcopyd_put_pages(kc, job->pages);
mempool_free(job, _job_pool);
fn(read_err, write_err, context);
if (atomic_dec_and_test(&kc->nr_jobs))
wake_up(&kc->destroyq);
return 0;
}
@ -430,6 +439,7 @@ static void do_work(void *ignored)
*/
static void dispatch_job(struct kcopyd_job *job)
{
atomic_inc(&job->kc->nr_jobs);
push(&_pages_jobs, job);
wake();
}
@ -572,21 +582,21 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
/*-----------------------------------------------------------------
* Unit setup
*---------------------------------------------------------------*/
static DECLARE_MUTEX(_client_lock);
static DEFINE_MUTEX(_client_lock);
static LIST_HEAD(_clients);
static void client_add(struct kcopyd_client *kc)
{
down(&_client_lock);
mutex_lock(&_client_lock);
list_add(&kc->list, &_clients);
up(&_client_lock);
mutex_unlock(&_client_lock);
}
static void client_del(struct kcopyd_client *kc)
{
down(&_client_lock);
mutex_lock(&_client_lock);
list_del(&kc->list);
up(&_client_lock);
mutex_unlock(&_client_lock);
}
static DEFINE_MUTEX(kcopyd_init_lock);
@ -669,6 +679,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
return r;
}
init_waitqueue_head(&kc->destroyq);
atomic_set(&kc->nr_jobs, 0);
client_add(kc);
*result = kc;
return 0;
@ -676,6 +689,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
void kcopyd_client_destroy(struct kcopyd_client *kc)
{
/* Wait for completion of all jobs submitted by this client. */
wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
dm_io_put(kc->nr_pages);
client_free_pages(kc);
client_del(kc);

View file

@ -43,6 +43,7 @@
#include <linux/buffer_head.h> /* for invalidate_bdev */
#include <linux/suspend.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/init.h>
@ -158,11 +159,12 @@ static int start_readonly;
*/
static DECLARE_WAIT_QUEUE_HEAD(md_event_waiters);
static atomic_t md_event_count;
static void md_new_event(mddev_t *mddev)
void md_new_event(mddev_t *mddev)
{
atomic_inc(&md_event_count);
wake_up(&md_event_waiters);
}
EXPORT_SYMBOL_GPL(md_new_event);
/*
* Enables to iterate over all existing md arrays
@ -253,7 +255,7 @@ static mddev_t * mddev_find(dev_t unit)
else
new->md_minor = MINOR(unit) >> MdpMinorShift;
init_MUTEX(&new->reconfig_sem);
mutex_init(&new->reconfig_mutex);
INIT_LIST_HEAD(&new->disks);
INIT_LIST_HEAD(&new->all_mddevs);
init_timer(&new->safemode_timer);
@ -266,6 +268,7 @@ static mddev_t * mddev_find(dev_t unit)
kfree(new);
return NULL;
}
set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags);
blk_queue_make_request(new->queue, md_fail_request);
@ -274,22 +277,22 @@ static mddev_t * mddev_find(dev_t unit)
static inline int mddev_lock(mddev_t * mddev)
{
return down_interruptible(&mddev->reconfig_sem);
return mutex_lock_interruptible(&mddev->reconfig_mutex);
}
static inline void mddev_lock_uninterruptible(mddev_t * mddev)
{
down(&mddev->reconfig_sem);
mutex_lock(&mddev->reconfig_mutex);
}
static inline int mddev_trylock(mddev_t * mddev)
{
return down_trylock(&mddev->reconfig_sem);
return mutex_trylock(&mddev->reconfig_mutex);
}
static inline void mddev_unlock(mddev_t * mddev)
{
up(&mddev->reconfig_sem);
mutex_unlock(&mddev->reconfig_mutex);
md_wakeup_thread(mddev->thread);
}
@ -660,7 +663,8 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
}
if (sb->major_version != 0 ||
sb->minor_version != 90) {
sb->minor_version < 90 ||
sb->minor_version > 91) {
printk(KERN_WARNING "Bad version number %d.%d on %s\n",
sb->major_version, sb->minor_version,
b);
@ -745,6 +749,20 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->bitmap_offset = 0;
mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
if (mddev->minor_version >= 91) {
mddev->reshape_position = sb->reshape_position;
mddev->delta_disks = sb->delta_disks;
mddev->new_level = sb->new_level;
mddev->new_layout = sb->new_layout;
mddev->new_chunk = sb->new_chunk;
} else {
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
mddev->new_level = mddev->level;
mddev->new_layout = mddev->layout;
mddev->new_chunk = mddev->chunk_size;
}
if (sb->state & (1<<MD_SB_CLEAN))
mddev->recovery_cp = MaxSector;
else {
@ -764,7 +782,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
mddev->bitmap_file == NULL) {
if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6
if (mddev->level != 1 && mddev->level != 4
&& mddev->level != 5 && mddev->level != 6
&& mddev->level != 10) {
/* FIXME use a better test */
printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
@ -838,7 +857,6 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->md_magic = MD_SB_MAGIC;
sb->major_version = mddev->major_version;
sb->minor_version = mddev->minor_version;
sb->patch_version = mddev->patch_version;
sb->gvalid_words = 0; /* ignored */
memcpy(&sb->set_uuid0, mddev->uuid+0, 4);
@ -857,6 +875,17 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->events_hi = (mddev->events>>32);
sb->events_lo = (u32)mddev->events;
if (mddev->reshape_position == MaxSector)
sb->minor_version = 90;
else {
sb->minor_version = 91;
sb->reshape_position = mddev->reshape_position;
sb->new_level = mddev->new_level;
sb->delta_disks = mddev->delta_disks;
sb->new_layout = mddev->new_layout;
sb->new_chunk = mddev->new_chunk;
}
mddev->minor_version = sb->minor_version;
if (mddev->in_sync)
{
sb->recovery_cp = mddev->recovery_cp;
@ -893,10 +922,9 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
d->raid_disk = rdev2->raid_disk;
else
d->raid_disk = rdev2->desc_nr; /* compatibility */
if (test_bit(Faulty, &rdev2->flags)) {
if (test_bit(Faulty, &rdev2->flags))
d->state = (1<<MD_DISK_FAULTY);
failed++;
} else if (test_bit(In_sync, &rdev2->flags)) {
else if (test_bit(In_sync, &rdev2->flags)) {
d->state = (1<<MD_DISK_ACTIVE);
d->state |= (1<<MD_DISK_SYNC);
active++;
@ -1102,6 +1130,20 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
}
mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
}
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
mddev->reshape_position = le64_to_cpu(sb->reshape_position);
mddev->delta_disks = le32_to_cpu(sb->delta_disks);
mddev->new_level = le32_to_cpu(sb->new_level);
mddev->new_layout = le32_to_cpu(sb->new_layout);
mddev->new_chunk = le32_to_cpu(sb->new_chunk)<<9;
} else {
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
mddev->new_level = mddev->level;
mddev->new_layout = mddev->layout;
mddev->new_chunk = mddev->chunk_size;
}
} else if (mddev->pers == NULL) {
/* Insist of good event counter while assembling */
__u64 ev1 = le64_to_cpu(sb->events);
@ -1173,6 +1215,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
}
if (mddev->reshape_position != MaxSector) {
sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE);
sb->reshape_position = cpu_to_le64(mddev->reshape_position);
sb->new_layout = cpu_to_le32(mddev->new_layout);
sb->delta_disks = cpu_to_le32(mddev->delta_disks);
sb->new_level = cpu_to_le32(mddev->new_level);
sb->new_chunk = cpu_to_le32(mddev->new_chunk>>9);
}
max_dev = 0;
ITERATE_RDEV(mddev,rdev2,tmp)
@ -1301,6 +1351,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
else
ko = &rdev->bdev->bd_disk->kobj;
sysfs_create_link(&rdev->kobj, ko, "block");
bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk);
return 0;
}
@ -1311,6 +1362,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
MD_BUG();
return;
}
bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk);
list_del_init(&rdev->same_set);
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
rdev->mddev = NULL;
@ -1493,7 +1545,7 @@ static void sync_sbs(mddev_t * mddev)
}
}
static void md_update_sb(mddev_t * mddev)
void md_update_sb(mddev_t * mddev)
{
int err;
struct list_head *tmp;
@ -1570,6 +1622,7 @@ repeat:
wake_up(&mddev->sb_wait);
}
EXPORT_SYMBOL_GPL(md_update_sb);
/* words written to sysfs files may, or my not, be \n terminated.
* We want to accept with case. For this we use cmd_match.
@ -2162,7 +2215,9 @@ action_show(mddev_t *mddev, char *page)
char *type = "idle";
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) {
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
type = "reshape";
else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
type = "resync";
else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
@ -2193,7 +2248,14 @@ action_store(mddev_t *mddev, const char *page, size_t len)
return -EBUSY;
else if (cmd_match(page, "resync") || cmd_match(page, "recover"))
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
else {
else if (cmd_match(page, "reshape")) {
int err;
if (mddev->pers->start_reshape == NULL)
return -EINVAL;
err = mddev->pers->start_reshape(mddev);
if (err)
return err;
} else {
if (cmd_match(page, "check"))
set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
else if (cmd_match(page, "repair"))
@ -2304,6 +2366,63 @@ sync_completed_show(mddev_t *mddev, char *page)
static struct md_sysfs_entry
md_sync_completed = __ATTR_RO(sync_completed);
static ssize_t
suspend_lo_show(mddev_t *mddev, char *page)
{
return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo);
}
static ssize_t
suspend_lo_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
if (mddev->pers->quiesce == NULL)
return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
if (new >= mddev->suspend_hi ||
(new > mddev->suspend_lo && new < mddev->suspend_hi)) {
mddev->suspend_lo = new;
mddev->pers->quiesce(mddev, 2);
return len;
} else
return -EINVAL;
}
static struct md_sysfs_entry md_suspend_lo =
__ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
static ssize_t
suspend_hi_show(mddev_t *mddev, char *page)
{
return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_hi);
}
static ssize_t
suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
if (mddev->pers->quiesce == NULL)
return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
if ((new <= mddev->suspend_lo && mddev->suspend_lo >= mddev->suspend_hi) ||
(new > mddev->suspend_lo && new > mddev->suspend_hi)) {
mddev->suspend_hi = new;
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
return len;
} else
return -EINVAL;
}
static struct md_sysfs_entry md_suspend_hi =
__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
static struct attribute *md_default_attrs[] = {
&md_level.attr,
&md_raid_disks.attr,
@ -2321,6 +2440,8 @@ static struct attribute *md_redundancy_attrs[] = {
&md_sync_max.attr,
&md_sync_speed.attr,
&md_sync_completed.attr,
&md_suspend_lo.attr,
&md_suspend_hi.attr,
NULL,
};
static struct attribute_group md_redundancy_group = {
@ -2380,7 +2501,7 @@ int mdp_major = 0;
static struct kobject *md_probe(dev_t dev, int *part, void *data)
{
static DECLARE_MUTEX(disks_sem);
static DEFINE_MUTEX(disks_mutex);
mddev_t *mddev = mddev_find(dev);
struct gendisk *disk;
int partitioned = (MAJOR(dev) != MD_MAJOR);
@ -2390,15 +2511,15 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
if (!mddev)
return NULL;
down(&disks_sem);
mutex_lock(&disks_mutex);
if (mddev->gendisk) {
up(&disks_sem);
mutex_unlock(&disks_mutex);
mddev_put(mddev);
return NULL;
}
disk = alloc_disk(1 << shift);
if (!disk) {
up(&disks_sem);
mutex_unlock(&disks_mutex);
mddev_put(mddev);
return NULL;
}
@ -2416,7 +2537,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
disk->queue = mddev->queue;
add_disk(disk);
mddev->gendisk = disk;
up(&disks_sem);
mutex_unlock(&disks_mutex);
mddev->kobj.parent = &disk->kobj;
mddev->kobj.k_name = NULL;
snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
@ -2539,6 +2660,14 @@ static int do_md_run(mddev_t * mddev)
mddev->level = pers->level;
strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
if (mddev->reshape_position != MaxSector &&
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
mddev->pers = NULL;
module_put(pers->owner);
return -EINVAL;
}
mddev->recovery = 0;
mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
mddev->barriers_work = 1;
@ -2772,7 +2901,6 @@ static void autorun_array(mddev_t *mddev)
*/
static void autorun_devices(int part)
{
struct list_head candidates;
struct list_head *tmp;
mdk_rdev_t *rdev0, *rdev;
mddev_t *mddev;
@ -2781,6 +2909,7 @@ static void autorun_devices(int part)
printk(KERN_INFO "md: autorun ...\n");
while (!list_empty(&pending_raid_disks)) {
dev_t dev;
LIST_HEAD(candidates);
rdev0 = list_entry(pending_raid_disks.next,
mdk_rdev_t, same_set);
@ -3427,11 +3556,18 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
mddev->bitmap_offset = 0;
mddev->reshape_position = MaxSector;
/*
* Generate a 128 bit UUID
*/
get_random_bytes(mddev->uuid, 16);
mddev->new_level = mddev->level;
mddev->new_chunk = mddev->chunk_size;
mddev->new_layout = mddev->layout;
mddev->delta_disks = 0;
return 0;
}
@ -3440,6 +3576,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
mdk_rdev_t * rdev;
int rv;
struct list_head *tmp;
int fit = (size == 0);
if (mddev->pers->resize == NULL)
return -EINVAL;
@ -3457,7 +3594,6 @@ static int update_size(mddev_t *mddev, unsigned long size)
return -EBUSY;
ITERATE_RDEV(mddev,rdev,tmp) {
sector_t avail;
int fit = (size == 0);
if (rdev->sb_offset > rdev->data_offset)
avail = (rdev->sb_offset*2) - rdev->data_offset;
else
@ -3487,14 +3623,16 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks)
{
int rv;
/* change the number of raid disks */
if (mddev->pers->reshape == NULL)
if (mddev->pers->check_reshape == NULL)
return -EINVAL;
if (raid_disks <= 0 ||
raid_disks >= mddev->max_disks)
return -EINVAL;
if (mddev->sync_thread)
if (mddev->sync_thread || mddev->reshape_position != MaxSector)
return -EBUSY;
rv = mddev->pers->reshape(mddev, raid_disks);
mddev->delta_disks = raid_disks - mddev->raid_disks;
rv = mddev->pers->check_reshape(mddev);
return rv;
}
@ -4041,7 +4179,10 @@ static void status_unused(struct seq_file *seq)
static void status_resync(struct seq_file *seq, mddev_t * mddev)
{
unsigned long max_blocks, resync, res, dt, db, rt;
sector_t max_blocks, resync, res;
unsigned long dt, db, rt;
int scale;
unsigned int per_milli;
resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
@ -4057,9 +4198,22 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
MD_BUG();
return;
}
res = (resync/1024)*1000/(max_blocks/1024 + 1);
/* Pick 'scale' such that (resync>>scale)*1000 will fit
* in a sector_t, and (max_blocks>>scale) will fit in a
* u32, as those are the requirements for sector_div.
* Thus 'scale' must be at least 10
*/
scale = 10;
if (sizeof(sector_t) > sizeof(unsigned long)) {
while ( max_blocks/2 > (1ULL<<(scale+32)))
scale++;
}
res = (resync>>scale)*1000;
sector_div(res, (u32)((max_blocks>>scale)+1));
per_milli = res;
{
int i, x = res/50, y = 20-x;
int i, x = per_milli/50, y = 20-x;
seq_printf(seq, "[");
for (i = 0; i < x; i++)
seq_printf(seq, "=");
@ -4068,10 +4222,14 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
seq_printf(seq, ".");
seq_printf(seq, "] ");
}
seq_printf(seq, " %s =%3lu.%lu%% (%lu/%lu)",
seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)",
(test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)?
"reshape" :
(test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
"resync" : "recovery"),
res/10, res % 10, resync, max_blocks);
"resync" : "recovery")),
per_milli/10, per_milli % 10,
(unsigned long long) resync,
(unsigned long long) max_blocks);
/*
* We do not want to overflow, so the order of operands and
@ -4085,7 +4243,7 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
db = resync - (mddev->resync_mark_cnt/2);
rt = (dt * ((max_blocks-resync) / (db/100+1)))/100;
rt = (dt * ((unsigned long)(max_blocks-resync) / (db/100+1)))/100;
seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
@ -4442,7 +4600,7 @@ static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
#define SYNC_MARKS 10
#define SYNC_MARK_STEP (3*HZ)
static void md_do_sync(mddev_t *mddev)
void md_do_sync(mddev_t *mddev)
{
mddev_t *mddev2;
unsigned int currspeed = 0,
@ -4522,7 +4680,9 @@ static void md_do_sync(mddev_t *mddev)
*/
max_sectors = mddev->resync_max_sectors;
mddev->resync_mismatches = 0;
} else
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->size << 1;
else
/* recovery follows the physical size of devices */
max_sectors = mddev->size << 1;
@ -4658,6 +4818,8 @@ static void md_do_sync(mddev_t *mddev)
mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
mddev->curr_resync > 2 &&
mddev->curr_resync >= mddev->recovery_cp) {
if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
@ -4675,6 +4837,7 @@ static void md_do_sync(mddev_t *mddev)
set_bit(MD_RECOVERY_DONE, &mddev->recovery);
md_wakeup_thread(mddev->thread);
}
EXPORT_SYMBOL_GPL(md_do_sync);
/*
@ -4730,7 +4893,7 @@ void md_check_recovery(mddev_t *mddev)
))
return;
if (mddev_trylock(mddev)==0) {
if (mddev_trylock(mddev)) {
int spares =0;
spin_lock_irq(&mddev->write_lock);
@ -4866,7 +5029,7 @@ static int md_notify_reboot(struct notifier_block *this,
printk(KERN_INFO "md: stopping all md devices.\n");
ITERATE_MDDEV(mddev,tmp)
if (mddev_trylock(mddev)==0)
if (mddev_trylock(mddev))
do_md_stop (mddev, 1);
/*
* certain more exotic SCSI devices are known to be

View file

@ -1401,6 +1401,9 @@ static void raid1d(mddev_t *mddev)
int i;
clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
clear_bit(R1BIO_Barrier, &r1_bio->state);
for (i=0; i < conf->raid_disks; i++)
if (r1_bio->bios[i])
atomic_inc(&r1_bio->remaining);
for (i=0; i < conf->raid_disks; i++)
if (r1_bio->bios[i]) {
struct bio_vec *bvec;
@ -1789,6 +1792,11 @@ static int run(mddev_t *mddev)
mdname(mddev), mddev->level);
goto out;
}
if (mddev->reshape_position != MaxSector) {
printk("raid1: %s: reshape_position set but not supported\n",
mdname(mddev));
goto out;
}
/*
* copy the already verified devices into our private RAID1
* bookkeeping area. [whatever we allocate in run(),
@ -1971,7 +1979,7 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
return 0;
}
static int raid1_reshape(mddev_t *mddev, int raid_disks)
static int raid1_reshape(mddev_t *mddev)
{
/* We need to:
* 1/ resize the r1bio_pool
@ -1988,10 +1996,22 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks)
struct pool_info *newpoolinfo;
mirror_info_t *newmirrors;
conf_t *conf = mddev_to_conf(mddev);
int cnt;
int cnt, raid_disks;
int d, d2;
/* Cannot change chunk_size, layout, or level */
if (mddev->chunk_size != mddev->new_chunk ||
mddev->layout != mddev->new_layout ||
mddev->level != mddev->new_level) {
mddev->new_chunk = mddev->chunk_size;
mddev->new_layout = mddev->layout;
mddev->new_level = mddev->level;
return -EINVAL;
}
raid_disks = mddev->raid_disks + mddev->delta_disks;
if (raid_disks < conf->raid_disks) {
cnt=0;
for (d= 0; d < conf->raid_disks; d++)
@ -2038,6 +2058,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks)
mddev->degraded += (raid_disks - conf->raid_disks);
conf->raid_disks = mddev->raid_disks = raid_disks;
mddev->delta_disks = 0;
conf->last_used = 0; /* just make sure it is in-range */
lower_barrier(conf);
@ -2079,7 +2100,7 @@ static struct mdk_personality raid1_personality =
.spare_active = raid1_spare_active,
.sync_request = sync_request,
.resize = raid1_resize,
.reshape = raid1_reshape,
.check_reshape = raid1_reshape,
.quiesce = raid1_quiesce,
};

File diff suppressed because it is too large Load diff

View file

@ -331,9 +331,9 @@ static int grow_stripes(raid6_conf_t *conf, int num)
kmem_cache_t *sc;
int devs = conf->raid_disks;
sprintf(conf->cache_name, "raid6/%s", mdname(conf->mddev));
sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev));
sc = kmem_cache_create(conf->cache_name,
sc = kmem_cache_create(conf->cache_name[0],
sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
0, 0, NULL, NULL);
if (!sc)
@ -2006,11 +2006,14 @@ static int run(mddev_t *mddev)
return -EIO;
}
mddev->private = kzalloc(sizeof (raid6_conf_t)
+ mddev->raid_disks * sizeof(struct disk_info),
GFP_KERNEL);
mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL);
if ((conf = mddev->private) == NULL)
goto abort;
conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info),
GFP_KERNEL);
if (!conf->disks)
goto abort;
conf->mddev = mddev;
if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
@ -2158,6 +2161,7 @@ abort:
print_raid6_conf(conf);
safe_put_page(conf->spare_page);
kfree(conf->stripe_hashtbl);
kfree(conf->disks);
kfree(conf);
}
mddev->private = NULL;

View file

@ -86,7 +86,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
if (dvbdev && dvbdev->fops) {
int err = 0;
struct file_operations *old_fops;
const struct file_operations *old_fops;
file->private_data = dvbdev;
old_fops = file->f_op;

View file

@ -97,7 +97,7 @@ static int video_open(struct inode *inode, struct file *file)
unsigned int minor = iminor(inode);
int err = 0;
struct video_device *vfl;
struct file_operations *old_fops;
const struct file_operations *old_fops;
if(minor>=VIDEO_NUM_DEVICES)
return -ENODEV;

View file

@ -56,7 +56,7 @@
typedef struct _i2o_proc_entry_t {
char *name; /* entry name */
mode_t mode; /* mode */
struct file_operations *fops; /* open function */
const struct file_operations *fops; /* open function */
} i2o_proc_entry;
/* global I2O /proc/i2o entry */

View file

@ -52,12 +52,13 @@ static struct notifier_block panic_notifier = { panic_happened, NULL, 1 };
void ibmasm_register_panic_notifier(void)
{
notifier_chain_register(&panic_notifier_list, &panic_notifier);
atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier);
}
void ibmasm_unregister_panic_notifier(void)
{
notifier_chain_unregister(&panic_notifier_list, &panic_notifier);
atomic_notifier_chain_unregister(&panic_notifier_list,
&panic_notifier);
}

View file

@ -101,7 +101,7 @@ static struct super_operations ibmasmfs_s_ops = {
.drop_inode = generic_delete_inode,
};
static struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
static struct file_system_type ibmasmfs_type = {
.owner = THIS_MODULE,

View file

@ -3159,7 +3159,7 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
* bond_netdev_event: handle netdev notifier chain events.
*
* This function receives events for the netdev chain. The caller (an
* ioctl handler calling notifier_call_chain) holds the necessary
* ioctl handler calling blocking_notifier_call_chain) holds the necessary
* locks for us to safely manipulate the slave devices (RTNL lock,
* dev_probe_lock).
*/

View file

@ -134,6 +134,7 @@
#include <linux/random.h>
#include <linux/init.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <asm/irq.h>
#include <asm/io.h>
@ -2932,7 +2933,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (id->driver_data & DEV_HAS_HIGH_DMA) {
/* packet format 3: supports 40-bit addressing */
np->desc_ver = DESC_VER_3;
if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) {
printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
pci_name(pci_dev));
} else {

View file

@ -44,6 +44,7 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_SERIAL_8250
#include <linux/serial_core.h>
@ -1195,17 +1196,17 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int err, pci_using_dac;
/* Configure DMA attributes. */
err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
if (!err) {
pci_using_dac = 1;
err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (err < 0) {
printk(KERN_ERR "%s: Unable to obtain 64 bit DMA "
"for consistent allocations\n", pci_name(pdev));
goto out;
}
} else {
err = pci_set_dma_mask(pdev, 0xffffffffULL);
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
printk(KERN_ERR "%s: No usable DMA configuration, "
"aborting.\n", pci_name(pdev));

View file

@ -207,7 +207,7 @@ static int __init nsc_ircc_init(void)
/* Register with PnP subsystem to detect disable ports */
ret = pnp_register_driver(&nsc_ircc_pnp_driver);
if (ret >= 0)
if (!ret)
pnp_registered = 1;
ret = -ENODEV;
@ -812,7 +812,7 @@ static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info)
int cfg_base = info->cfg_base;
int enabled;
/* User is shure about his config... accept it. */
/* User is sure about his config... accept it. */
IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): "
"io=0x%04x, irq=%d, dma=%d\n",
__FUNCTION__, info->fir_base, info->irq, info->dma);

View file

@ -172,7 +172,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
memset(stats, 0, sizeof(struct net_device_stats));
for_each_cpu(i) {
for_each_possible_cpu(i) {
struct net_device_stats *lb_stats;
lb_stats = &per_cpu(loopback_stats, i);

View file

@ -1828,10 +1828,10 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
int using_dac = 0;
/* See if we can set the dma mask early on; failure is fatal. */
if (sizeof(dma_addr_t) == 8 &&
!pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
if (sizeof(dma_addr_t) == 8 &&
!pci_set_dma_mask(pci_dev, DMA_64BIT_MASK)) {
using_dac = 1;
} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
using_dac = 0;
} else {
printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");

View file

@ -2283,7 +2283,7 @@ static void set_rx_mode(struct net_device *net_dev)
int i, table_entries;
u32 rx_mode;
/* 635 Hash Table entires = 256(2^16) */
/* 635 Hash Table entries = 256(2^16) */
if((sis_priv->chipset_rev >= SIS635A_900_REV) ||
(sis_priv->chipset_rev == SIS900B_900_REV))
table_entries = 16;

View file

@ -513,7 +513,7 @@ struct mii_phy {
u_char *rst; /* Start of reset sequence in SROM */
u_int mc; /* Media Capabilities */
u_int ana; /* NWay Advertisement */
u_int fdx; /* Full DupleX capabilites for each media */
u_int fdx; /* Full DupleX capabilities for each media */
u_int ttm; /* Transmit Threshold Mode for each media */
u_int mci; /* 21142 MII Connector Interrupt info */
};

View file

@ -199,7 +199,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
/* negotiation ended successfully */
/* get the link partners reply and mask out all but
* bits 24-21 which show the partners capabilites
* bits 24-21 which show the partners capabilities
* and match those to what we advertised
*
* then begin to interpret the results of the negotiation.

View file

@ -208,7 +208,7 @@ static const struct typhoon_card_info typhoon_card_info[] __devinitdata = {
};
/* Notes on the new subsystem numbering scheme:
* bits 0-1 indicate crypto capabilites: (0) variable, (1) DES, or (2) 3DES
* bits 0-1 indicate crypto capabilities: (0) variable, (1) DES, or (2) 3DES
* bit 4 indicates if this card has secured firmware (we don't support it)
* bit 8 indicates if this is a (0) copper or (1) fiber card
* bits 12-16 indicate card type: (0) client and (1) server
@ -788,7 +788,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
/* we have two rings to choose from, but we only use txLo for now
* If we start using the Hi ring as well, we'll need to update
* typhoon_stop_runtime(), typhoon_interrupt(), typhoon_num_free_tx(),
* and TXHI_ENTIRES to match, as well as update the TSO code below
* and TXHI_ENTRIES to match, as well as update the TSO code below
* to get the right DMA address
*/
txRing = &tp->txLoRing;

View file

@ -577,8 +577,8 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
We set both dma_mask and consistent_dma_mask to 28 bits
and pray pci_alloc_consistent() will use this info. It should
work on most platforms */
if (pci_set_consistent_dma_mask(pdev, 0x0FFFFFFF) ||
pci_set_dma_mask(pdev, 0x0FFFFFFF)) {
if (pci_set_consistent_dma_mask(pdev, DMA_28BIT_MASK) ||
pci_set_dma_mask(pdev, DMA_28BIT_MASK)) {
printk(KERN_ERR "wanXL: No usable DMA configuration\n");
return -EIO;
}

View file

@ -3858,7 +3858,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
unsigned long flags;
/* Note : you may have realised that, as this is a SET operation,
* this is priviledged and therefore a normal user can't
* this is privileged and therefore a normal user can't
* perform scanning.
* This is not an error, while the device perform scanning,
* traffic doesn't flow, so it's a perfect DoS...

View file

@ -747,7 +747,7 @@ prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
if (essid->length) {
dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */
/* if it is to big, trunk it */
/* if it is too big, trunk it */
dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length);
} else {
dwrq->flags = 0;

View file

@ -22,6 +22,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/init.h> /* For __init, __exit */
#include <linux/dma-mapping.h>
#include "prismcompat.h"
#include "islpci_dev.h"
@ -124,7 +125,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* enable PCI DMA */
if (pci_set_dma_mask(pdev, 0xffffffff)) {
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME);
goto do_pci_disable_device;
}

View file

@ -217,11 +217,10 @@ static void oprofile_end_trace(struct oprofile_cpu_buffer * cpu_buf)
cpu_buf->tracing = 0;
}
void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel)
{
struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
unsigned long pc = profile_pc(regs);
int is_kernel = !user_mode(regs);
if (!backtrace_depth) {
log_sample(cpu_buf, pc, is_kernel, event);
@ -238,6 +237,14 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
oprofile_end_trace(cpu_buf);
}
void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
{
int is_kernel = !user_mode(regs);
unsigned long pc = profile_pc(regs);
oprofile_add_ext_sample(pc, regs, event, is_kernel);
}
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
{
struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];

View file

@ -22,7 +22,7 @@ void oprofile_reset_stats(void)
struct oprofile_cpu_buffer * cpu_buf;
int i;
for_each_cpu(i) {
for_each_possible_cpu(i) {
cpu_buf = &cpu_buffer[i];
cpu_buf->sample_received = 0;
cpu_buf->sample_lost_overflow = 0;
@ -46,7 +46,7 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
if (!dir)
return;
for_each_cpu(i) {
for_each_possible_cpu(i) {
cpu_buf = &cpu_buffer[i];
snprintf(buf, 10, "cpu%d", i);
cpudir = oprofilefs_mkdir(sb, dir, buf);

View file

@ -130,7 +130,7 @@ static struct file_operations ulong_ro_fops = {
static struct dentry * __oprofilefs_create_file(struct super_block * sb,
struct dentry * root, char const * name, struct file_operations * fops,
struct dentry * root, char const * name, const struct file_operations * fops,
int perm)
{
struct dentry * dentry;
@ -203,7 +203,7 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
char const * name, struct file_operations * fops)
char const * name, const struct file_operations * fops)
{
if (!__oprofilefs_create_file(sb, root, name, fops, 0644))
return -EFAULT;
@ -212,7 +212,7 @@ int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
char const * name, struct file_operations * fops, int perm)
char const * name, const struct file_operations * fops, int perm)
{
if (!__oprofilefs_create_file(sb, root, name, fops, perm))
return -EFAULT;

View file

@ -499,11 +499,16 @@ static int led_halt(struct notifier_block *, unsigned long, void *);
static struct notifier_block led_notifier = {
.notifier_call = led_halt,
};
static int notifier_disabled = 0;
static int led_halt(struct notifier_block *nb, unsigned long event, void *buf)
{
char *txt;
if (notifier_disabled)
return NOTIFY_OK;
notifier_disabled = 1;
switch (event) {
case SYS_RESTART: txt = "SYSTEM RESTART";
break;
@ -527,7 +532,6 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf)
if (led_func_ptr)
led_func_ptr(0xff); /* turn all LEDs ON */
unregister_reboot_notifier(&led_notifier);
return NOTIFY_OK;
}
@ -758,6 +762,12 @@ not_found:
return 1;
}
static void __exit led_exit(void)
{
unregister_reboot_notifier(&led_notifier);
return;
}
#ifdef CONFIG_PROC_FS
module_init(led_create_procfs)
#endif

View file

@ -251,7 +251,8 @@ static int __init power_init(void)
}
/* Register a call for panic conditions. */
notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
atomic_notifier_chain_register(&panic_notifier_list,
&parisc_panic_block);
tasklet_enable(&power_tasklet);
@ -264,7 +265,8 @@ static void __exit power_exit(void)
return;
tasklet_disable(&power_tasklet);
notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
atomic_notifier_chain_unregister(&panic_notifier_list,
&parisc_panic_block);
power_tasklet.func = NULL;
pdc_soft_power_button(0);
}

View file

@ -3126,9 +3126,9 @@ parport_pc_find_isa_ports (int autoirq, int autodma)
* autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY
* autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO
*/
static int __init parport_pc_find_ports (int autoirq, int autodma)
static void __init parport_pc_find_ports (int autoirq, int autodma)
{
int count = 0, r;
int count = 0, err;
#ifdef CONFIG_PARPORT_PC_SUPERIO
detect_and_report_winbond ();
@ -3140,23 +3140,17 @@ static int __init parport_pc_find_ports (int autoirq, int autodma)
/* PnP ports, skip detection if SuperIO already found them */
if (!count) {
r = pnp_register_driver (&parport_pc_pnp_driver);
if (r >= 0) {
err = pnp_register_driver (&parport_pc_pnp_driver);
if (!err)
pnp_registered_parport = 1;
count += r;
}
}
/* ISA ports and whatever (see asm/parport.h). */
count += parport_pc_find_nonpci_ports (autoirq, autodma);
parport_pc_find_nonpci_ports (autoirq, autodma);
r = pci_register_driver (&parport_pc_pci_driver);
if (r)
return r;
pci_registered_parport = 1;
count += 1;
return count;
err = pci_register_driver (&parport_pc_pci_driver);
if (!err)
pci_registered_parport = 1;
}
/*
@ -3381,8 +3375,6 @@ __setup("parport_init_mode=",parport_init_mode_setup);
static int __init parport_pc_init(void)
{
int count = 0;
if (parse_parport_params())
return -EINVAL;
@ -3395,12 +3387,11 @@ static int __init parport_pc_init(void)
break;
if ((io_hi[i]) == PARPORT_IOHI_AUTO)
io_hi[i] = 0x400 + io[i];
if (parport_pc_probe_port(io[i], io_hi[i],
irqval[i], dmaval[i], NULL))
count++;
parport_pc_probe_port(io[i], io_hi[i],
irqval[i], dmaval[i], NULL);
}
} else
count += parport_pc_find_ports (irqval[0], dmaval[0]);
parport_pc_find_ports (irqval[0], dmaval[0]);
return 0;
}

View file

@ -47,7 +47,7 @@ static void card_remove(struct pnp_dev * dev)
{
dev->card_link = NULL;
}
static void card_remove_first(struct pnp_dev * dev)
{
struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
@ -361,7 +361,7 @@ static int card_resume(struct pnp_dev *dev)
int pnp_register_card_driver(struct pnp_card_driver * drv)
{
int count;
int error;
struct list_head *pos, *temp;
drv->link.name = drv->name;
@ -372,21 +372,19 @@ int pnp_register_card_driver(struct pnp_card_driver * drv)
drv->link.suspend = drv->suspend ? card_suspend : NULL;
drv->link.resume = drv->resume ? card_resume : NULL;
count = pnp_register_driver(&drv->link);
if (count < 0)
return count;
error = pnp_register_driver(&drv->link);
if (error < 0)
return error;
spin_lock(&pnp_lock);
list_add_tail(&drv->global_list, &pnp_card_drivers);
spin_unlock(&pnp_lock);
count = 0;
list_for_each_safe(pos,temp,&pnp_cards){
struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
count += card_probe(card,drv);
card_probe(card,drv);
}
return count;
return 0;
}
/**

View file

@ -201,31 +201,14 @@ struct bus_type pnp_bus_type = {
.resume = pnp_bus_resume,
};
static int count_devices(struct device * dev, void * c)
{
int * count = c;
(*count)++;
return 0;
}
int pnp_register_driver(struct pnp_driver *drv)
{
int count;
pnp_dbg("the driver '%s' has been registered", drv->name);
drv->driver.name = drv->name;
drv->driver.bus = &pnp_bus_type;
count = driver_register(&drv->driver);
/* get the number of initial matches */
if (count >= 0){
count = 0;
driver_for_each_device(&drv->driver, NULL, &count, count_devices);
}
return count;
return driver_register(&drv->driver);
}
void pnp_unregister_driver(struct pnp_driver *drv)

165
drivers/rtc/Kconfig Normal file
View file

@ -0,0 +1,165 @@
\#
# RTC class/drivers configuration
#
menu "Real Time Clock"
config RTC_LIB
tristate
config RTC_CLASS
tristate "RTC class"
depends on EXPERIMENTAL
default n
select RTC_LIB
help
Generic RTC class support. If you say yes here, you will
be allowed to plug one or more RTCs to your system. You will
probably want to enable one of more of the interfaces below.
This driver can also be built as a module. If so, the module
will be called rtc-class.
config RTC_HCTOSYS
bool "Set system time from RTC on startup"
depends on RTC_CLASS = y
default y
help
If you say yes here, the system time will be set using
the value read from the specified RTC device. This is useful
in order to avoid unnecessary fschk runs.
config RTC_HCTOSYS_DEVICE
string "The RTC to read the time from"
depends on RTC_HCTOSYS = y
default "rtc0"
help
The RTC device that will be used as the source for
the system time, usually rtc0.
comment "RTC interfaces"
depends on RTC_CLASS
config RTC_INTF_SYSFS
tristate "sysfs"
depends on RTC_CLASS && SYSFS
default RTC_CLASS
help
Say yes here if you want to use your RTC using the sysfs
interface, /sys/class/rtc/rtcX .
This driver can also be built as a module. If so, the module
will be called rtc-sysfs.
config RTC_INTF_PROC
tristate "proc"
depends on RTC_CLASS && PROC_FS
default RTC_CLASS
help
Say yes here if you want to use your RTC using the proc
interface, /proc/driver/rtc .
This driver can also be built as a module. If so, the module
will be called rtc-proc.
config RTC_INTF_DEV
tristate "dev"
depends on RTC_CLASS
default RTC_CLASS
help
Say yes here if you want to use your RTC using the dev
interface, /dev/rtc .
This driver can also be built as a module. If so, the module
will be called rtc-dev.
comment "RTC drivers"
depends on RTC_CLASS
config RTC_DRV_X1205
tristate "Xicor/Intersil X1205"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Xicor/Intersil X1205 RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Dallas/Maxim DS1672 timekeeping chip.
This driver can also be built as a module. If so, the module
will be called rtc-ds1672.
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Philips PCF8563 RTC chip. The Epson RTC8564
should work as well.
This driver can also be built as a module. If so, the module
will be called rtc-pcf8563.
config RTC_DRV_RS5C372
tristate "Ricoh RS5C372A/B"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
Ricoh RS5C372A and RS5C372B RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-rs5c372.
config RTC_DRV_M48T86
tristate "ST M48T86/Dallas DS12887"
depends on RTC_CLASS
help
If you say Y here you will get support for the
ST M48T86 and Dallas DS12887 RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-m48t86.
config RTC_DRV_EP93XX
tristate "Cirrus Logic EP93XX"
depends on RTC_CLASS && ARCH_EP93XX
help
If you say yes here you get support for the
RTC embedded in the Cirrus Logic EP93XX processors.
This driver can also be built as a module. If so, the module
will be called rtc-ep93xx.
config RTC_DRV_SA1100
tristate "SA11x0/PXA2xx"
depends on RTC_CLASS && (ARCH_SA1100 || ARCH_PXA)
help
If you say Y here you will get access to the real time clock
built into your SA11x0 or PXA2xx CPU.
To compile this driver as a module, choose M here: the
module will be called rtc-sa1100.
config RTC_DRV_TEST
tristate "Test driver/device"
depends on RTC_CLASS
help
If you say yes here you get support for the
RTC test driver. It's a software RTC which can be
used to test the RTC subsystem APIs. It gets
the time from the system clock.
You want this driver only if you are doing development
on the RTC subsystem. Please read the source code
for further details.
This driver can also be built as a module. If so, the module
will be called rtc-test.
endmenu

21
drivers/rtc/Makefile Normal file
View file

@ -0,0 +1,21 @@
#
# Makefile for RTC class/drivers.
#
obj-$(CONFIG_RTC_LIB) += rtc-lib.o
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o

145
drivers/rtc/class.c Normal file
View file

@ -0,0 +1,145 @@
/*
* RTC subsystem, base class
*
* Copyright (C) 2005 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* class skeleton from drivers/hwmon/hwmon.c
*
* 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 <linux/module.h>
#include <linux/rtc.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
static DEFINE_IDR(rtc_idr);
static DEFINE_MUTEX(idr_lock);
struct class *rtc_class;
static void rtc_device_release(struct class_device *class_dev)
{
struct rtc_device *rtc = to_rtc_device(class_dev);
mutex_lock(&idr_lock);
idr_remove(&rtc_idr, rtc->id);
mutex_unlock(&idr_lock);
kfree(rtc);
}
/**
* rtc_device_register - register w/ RTC class
* @dev: the device to register
*
* rtc_device_unregister() must be called when the class device is no
* longer needed.
*
* Returns the pointer to the new struct class device.
*/
struct rtc_device *rtc_device_register(const char *name, struct device *dev,
struct rtc_class_ops *ops,
struct module *owner)
{
struct rtc_device *rtc;
int id, err;
if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
err = -ENOMEM;
goto exit;
}
mutex_lock(&idr_lock);
err = idr_get_new(&rtc_idr, NULL, &id);
mutex_unlock(&idr_lock);
if (err < 0)
goto exit;
id = id & MAX_ID_MASK;
rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
if (rtc == NULL) {
err = -ENOMEM;
goto exit_idr;
}
rtc->id = id;
rtc->ops = ops;
rtc->owner = owner;
rtc->class_dev.dev = dev;
rtc->class_dev.class = rtc_class;
rtc->class_dev.release = rtc_device_release;
mutex_init(&rtc->ops_lock);
spin_lock_init(&rtc->irq_lock);
spin_lock_init(&rtc->irq_task_lock);
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
err = class_device_register(&rtc->class_dev);
if (err)
goto exit_kfree;
dev_info(dev, "rtc core: registered %s as %s\n",
rtc->name, rtc->class_dev.class_id);
return rtc;
exit_kfree:
kfree(rtc);
exit_idr:
idr_remove(&rtc_idr, id);
exit:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rtc_device_register);
/**
* rtc_device_unregister - removes the previously registered RTC class device
*
* @rtc: the RTC class device to destroy
*/
void rtc_device_unregister(struct rtc_device *rtc)
{
mutex_lock(&rtc->ops_lock);
rtc->ops = NULL;
mutex_unlock(&rtc->ops_lock);
class_device_unregister(&rtc->class_dev);
}
EXPORT_SYMBOL_GPL(rtc_device_unregister);
int rtc_interface_register(struct class_interface *intf)
{
intf->class = rtc_class;
return class_interface_register(intf);
}
EXPORT_SYMBOL_GPL(rtc_interface_register);
static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
if (IS_ERR(rtc_class)) {
printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
return PTR_ERR(rtc_class);
}
return 0;
}
static void __exit rtc_exit(void)
{
class_destroy(rtc_class);
}
module_init(rtc_init);
module_exit(rtc_exit);
MODULE_AUTHOR("Alessandro Zummo <[email protected]>");
MODULE_DESCRIPTION("RTC class support");
MODULE_LICENSE("GPL");

69
drivers/rtc/hctosys.c Normal file
View file

@ -0,0 +1,69 @@
/*
* RTC subsystem, initialize system time on startup
*
* Copyright (C) 2005 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* 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 <linux/rtc.h>
/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
* whether it stores the most close value or the value with partial
* seconds truncated. However, it is important that we use it to store
* the truncated value. This is because otherwise it is necessary,
* in an rtc sync function, to read both xtime.tv_sec and
* xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
* of >32bits is not possible. So storing the most close value would
* slow down the sync API. So here we have the truncated value and
* the best guess is to add 0.5s.
*/
static int __init rtc_hctosys(void)
{
int err;
struct rtc_time tm;
struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (class_dev == NULL) {
printk("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
return -ENODEV;
}
err = rtc_read_time(class_dev, &tm);
if (err == 0) {
err = rtc_valid_tm(&tm);
if (err == 0) {
struct timespec tv;
tv.tv_nsec = NSEC_PER_SEC >> 1;
rtc_tm_to_time(&tm, &tv.tv_sec);
do_settimeofday(&tv);
dev_info(class_dev->dev,
"setting the system clock to "
"%d-%02d-%02d %02d:%02d:%02d (%u)\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
(unsigned int) tv.tv_sec);
}
else
dev_err(class_dev->dev,
"hctosys: invalid date/time\n");
}
else
dev_err(class_dev->dev,
"hctosys: unable to read the hardware clock\n");
rtc_class_close(class_dev);
return 0;
}
late_initcall(rtc_hctosys);

277
drivers/rtc/interface.c Normal file
View file

@ -0,0 +1,277 @@
/*
* RTC subsystem, interface functions
*
* Copyright (C) 2005 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* based on arch/arm/common/rtctime.c
*
* 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 <linux/rtc.h>
int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
{
int err;
struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return -EBUSY;
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->read_time)
err = -EINVAL;
else {
memset(tm, 0, sizeof(struct rtc_time));
err = rtc->ops->read_time(class_dev->dev, tm);
}
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_read_time);
int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
{
int err;
struct rtc_device *rtc = to_rtc_device(class_dev);
err = rtc_valid_tm(tm);
if (err != 0)
return err;
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return -EBUSY;
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->set_time)
err = -EINVAL;
else
err = rtc->ops->set_time(class_dev->dev, tm);
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);
int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
{
int err;
struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return -EBUSY;
if (!rtc->ops)
err = -ENODEV;
else if (rtc->ops->set_mmss)
err = rtc->ops->set_mmss(class_dev->dev, secs);
else if (rtc->ops->read_time && rtc->ops->set_time) {
struct rtc_time new, old;
err = rtc->ops->read_time(class_dev->dev, &old);
if (err == 0) {
rtc_time_to_tm(secs, &new);
/*
* avoid writing when we're going to change the day of
* the month. We will retry in the next minute. This
* basically means that if the RTC must not drift
* by more than 1 minute in 11 minutes.
*/
if (!((old.tm_hour == 23 && old.tm_min == 59) ||
(new.tm_hour == 23 && new.tm_min == 59)))
err = rtc->ops->set_time(class_dev->dev, &new);
}
}
else
err = -EINVAL;
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);
int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
{
int err;
struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return -EBUSY;
if (rtc->ops == NULL)
err = -ENODEV;
else if (!rtc->ops->read_alarm)
err = -EINVAL;
else {
memset(alarm, 0, sizeof(struct rtc_wkalrm));
err = rtc->ops->read_alarm(class_dev->dev, alarm);
}
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_read_alarm);
int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
{
int err;
struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return -EBUSY;
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->set_alarm)
err = -EINVAL;
else
err = rtc->ops->set_alarm(class_dev->dev, alarm);
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_alarm);
void rtc_update_irq(struct class_device *class_dev,
unsigned long num, unsigned long events)
{
struct rtc_device *rtc = to_rtc_device(class_dev);
spin_lock(&rtc->irq_lock);
rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
spin_unlock(&rtc->irq_lock);
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task)
rtc->irq_task->func(rtc->irq_task->private_data);
spin_unlock(&rtc->irq_task_lock);
wake_up_interruptible(&rtc->irq_queue);
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
}
EXPORT_SYMBOL_GPL(rtc_update_irq);
struct class_device *rtc_class_open(char *name)
{
struct class_device *class_dev = NULL,
*class_dev_tmp;
down(&rtc_class->sem);
list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
class_dev = class_dev_tmp;
break;
}
}
if (class_dev) {
if (!try_module_get(to_rtc_device(class_dev)->owner))
class_dev = NULL;
}
up(&rtc_class->sem);
return class_dev;
}
EXPORT_SYMBOL_GPL(rtc_class_open);
void rtc_class_close(struct class_device *class_dev)
{
module_put(to_rtc_device(class_dev)->owner);
}
EXPORT_SYMBOL_GPL(rtc_class_close);
int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
{
int retval = -EBUSY;
struct rtc_device *rtc = to_rtc_device(class_dev);
if (task == NULL || task->func == NULL)
return -EINVAL;
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task == NULL) {
rtc->irq_task = task;
retval = 0;
}
spin_unlock(&rtc->irq_task_lock);
return retval;
}
EXPORT_SYMBOL_GPL(rtc_irq_register);
void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
{
struct rtc_device *rtc = to_rtc_device(class_dev);
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task == task)
rtc->irq_task = NULL;
spin_unlock(&rtc->irq_task_lock);
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
{
int err = 0;
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(class_dev);
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != task)
err = -ENXIO;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0)
err = rtc->ops->irq_set_state(class_dev->dev, enabled);
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
{
int err = 0, tmp = 0;
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(class_dev);
/* allowed range is 2-8192 */
if (freq < 2 || freq > 8192)
return -EINVAL;
/*
FIXME: this does not belong here, will move where appropriate
at a later stage. It cannot hurt right now, trust me :)
if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
return -EACCES;
*/
/* check if freq is a power of 2 */
while (freq > (1 << tmp))
tmp++;
if (freq != (1 << tmp))
return -EINVAL;
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != task)
err = -ENXIO;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0) {
err = rtc->ops->irq_set_freq(class_dev->dev, freq);
if (err == 0)
rtc->irq_freq = freq;
}
return err;
}

382
drivers/rtc/rtc-dev.c Normal file
View file

@ -0,0 +1,382 @@
/*
* RTC subsystem, dev interface
*
* Copyright (C) 2005 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* based on arch/arm/common/rtctime.c
*
* 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 <linux/module.h>
#include <linux/rtc.h>
static struct class *rtc_dev_class;
static dev_t rtc_devt;
#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
static int rtc_dev_open(struct inode *inode, struct file *file)
{
int err;
struct rtc_device *rtc = container_of(inode->i_cdev,
struct rtc_device, char_dev);
struct rtc_class_ops *ops = rtc->ops;
/* We keep the lock as long as the device is in use
* and return immediately if busy
*/
if (!(mutex_trylock(&rtc->char_lock)))
return -EBUSY;
file->private_data = &rtc->class_dev;
err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
if (err == 0) {
spin_lock_irq(&rtc->irq_lock);
rtc->irq_data = 0;
spin_unlock_irq(&rtc->irq_lock);
return 0;
}
/* something has gone wrong, release the lock */
mutex_unlock(&rtc->char_lock);
return err;
}
static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct rtc_device *rtc = to_rtc_device(file->private_data);
DECLARE_WAITQUEUE(wait, current);
unsigned long data;
ssize_t ret;
if (count < sizeof(unsigned long))
return -EINVAL;
add_wait_queue(&rtc->irq_queue, &wait);
do {
__set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&rtc->irq_lock);
data = rtc->irq_data;
rtc->irq_data = 0;
spin_unlock_irq(&rtc->irq_lock);
if (data != 0) {
ret = 0;
break;
}
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
break;
}
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
schedule();
} while (1);
set_current_state(TASK_RUNNING);
remove_wait_queue(&rtc->irq_queue, &wait);
if (ret == 0) {
/* Check for any data updates */
if (rtc->ops->read_callback)
data = rtc->ops->read_callback(rtc->class_dev.dev, data);
ret = put_user(data, (unsigned long __user *)buf);
if (ret == 0)
ret = sizeof(unsigned long);
}
return ret;
}
static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
{
struct rtc_device *rtc = to_rtc_device(file->private_data);
unsigned long data;
poll_wait(file, &rtc->irq_queue, wait);
data = rtc->irq_data;
return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
}
static int rtc_dev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err = 0;
struct class_device *class_dev = file->private_data;
struct rtc_device *rtc = to_rtc_device(class_dev);
struct rtc_class_ops *ops = rtc->ops;
struct rtc_time tm;
struct rtc_wkalrm alarm;
void __user *uarg = (void __user *) arg;
/* avoid conflicting IRQ users */
if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task)
err = -EBUSY;
spin_unlock(&rtc->irq_task_lock);
if (err < 0)
return err;
}
/* try the driver's ioctl interface */
if (ops->ioctl) {
err = ops->ioctl(class_dev->dev, cmd, arg);
if (err != -EINVAL)
return err;
}
/* if the driver does not provide the ioctl interface
* or if that particular ioctl was not implemented
* (-EINVAL), we will try to emulate here.
*/
switch (cmd) {
case RTC_ALM_READ:
err = rtc_read_alarm(class_dev, &alarm);
if (err < 0)
return err;
if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
return -EFAULT;
break;
case RTC_ALM_SET:
if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
return -EFAULT;
alarm.enabled = 0;
alarm.pending = 0;
alarm.time.tm_mday = -1;
alarm.time.tm_mon = -1;
alarm.time.tm_year = -1;
alarm.time.tm_wday = -1;
alarm.time.tm_yday = -1;
alarm.time.tm_isdst = -1;
err = rtc_set_alarm(class_dev, &alarm);
break;
case RTC_RD_TIME:
err = rtc_read_time(class_dev, &tm);
if (err < 0)
return err;
if (copy_to_user(uarg, &tm, sizeof(tm)))
return -EFAULT;
break;
case RTC_SET_TIME:
if (!capable(CAP_SYS_TIME))
return -EACCES;
if (copy_from_user(&tm, uarg, sizeof(tm)))
return -EFAULT;
err = rtc_set_time(class_dev, &tm);
break;
#if 0
case RTC_EPOCH_SET:
#ifndef rtc_epoch
/*
* There were no RTC clocks before 1900.
*/
if (arg < 1900) {
err = -EINVAL;
break;
}
if (!capable(CAP_SYS_TIME)) {
err = -EACCES;
break;
}
rtc_epoch = arg;
err = 0;
#endif
break;
case RTC_EPOCH_READ:
err = put_user(rtc_epoch, (unsigned long __user *)uarg);
break;
#endif
case RTC_WKALM_SET:
if (copy_from_user(&alarm, uarg, sizeof(alarm)))
return -EFAULT;
err = rtc_set_alarm(class_dev, &alarm);
break;
case RTC_WKALM_RD:
err = rtc_read_alarm(class_dev, &alarm);
if (err < 0)
return err;
if (copy_to_user(uarg, &alarm, sizeof(alarm)))
return -EFAULT;
break;
default:
err = -EINVAL;
break;
}
return err;
}
static int rtc_dev_release(struct inode *inode, struct file *file)
{
struct rtc_device *rtc = to_rtc_device(file->private_data);
if (rtc->ops->release)
rtc->ops->release(rtc->class_dev.dev);
mutex_unlock(&rtc->char_lock);
return 0;
}
static int rtc_dev_fasync(int fd, struct file *file, int on)
{
struct rtc_device *rtc = to_rtc_device(file->private_data);
return fasync_helper(fd, file, on, &rtc->async_queue);
}
static struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.ioctl = rtc_dev_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
};
/* insertion/removal hooks */
static int rtc_dev_add_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
int err = 0;
struct rtc_device *rtc = to_rtc_device(class_dev);
if (rtc->id >= RTC_DEV_MAX) {
dev_err(class_dev->dev, "too many RTCs\n");
return -EINVAL;
}
mutex_init(&rtc->char_lock);
spin_lock_init(&rtc->irq_lock);
init_waitqueue_head(&rtc->irq_queue);
cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner;
if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
cdev_del(&rtc->char_dev);
dev_err(class_dev->dev,
"failed to add char device %d:%d\n",
MAJOR(rtc_devt), rtc->id);
return -ENODEV;
}
rtc->rtc_dev = class_device_create(rtc_dev_class, NULL,
MKDEV(MAJOR(rtc_devt), rtc->id),
class_dev->dev, "rtc%d", rtc->id);
if (IS_ERR(rtc->rtc_dev)) {
dev_err(class_dev->dev, "cannot create rtc_dev device\n");
err = PTR_ERR(rtc->rtc_dev);
goto err_cdev_del;
}
dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n",
MAJOR(rtc->rtc_dev->devt),
MINOR(rtc->rtc_dev->devt));
return 0;
err_cdev_del:
cdev_del(&rtc->char_dev);
return err;
}
static void rtc_dev_remove_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
struct rtc_device *rtc = to_rtc_device(class_dev);
if (rtc->rtc_dev) {
dev_dbg(class_dev->dev, "removing char %d:%d\n",
MAJOR(rtc->rtc_dev->devt),
MINOR(rtc->rtc_dev->devt));
class_device_unregister(rtc->rtc_dev);
cdev_del(&rtc->char_dev);
}
}
/* interface registration */
static struct class_interface rtc_dev_interface = {
.add = &rtc_dev_add_device,
.remove = &rtc_dev_remove_device,
};
static int __init rtc_dev_init(void)
{
int err;
rtc_dev_class = class_create(THIS_MODULE, "rtc-dev");
if (IS_ERR(rtc_dev_class))
return PTR_ERR(rtc_dev_class);
err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
if (err < 0) {
printk(KERN_ERR "%s: failed to allocate char dev region\n",
__FILE__);
goto err_destroy_class;
}
err = rtc_interface_register(&rtc_dev_interface);
if (err < 0) {
printk(KERN_ERR "%s: failed to register the interface\n",
__FILE__);
goto err_unregister_chrdev;
}
return 0;
err_unregister_chrdev:
unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
err_destroy_class:
class_destroy(rtc_dev_class);
return err;
}
static void __exit rtc_dev_exit(void)
{
class_interface_unregister(&rtc_dev_interface);
class_destroy(rtc_dev_class);
unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
}
module_init(rtc_dev_init);
module_exit(rtc_dev_exit);
MODULE_AUTHOR("Alessandro Zummo <[email protected]>");
MODULE_DESCRIPTION("RTC class dev interface");
MODULE_LICENSE("GPL");

233
drivers/rtc/rtc-ds1672.c Normal file
View file

@ -0,0 +1,233 @@
/*
* An rtc/i2c driver for the Dallas DS1672
* Copyright 2005 Alessandro Zummo
*
* 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 <linux/module.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#define DRV_VERSION "0.2"
/* Addresses to scan: none. This chip cannot be detected. */
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD;
/* Registers */
#define DS1672_REG_CNT_BASE 0
#define DS1672_REG_CONTROL 4
#define DS1672_REG_TRICKLE 5
/* Prototypes */
static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
/*
* In the routines that deal directly with the ds1672 hardware, we use
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
* Epoch is initialized as 2000. Time is set to UTC.
*/
static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
unsigned long time;
unsigned char addr = DS1672_REG_CNT_BASE;
unsigned char buf[4];
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, &addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 4, buf }, /* read date */
};
/* read date registers */
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
return -EIO;
}
dev_dbg(&client->dev,
"%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
__FUNCTION__,
buf[0], buf[1], buf[2], buf[3]);
time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
rtc_time_to_tm(time, tm);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
return 0;
}
static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
{
int xfer;
unsigned char buf[5];
buf[0] = DS1672_REG_CNT_BASE;
buf[1] = secs & 0x000000FF;
buf[2] = (secs & 0x0000FF00) >> 8;
buf[3] = (secs & 0x00FF0000) >> 16;
buf[4] = (secs & 0xFF000000) >> 24;
xfer = i2c_master_send(client, buf, 5);
if (xfer != 5) {
dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
return -EIO;
}
return 0;
}
static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
unsigned long secs;
dev_dbg(&client->dev,
"%s: secs=%d, mins=%d, hours=%d, ",
"mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
rtc_tm_to_time(tm, &secs);
return ds1672_set_mmss(client, secs);
}
static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return ds1672_get_datetime(to_i2c_client(dev), tm);
}
static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
return ds1672_set_datetime(to_i2c_client(dev), tm);
}
static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
{
return ds1672_set_mmss(to_i2c_client(dev), secs);
}
static struct rtc_class_ops ds1672_rtc_ops = {
.read_time = ds1672_rtc_read_time,
.set_time = ds1672_rtc_set_time,
.set_mmss = ds1672_rtc_set_mmss,
};
static int ds1672_attach(struct i2c_adapter *adapter)
{
dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
return i2c_probe(adapter, &addr_data, ds1672_probe);
}
static int ds1672_detach(struct i2c_client *client)
{
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
dev_dbg(&client->dev, "%s\n", __FUNCTION__);
if (rtc)
rtc_device_unregister(rtc);
if ((err = i2c_detach_client(client)))
return err;
kfree(client);
return 0;
}
static struct i2c_driver ds1672_driver = {
.driver = {
.name = "ds1672",
},
.id = I2C_DRIVERID_DS1672,
.attach_adapter = &ds1672_attach,
.detach_client = &ds1672_detach,
};
static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
{
int err = 0;
struct i2c_client *client;
struct rtc_device *rtc;
dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
/* I2C client */
client->addr = address;
client->driver = &ds1672_driver;
client->adapter = adapter;
strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE);
/* Inform the i2c layer */
if ((err = i2c_attach_client(client)))
goto exit_kfree;
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
&ds1672_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
dev_err(&client->dev,
"unable to register the class device\n");
goto exit_detach;
}
i2c_set_clientdata(client, rtc);
return 0;
exit_detach:
i2c_detach_client(client);
exit_kfree:
kfree(client);
exit:
return err;
}
static int __init ds1672_init(void)
{
return i2c_add_driver(&ds1672_driver);
}
static void __exit ds1672_exit(void)
{
i2c_del_driver(&ds1672_driver);
}
MODULE_AUTHOR("Alessandro Zummo <[email protected]>");
MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(ds1672_init);
module_exit(ds1672_exit);

162
drivers/rtc/rtc-ep93xx.c Normal file
View file

@ -0,0 +1,162 @@
/*
* A driver for the RTC embedded in the Cirrus Logic EP93XX processors
* Copyright (c) 2006 Tower Technologies
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* 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 <linux/module.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <asm/hardware.h>
#define EP93XX_RTC_REG(x) (EP93XX_RTC_BASE + (x))
#define EP93XX_RTC_DATA EP93XX_RTC_REG(0x0000)
#define EP93XX_RTC_LOAD EP93XX_RTC_REG(0x000C)
#define EP93XX_RTC_SWCOMP EP93XX_RTC_REG(0x0108)
#define DRV_VERSION "0.2"
static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload,
unsigned short *delete)
{
unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP);
if (preload)
*preload = comp & 0xffff;
if (delete)
*delete = (comp >> 16) & 0x1f;
return 0;
}
static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned long time = __raw_readl(EP93XX_RTC_DATA);
rtc_time_to_tm(time, tm);
return 0;
}
static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
{
__raw_writel(secs + 1, EP93XX_RTC_LOAD);
return 0;
}
static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
int err;
unsigned long secs;
err = rtc_tm_to_time(tm, &secs);
if (err != 0)
return err;
return ep93xx_rtc_set_mmss(dev, secs);
}
static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
{
unsigned short preload, delete;
ep93xx_get_swcomp(dev, &preload, &delete);
seq_printf(seq, "24hr\t\t: yes\n");
seq_printf(seq, "preload\t\t: %d\n", preload);
seq_printf(seq, "delete\t\t: %d\n", delete);
return 0;
}
static struct rtc_class_ops ep93xx_rtc_ops = {
.read_time = ep93xx_rtc_read_time,
.set_time = ep93xx_rtc_set_time,
.set_mmss = ep93xx_rtc_set_mmss,
.proc = ep93xx_rtc_proc,
};
static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned short preload;
ep93xx_get_swcomp(dev, &preload, NULL);
return sprintf(buf, "%d\n", preload);
}
static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL);
static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned short delete;
ep93xx_get_swcomp(dev, NULL, &delete);
return sprintf(buf, "%d\n", delete);
}
static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL);
static int __devinit ep93xx_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc = rtc_device_register("ep93xx",
&dev->dev, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
dev_err(&dev->dev, "unable to register\n");
return PTR_ERR(rtc);
}
platform_set_drvdata(dev, rtc);
device_create_file(&dev->dev, &dev_attr_comp_preload);
device_create_file(&dev->dev, &dev_attr_comp_delete);
return 0;
}
static int __devexit ep93xx_rtc_remove(struct platform_device *dev)
{
struct rtc_device *rtc = platform_get_drvdata(dev);
if (rtc)
rtc_device_unregister(rtc);
platform_set_drvdata(dev, NULL);
return 0;
}
static struct platform_driver ep93xx_rtc_platform_driver = {
.driver = {
.name = "ep93xx-rtc",
.owner = THIS_MODULE,
},
.probe = ep93xx_rtc_probe,
.remove = __devexit_p(ep93xx_rtc_remove),
};
static int __init ep93xx_rtc_init(void)
{
return platform_driver_register(&ep93xx_rtc_platform_driver);
}
static void __exit ep93xx_rtc_exit(void)
{
platform_driver_unregister(&ep93xx_rtc_platform_driver);
}
MODULE_AUTHOR("Alessandro Zummo <[email protected]>");
MODULE_DESCRIPTION("EP93XX RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(ep93xx_rtc_init);
module_exit(ep93xx_rtc_exit);

Some files were not shown because too many files have changed in this diff Show more