mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
Merge ../linux-2.6
This commit is contained in:
commit
bac30d1a78
779 changed files with 22983 additions and 7760 deletions
|
|
@ -70,4 +70,6 @@ source "drivers/sn/Kconfig"
|
|||
|
||||
source "drivers/edac/Kconfig"
|
||||
|
||||
source "drivers/rtc/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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? */
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(®->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(®->list, &rh->quiesced_regions);
|
||||
} else {
|
||||
} else if (reg->state == RH_DIRTY) {
|
||||
reg->state = RH_CLEAN;
|
||||
list_add(®->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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
235
drivers/md/md.c
235
drivers/md/md.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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...
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
165
drivers/rtc/Kconfig
Normal 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
21
drivers/rtc/Makefile
Normal 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
145
drivers/rtc/class.c
Normal 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
69
drivers/rtc/hctosys.c
Normal 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
277
drivers/rtc/interface.c
Normal 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
382
drivers/rtc/rtc-dev.c
Normal 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
233
drivers/rtc/rtc-ds1672.c
Normal 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
162
drivers/rtc/rtc-ep93xx.c
Normal 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
Loading…
Reference in a new issue