diff options
Diffstat (limited to 'drivers')
140 files changed, 7797 insertions, 2157 deletions
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 4b65f74d66b..ce074f6f336 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -129,19 +129,6 @@ static DEFINE_SPINLOCK(mfm_lock); #define MAJOR_NR MFM_ACORN_MAJOR #define QUEUE (mfm_queue) #define CURRENT elv_next_request(mfm_queue) -/* - * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc - */ -#ifndef HDIO_GETGEO -#define HDIO_GETGEO 0x301 -struct hd_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; -#endif - /* * Configuration section @@ -1153,22 +1140,13 @@ static int mfm_initdrives(void) * The 'front' end of the mfm driver follows... */ -static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct mfm_info *p = inode->i_bdev->bd_disk->private_data; - struct hd_geometry *geo = (struct hd_geometry *) arg; - if (cmd != HDIO_GETGEO) - return -EINVAL; - if (!arg) - return -EINVAL; - if (put_user (p->heads, &geo->heads)) - return -EFAULT; - if (put_user (p->sectors, &geo->sectors)) - return -EFAULT; - if (put_user (p->cylinders, &geo->cylinders)) - return -EFAULT; - if (put_user (get_start_sect(inode->i_bdev), &geo->start)) - return -EFAULT; + struct mfm_info *p = bdev->bd_disk->private_data; + + geo->heads = p->heads; + geo->sectors = p->sectors; + geo->cylinders = p->cylinders; return 0; } @@ -1219,7 +1197,7 @@ void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack, static struct block_device_operations mfm_fops = { .owner = THIS_MODULE, - .ioctl = mfm_ioctl, + .getgeo = mfm_getgeo, }; /* diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e3cd0b16031..20c9a37643c 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -204,11 +204,13 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size, return AE_OK; } +EXPORT_SYMBOL_GPL(acpi_os_map_memory); void acpi_os_unmap_memory(void __iomem * virt, acpi_size size) { iounmap(virt); } +EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); #ifdef ACPI_FUTURE_USAGE acpi_status diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index c57e20dcb0f..074abc81ec3 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -2126,8 +2126,7 @@ static void process_rsq(ns_dev *card) if (!ns_rsqe_valid(card->rsq.next)) return; - while (ns_rsqe_valid(card->rsq.next)) - { + do { dequeue_rx(card, card->rsq.next); ns_rsqe_init(card->rsq.next); previous = card->rsq.next; @@ -2135,7 +2134,7 @@ static void process_rsq(ns_dev *card) card->rsq.next = card->rsq.base; else card->rsq.next++; - } + } while (ns_rsqe_valid(card->rsq.next)); writel((((u32) previous) - ((u32) card->rsq.base)), card->membase + RSQH); } diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 21097a39a05..4a7bb7dfce8 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -92,34 +92,28 @@ static int DAC960_open(struct inode *inode, struct file *file) return 0; } -static int DAC960_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; DAC960_Controller_T *p = disk->queue->queuedata; int drive_nr = (long)disk->private_data; - struct hd_geometry g; - struct hd_geometry __user *loc = (struct hd_geometry __user *)arg; - - if (cmd != HDIO_GETGEO || !loc) - return -EINVAL; if (p->FirmwareType == DAC960_V1_Controller) { - g.heads = p->V1.GeometryTranslationHeads; - g.sectors = p->V1.GeometryTranslationSectors; - g.cylinders = p->V1.LogicalDriveInformation[drive_nr]. - LogicalDriveSize / (g.heads * g.sectors); + geo->heads = p->V1.GeometryTranslationHeads; + geo->sectors = p->V1.GeometryTranslationSectors; + geo->cylinders = p->V1.LogicalDriveInformation[drive_nr]. + LogicalDriveSize / (geo->heads * geo->sectors); } else { DAC960_V2_LogicalDeviceInfo_T *i = p->V2.LogicalDeviceInformation[drive_nr]; switch (i->DriveGeometry) { case DAC960_V2_Geometry_128_32: - g.heads = 128; - g.sectors = 32; + geo->heads = 128; + geo->sectors = 32; break; case DAC960_V2_Geometry_255_63: - g.heads = 255; - g.sectors = 63; + geo->heads = 255; + geo->sectors = 63; break; default: DAC960_Error("Illegal Logical Device Geometry %d\n", @@ -127,12 +121,11 @@ static int DAC960_ioctl(struct inode *inode, struct file *file, return -EINVAL; } - g.cylinders = i->ConfigurableDeviceSize / (g.heads * g.sectors); + geo->cylinders = i->ConfigurableDeviceSize / + (geo->heads * geo->sectors); } - g.start = get_start_sect(inode->i_bdev); - - return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; + return 0; } static int DAC960_media_changed(struct gendisk *disk) @@ -157,7 +150,7 @@ static int DAC960_revalidate_disk(struct gendisk *disk) static struct block_device_operations DAC960_BlockDeviceOperations = { .owner = THIS_MODULE, .open = DAC960_open, - .ioctl = DAC960_ioctl, + .getgeo = DAC960_getgeo, .media_changed = DAC960_media_changed, .revalidate_disk = DAC960_revalidate_disk, }; @@ -3767,7 +3760,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command) if (SenseKey == DAC960_SenseKey_VendorSpecific && AdditionalSenseCode == 0x80 && AdditionalSenseCodeQualifier < - sizeof(DAC960_EventMessages) / sizeof(char *)) + ARRAY_SIZE(DAC960_EventMessages)) DAC960_Critical("Physical Device %d:%d %s\n", Controller, EventLogEntry->Channel, EventLogEntry->TargetID, diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 5d2d649f7e8..196c0ec9cd5 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1079,6 +1079,19 @@ static void redo_acsi_request( void ) * ***********************************************************************/ +static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct acsi_info_struct *aip = bdev->bd_disk->private_data; + + /* + * Just fake some geometry here, it's nonsense anyway + * To make it easy, use Adaptec's usual 64/32 mapping + */ + geo->heads = 64; + geo->sectors = 32; + geo->cylinders = aip->size >> 11; + return 0; +} static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) @@ -1086,18 +1099,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file, struct gendisk *disk = inode->i_bdev->bd_disk; struct acsi_info_struct *aip = disk->private_data; switch (cmd) { - case HDIO_GETGEO: - /* HDIO_GETGEO is supported more for getting the partition's - * start sector... */ - { struct hd_geometry *geo = (struct hd_geometry *)arg; - /* just fake some geometry here, it's nonsense anyway; to make it - * easy, use Adaptec's usual 64/32 mapping */ - put_user( 64, &geo->heads ); - put_user( 32, &geo->sectors ); - put_user( aip->size >> 11, &geo->cylinders ); - put_user(get_start_sect(inode->i_bdev), &geo->start); - return 0; - } case SCSI_IOCTL_GET_IDLUN: /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ put_user( aip->target | (aip->lun << 8), @@ -1592,6 +1593,7 @@ static struct block_device_operations acsi_fops = { .open = acsi_open, .release = acsi_release, .ioctl = acsi_ioctl, + .getgeo = acsi_getgeo, .media_changed = acsi_media_change, .revalidate_disk= acsi_revalidate, }; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 0acbfff8ad2..3c679d30b69 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -131,7 +131,7 @@ static struct fd_drive_type drive_types[] = { { FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2}, { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; -static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); +static int num_dr_types = ARRAY_SIZE(drive_types); static int amiga_read(int), dos_read(int); static void amiga_write(int), dos_write(int); @@ -1424,6 +1424,16 @@ static void do_fd_request(request_queue_t * q) redo_fd_request(); } +static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + int drive = MINOR(bdev->bd_dev) & 3; + + geo->heads = unit[drive].type->heads; + geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; + geo->cylinders = unit[drive].type->tracks; + return 0; +} + static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { @@ -1431,18 +1441,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, static struct floppy_struct getprm; switch(cmd){ - case HDIO_GETGEO: - { - struct hd_geometry loc; - loc.heads = unit[drive].type->heads; - loc.sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; - loc.cylinders = unit[drive].type->tracks; - loc.start = 0; - if (copy_to_user((void *)param, (void *)&loc, - sizeof(struct hd_geometry))) - return -EFAULT; - break; - } case FDFMTBEG: get_fdc(drive); if (fd_ref[drive] > 1) { @@ -1652,6 +1650,7 @@ static struct block_device_operations floppy_fops = { .open = floppy_open, .release = floppy_release, .ioctl = fd_ioctl, + .getgeo = fd_getgeo, .media_changed = amiga_floppy_change, }; diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 0e97fcb9f3a..c05ee8bffd9 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -169,38 +169,26 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio) return 0; } -/* This ioctl implementation expects userland to have the device node - * permissions set so that only priviledged users can open an aoe - * block device directly. - */ static int -aoeblk_ioctl(struct inode *inode, struct file *filp, uint cmd, ulong arg) +aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct aoedev *d; - - if (!arg) - return -EINVAL; + struct aoedev *d = bdev->bd_disk->private_data; - d = inode->i_bdev->bd_disk->private_data; if ((d->flags & DEVFL_UP) == 0) { printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n"); return -ENODEV; } - if (cmd == HDIO_GETGEO) { - d->geo.start = get_start_sect(inode->i_bdev); - if (!copy_to_user((void __user *) arg, &d->geo, sizeof d->geo)) - return 0; - return -EFAULT; - } - printk(KERN_INFO "aoe: aoeblk_ioctl: unknown ioctl %d\n", cmd); - return -EINVAL; + geo->cylinders = d->geo.cylinders; + geo->heads = d->geo.heads; + geo->sectors = d->geo.sectors; + return 0; } static struct block_device_operations aoe_bdops = { .open = aoeblk_open, .release = aoeblk_release, - .ioctl = aoeblk_ioctl, + .getgeo = aoeblk_getgeo, .owner = THIS_MODULE, }; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 22bda05fc69..3aa68a5447d 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -181,7 +181,7 @@ static struct { { 6, TYPE_HD }, /* 31: H1640 <- was H1600 == h1600 for PC */ }; -#define NUM_DISK_MINORS (sizeof(minor2disktype)/sizeof(*minor2disktype)) +#define NUM_DISK_MINORS ARRAY_SIZE(minor2disktype) /* * Maximum disk size (in kilobytes). This default is used whenever the diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d2815b7a915..e4e9f255bd1 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1,6 +1,6 @@ /* * Disk Array driver for HP SA 5xxx and 6xxx Controllers - * Copyright 2000, 2005 Hewlett-Packard Development Company, L.P. + * Copyright 2000, 2006 Hewlett-Packard Development Company, L.P. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,12 +47,12 @@ #include <linux/completion.h> #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 2.6.8)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8) +#define DRIVER_NAME "HP CISS Driver (v 2.6.10)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,10) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.10"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" " SA6i P600 P800 P400 P400i E200 E200i"); MODULE_LICENSE("GPL"); @@ -103,7 +103,7 @@ static const struct pci_device_id cciss_pci_device_id[] = { }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); -#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) +#define NR_PRODUCTS ARRAY_SIZE(products) /* board_id = Subsystem Device ID & Vendor ID * product = Marketing Name for the board @@ -153,6 +153,7 @@ static int cciss_open(struct inode *inode, struct file *filep); static int cciss_release(struct inode *inode, struct file *filep); static int cciss_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int revalidate_allvol(ctlr_info_t *host); static int cciss_revalidate(struct gendisk *disk); @@ -166,7 +167,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv); static void cciss_getgeometry(int cntl_num); - +static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32); static void start_io( ctlr_info_t *h); static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, @@ -194,6 +195,7 @@ static struct block_device_operations cciss_fops = { .open = cciss_open, .release = cciss_release, .ioctl = cciss_ioctl, + .getgeo = cciss_getgeo, #ifdef CONFIG_COMPAT .compat_ioctl = cciss_compat_ioctl, #endif @@ -282,7 +284,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, h->product_name, (unsigned long)h->board_id, h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], - (unsigned int)h->intr, + (unsigned int)h->intr[SIMPLE_MODE_INT], h->num_luns, h->Qdepth, h->commands_outstanding, h->maxQsinceinit, h->max_outstanding, h->maxSG); @@ -633,6 +635,20 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned return err; } #endif + +static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + drive_info_struct *drv = get_drv(bdev->bd_disk); + + if (!drv->cylinders) + return -ENXIO; + + geo->heads = drv->heads; + geo->sectors = drv->sectors; + geo->cylinders = drv->cylinders; + return 0; +} + /* * ioctl */ @@ -651,21 +667,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, #endif /* CCISS_DEBUG */ switch(cmd) { - case HDIO_GETGEO: - { - struct hd_geometry driver_geo; - if (drv->cylinders) { - driver_geo.heads = drv->heads; - driver_geo.sectors = drv->sectors; - driver_geo.cylinders = drv->cylinders; - } else - return -ENXIO; - driver_geo.start= get_start_sect(inode->i_bdev); - if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry))) - return -EFAULT; - return(0); - } - case CCISS_GETPCIINFO: { cciss_pci_info_struct pciinfo; @@ -2177,16 +2178,48 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c) start_io(h); } + +static void cciss_softirq_done(struct request *rq) +{ + CommandList_struct *cmd = rq->completion_data; + ctlr_info_t *h = hba[cmd->ctlr]; + u64bit temp64; + int i, ddir; + + if (cmd->Request.Type.Direction == XFER_READ) + ddir = PCI_DMA_FROMDEVICE; + else + ddir = PCI_DMA_TODEVICE; + + /* command did not need to be retried */ + /* unmap the DMA mapping for all the scatter gather elements */ + for(i=0; i<cmd->Header.SGList; i++) { + temp64.val32.lower = cmd->SG[i].Addr.lower; + temp64.val32.upper = cmd->SG[i].Addr.upper; + pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); + } + + complete_buffers(rq->bio, rq->errors); + +#ifdef CCISS_DEBUG + printk("Done with %p\n", rq); +#endif /* CCISS_DEBUG */ + + spin_lock_irq(&h->lock); + end_that_request_last(rq, rq->errors); + cmd_free(h, cmd,1); + spin_unlock_irq(&h->lock); +} + /* checks the status of the job and calls complete buffers to mark all - * buffers for the completed job. + * buffers for the completed job. Note that this function does not need + * to hold the hba/queue lock. */ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, int timeout) { int status = 1; - int i; int retry_cmd = 0; - u64bit temp64; if (timeout) status = 0; @@ -2294,24 +2327,10 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, resend_cciss_cmd(h,cmd); return; } - /* command did not need to be retried */ - /* unmap the DMA mapping for all the scatter gather elements */ - for(i=0; i<cmd->Header.SGList; i++) { - temp64.val32.lower = cmd->SG[i].Addr.lower; - temp64.val32.upper = cmd->SG[i].Addr.upper; - pci_unmap_page(hba[cmd->ctlr]->pdev, - temp64.val, cmd->SG[i].Len, - (cmd->Request.Type.Direction == XFER_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - } - complete_buffers(cmd->rq->bio, status); -#ifdef CCISS_DEBUG - printk("Done with %p\n", cmd->rq); -#endif /* CCISS_DEBUG */ - - end_that_request_last(cmd->rq, status ? 1 : -EIO); - cmd_free(h,cmd,1); + cmd->rq->completion_data = cmd; + cmd->rq->errors = status; + blk_complete_request(cmd->rq); } /* @@ -2661,6 +2680,60 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, return -1; } +/* If MSI/MSI-X is supported by the kernel we will try to enable it on + * controllers that are capable. If not, we use IO-APIC mode. + */ + +static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id) +{ +#ifdef CONFIG_PCI_MSI + int err; + struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1}, + {0,2}, {0,3}}; + + /* Some boards advertise MSI but don't really support it */ + if ((board_id == 0x40700E11) || + (board_id == 0x40800E11) || + (board_id == 0x40820E11) || + (board_id == 0x40830E11)) + goto default_int_mode; + + if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { + err = pci_enable_msix(pdev, cciss_msix_entries, 4); + if (!err) { + c->intr[0] = cciss_msix_entries[0].vector; + c->intr[1] = cciss_msix_entries[1].vector; + c->intr[2] = cciss_msix_entries[2].vector; + c->intr[3] = cciss_msix_entries[3].vector; + c->msix_vector = 1; + return; + } + if (err > 0) { + printk(KERN_WARNING "cciss: only %d MSI-X vectors " + "available\n", err); + } else { + printk(KERN_WARNING "cciss: MSI-X init failed %d\n", + err); + } + } + if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) { + if (!pci_enable_msi(pdev)) { + c->intr[SIMPLE_MODE_INT] = pdev->irq; + c->msi_vector = 1; + return; + } else { + printk(KERN_WARNING "cciss: MSI init failed\n"); + c->intr[SIMPLE_MODE_INT] = pdev->irq; + return; + } + } +#endif /* CONFIG_PCI_MSI */ + /* if we get here we're going to use the default interrupt mode */ +default_int_mode: + c->intr[SIMPLE_MODE_INT] = pdev->irq; + return; +} + static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; @@ -2721,7 +2794,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = pdev->irq; +/* If the kernel supports MSI/MSI-X we will try to enable that functionality, + * else we use the IO-APIC interrupt assigned to us by system ROM. + */ + cciss_interrupt_mode(c, pdev, board_id); /* * Memory base addr is first addr , the second points to the config @@ -2775,7 +2851,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) c->board_id = board_id; #ifdef CCISS_DEBUG - print_cfg_table(c->cfgtable); + print_cfg_table(c->cfgtable); #endif /* CCISS_DEBUG */ for(i=0; i<NR_PRODUCTS; i++) { @@ -3060,7 +3136,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, * 8 controller support. */ if (i < MAX_CTLR_ORIG) - hba[i]->major = MAJOR_NR + i; + hba[i]->major = COMPAQ_CISS_MAJOR + i; rc = register_blkdev(hba[i]->major, hba[i]->devname); if(rc == -EBUSY || rc == -EINVAL) { printk(KERN_ERR @@ -3075,11 +3151,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, /* make sure the board interrupts are off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); - if( request_irq(hba[i]->intr, do_cciss_intr, + if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr, SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, hba[i]->devname, hba[i])) { printk(KERN_ERR "cciss: Unable to get irq %d for %s\n", - hba[i]->intr, hba[i]->devname); + hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname); goto clean2; } hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL); @@ -3141,15 +3217,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, drv->queue = q; q->backing_dev_info.ra_pages = READ_AHEAD; - blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); - /* This is a hardware imposed limit. */ - blk_queue_max_hw_segments(q, MAXSGENTRIES); + /* This is a hardware imposed limit. */ + blk_queue_max_hw_segments(q, MAXSGENTRIES); - /* This is a limit in the driver and could be eliminated. */ - blk_queue_max_phys_segments(q, MAXSGENTRIES); + /* This is a limit in the driver and could be eliminated. */ + blk_queue_max_phys_segments(q, MAXSGENTRIES); - blk_queue_max_sectors(q, 512); + blk_queue_max_sectors(q, 512); + + blk_queue_softirq_done(q, cciss_softirq_done); q->queuedata = hba[i]; sprintf(disk->disk_name, "cciss/c%dd%d", i, j); @@ -3185,7 +3263,7 @@ clean4: NR_CMDS * sizeof( ErrorInfo_struct), hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle); - free_irq(hba[i]->intr, hba[i]); + free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]); clean2: unregister_blkdev(hba[i]->major, hba[i]->devname); clean1: @@ -3226,7 +3304,15 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) printk(KERN_WARNING "Error Flushing cache on controller %d\n", i); } - free_irq(hba[i]->intr, hba[i]); + free_irq(hba[i]->intr[2], hba[i]); + +#ifdef CONFIG_PCI_MSI + if (hba[i]->msix_vector) + pci_disable_msix(hba[i]->pdev); + else if (hba[i]->msi_vector) + pci_disable_msi(hba[i]->pdev); +#endif /* CONFIG_PCI_MSI */ + pci_set_drvdata(pdev, NULL); iounmap(hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 3b0858c8389..b24fc0553cc 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -13,8 +13,6 @@ #define IO_OK 0 #define IO_ERROR 1 -#define MAJOR_NR COMPAQ_CISS_MAJOR - struct ctlr_info; typedef struct ctlr_info ctlr_info_t; @@ -65,7 +63,6 @@ struct ctlr_info unsigned long io_mem_addr; unsigned long io_mem_length; CfgTable_struct __iomem *cfgtable; - unsigned int intr; int interrupts_enabled; int major; int max_commands; @@ -74,6 +71,13 @@ struct ctlr_info int num_luns; int highest_lun; int usage_count; /* number of opens all all minor devices */ +# define DOORBELL_INT 0 +# define PERF_MODE_INT 1 +# define SIMPLE_MODE_INT 2 +# define MEMQ_MODE_INT 3 + unsigned int intr[4]; + unsigned int msix_vector; + unsigned int msi_vector; // information about each logical volume drive_info_struct drv[CISS_MAX_LUN]; diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 2942d32280a..9e35de05d5c 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -714,7 +714,7 @@ cciss_scsi_detect(int ctlr) ((struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh; sh->hostdata[0] = (unsigned long) hba[ctlr]; - sh->irq = hba[ctlr]->intr; + sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT]; sh->unique_id = sh->irq; error = scsi_add_host(sh, &hba[ctlr]->pdev->dev); if (error) diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 9bddb687487..862b9abac0a 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -72,11 +72,11 @@ static ctlr_info_t *hba[MAX_CTLR]; static int eisa[8]; -#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) +#define NR_PRODUCTS ARRAY_SIZE(products) /* board_id = Subsystem Device ID & Vendor ID * product = Marketing Name for the board - * access = Address of the struct of function pointers + * access = Address of the struct of function pointers */ static struct board_type products[] = { { 0x0040110E, "IDA", &smart1_access }, @@ -160,6 +160,7 @@ static int sendcmd( static int ida_open(struct inode *inode, struct file *filep); static int ida_release(struct inode *inode, struct file *filep); static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io); static void do_ida_request(request_queue_t *q); @@ -199,6 +200,7 @@ static struct block_device_operations ida_fops = { .open = ida_open, .release = ida_release, .ioctl = ida_ioctl, + .getgeo = ida_getgeo, .revalidate_disk= ida_revalidate, }; @@ -1124,6 +1126,23 @@ static void ida_timer(unsigned long tdata) h->misc_tflags = 0; } +static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + drv_info_t *drv = get_drv(bdev->bd_disk); + + if (drv->cylinders) { + geo->heads = drv->heads; + geo->sectors = drv->sectors; + geo->cylinders = drv->cylinders; + } else { + geo->heads = 0xff; + geo->sectors = 0x3f; + geo->cylinders = drv->nr_blks / (0xff*0x3f); + } + + return 0; +} + /* * ida_ioctl does some miscellaneous stuff like reporting drive geometry, * setting readahead and submitting commands from userspace to the controller. @@ -1133,27 +1152,10 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, drv_info_t *drv = get_drv(inode->i_bdev->bd_disk); ctlr_info_t *host = get_host(inode->i_bdev->bd_disk); int error; - int diskinfo[4]; - struct hd_geometry __user *geo = (struct hd_geometry __user *)arg; ida_ioctl_t __user *io = (ida_ioctl_t __user *)arg; ida_ioctl_t *my_io; switch(cmd) { - case HDIO_GETGEO: - if (drv->cylinders) { - diskinfo[0] = drv->heads; - diskinfo[1] = drv->sectors; - diskinfo[2] = drv->cylinders; - } else { - diskinfo[0] = 0xff; - diskinfo[1] = 0x3f; - diskinfo[2] = drv->nr_blks / (0xff*0x3f); - } - put_user(diskinfo[0], &geo->heads); - put_user(diskinfo[1], &geo->sectors); - put_user(diskinfo[2], &geo->cylinders); - put_user(get_start_sect(inode->i_bdev), &geo->start); - return 0; case IDAGETDRVINFO: if (copy_to_user(&io->c.drv, drv, sizeof(drv_info_t))) return -EFAULT; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a5b857c5c4b..374621a512e 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -479,7 +479,6 @@ static struct floppy_struct floppy_type[32] = { { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */ }; -#define NUMBER(x) (sizeof(x) / sizeof(*(x))) #define SECTSIZE (_FD_SECTSIZE(*floppy)) /* Auto-detection: Disk type used until the next media change occurs. */ @@ -3445,6 +3444,23 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g) return 0; } +static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + int drive = (long)bdev->bd_disk->private_data; + int type = ITYPE(drive_state[drive].fd_device); + struct floppy_struct *g; + int ret; + + ret = get_floppy_geometry(drive, type, &g); + if (ret) + return ret; + + geo->heads = g->head; + geo->sectors = g->sect; + geo->cylinders = g->track; + return 0; +} + static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param) { @@ -3474,23 +3490,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, cmd = FDEJECT; } - /* generic block device ioctls */ - switch (cmd) { - /* the following have been inspired by the corresponding - * code for other block devices. */ - struct floppy_struct *g; - case HDIO_GETGEO: - { - struct hd_geometry loc; - ECALL(get_floppy_geometry(drive, type, &g)); - loc.heads = g->head; - loc.sectors = g->sect; - loc.cylinders = g->track; - loc.start = 0; - return _COPYOUT(loc); - } - } - /* convert the old style command into a new style command */ if ((cmd & 0xff00) == 0x0200) { ECALL(normalize_ioctl(&cmd, &size)); @@ -3645,7 +3644,7 @@ static void __init config_types(void) const char *name = NULL; static char temparea[32]; - if (type < NUMBER(default_drive_params)) { + if (type < ARRAY_SIZE(default_drive_params)) { params = &default_drive_params[type].params; if (type) { name = default_drive_params[type].name; @@ -3938,6 +3937,7 @@ static struct block_device_operations floppy_fops = { .open = floppy_open, .release = floppy_release, .ioctl = fd_ioctl, + .getgeo = fd_getgeo, .media_changed = check_floppy_change, .revalidate_disk = floppy_revalidate, }; @@ -3960,7 +3960,7 @@ static void __init register_devfs_entries(int drive) { int base_minor = (drive < 4) ? drive : (124 + drive); - if (UDP->cmos < NUMBER(default_drive_params)) { + if (UDP->cmos < ARRAY_SIZE(default_drive_params)) { int i = 0; do { int minor = base_minor + (table_sup[UDP->cmos][i] << 2); @@ -4218,7 +4218,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) !(allowed_drive_mask & (1 << drive)) || fdc_state[FDC(drive)].version == FDC_NONE) return NULL; - if (((*part >> 2) & 0x1f) >= NUMBER(floppy_type)) + if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type)) return NULL; *part = 0; return get_disk(disks[drive]); @@ -4570,7 +4570,7 @@ static void unregister_devfs_entries(int drive) { int i; - if (UDP->cmos < NUMBER(default_drive_params)) { + if (UDP->cmos < ARRAY_SIZE(default_drive_params)) { i = 0; do { devfs_remove("floppy/%d%s", drive, diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 33d6f237b2e..6997d8e6bfb 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -174,7 +174,6 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_namelen = 0; msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (send) diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index fa49d62626b..62d2464c12f 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -747,32 +747,33 @@ static int pd_open(struct inode *inode, struct file *file) return 0; } +static int pd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct pd_unit *disk = bdev->bd_disk->private_data; + + if (disk->alt_geom) { + geo->heads = PD_LOG_HEADS; + geo->sectors = PD_LOG_SECTS; + geo->cylinders = disk->capacity / (geo->heads * geo->sectors); + } else { + geo->heads = disk->heads; + geo->sectors = disk->sectors; + geo->cylinders = disk->cylinders; + } + + return 0; +} + static int pd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct pd_unit *disk = inode->i_bdev->bd_disk->private_data; - struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; - struct hd_geometry g; switch (cmd) { case CDROMEJECT: if (disk->access == 1) pd_special_command(disk, pd_eject); return 0; - case HDIO_GETGEO: - if (disk->alt_geom) { - g.heads = PD_LOG_HEADS; - g.sectors = PD_LOG_SECTS; - g.cylinders = disk->capacity / (g.heads * g.sectors); - } else { - g.heads = disk->heads; - g.sectors = disk->sectors; - g.cylinders = disk->cylinders; - } - g.start = get_start_sect(inode->i_bdev); - if (copy_to_user(geo, &g, sizeof(struct hd_geometry))) - return -EFAULT; - return 0; default: return -EINVAL; } @@ -815,6 +816,7 @@ static struct block_device_operations pd_fops = { .open = pd_open, .release = pd_release, .ioctl = pd_ioctl, + .getgeo = pd_getgeo, .media_changed = pd_check_media, .revalidate_disk= pd_revalidate }; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index e9746af29b9..852b564e903 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -205,6 +205,7 @@ static int pf_open(struct inode *inode, struct file *file); static void do_pf_request(request_queue_t * q); static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int pf_release(struct inode *inode, struct file *file); @@ -266,6 +267,7 @@ static struct block_device_operations pf_fops = { .open = pf_open, .release = pf_release, .ioctl = pf_ioctl, + .getgeo = pf_getgeo, .media_changed = pf_check_media, }; @@ -313,34 +315,34 @@ static int pf_open(struct inode *inode, struct file *file) return 0; } -static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; - struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; - struct hd_geometry g; - sector_t capacity; - - if (cmd == CDROMEJECT) { - if (pf->access == 1) { - pf_eject(pf); - return 0; - } - return -EBUSY; - } - if (cmd != HDIO_GETGEO) - return -EINVAL; - capacity = get_capacity(pf->disk); + struct pf_unit *pf = bdev->bd_disk->private_data; + sector_t capacity = get_capacity(pf->disk); + if (capacity < PF_FD_MAX) { - g.cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); - g.heads = PF_FD_HDS; - g.sectors = PF_FD_SPT; + geo->cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); + geo->heads = PF_FD_HDS; + geo->sectors = PF_FD_SPT; } else { - g.cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); - g.heads = PF_HD_HDS; - g.sectors = PF_HD_SPT; + geo->cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); + geo->heads = PF_HD_HDS; + geo->sectors = PF_HD_SPT; } - if (copy_to_user(geo, &g, sizeof(g))) - return -EFAULT; + + return 0; +} + +static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; + + if (cmd != CDROMEJECT) + return -EINVAL; + + if (pf->access != 1) + return -EBUSY; + pf_eject(pf); return 0; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index c0233efabeb..51b7a5c5b77 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1955,9 +1955,12 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY))) goto out; + if ((ret = bd_claim(pd->bdev, pd))) + goto out_putdev; + if ((ret = pkt_get_last_written(pd, &lba))) { printk("pktcdvd: pkt_get_last_written failed\n"); - goto out_putdev; + goto out_unclaim; } set_capacity(pd->disk, lba << 2); @@ -1967,7 +1970,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) q = bdev_get_queue(pd->bdev); if (write) { if ((ret = pkt_open_write(pd))) - goto out_putdev; + goto out_unclaim; /* * Some CDRW drives can not handle writes larger than one packet, * even if the size is a multiple of the packet size. @@ -1982,13 +1985,15 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write) } if ((ret = pkt_set_segment_merging(pd, q))) - goto out_putdev; + goto out_unclaim; if (write) printk("pktcdvd: %lukB available on disc\n", lba << 1); return 0; +out_unclaim: + bd_release(pd->bdev); out_putdev: blkdev_put(pd->bdev); out: @@ -2007,6 +2012,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush) pkt_lock_door(pd, 0); pkt_set_speed(pd, MAX_SPEED, MAX_SPEED); + bd_release(pd->bdev); blkdev_put(pd->bdev); } diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 29d1518be72..43415f69839 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -81,8 +81,7 @@ static void (*current_int_handler) (u_int) = NULL; static void ps2esdi_normal_interrupt_handler(u_int); static void ps2esdi_initial_reset_int_handler(u_int); static void ps2esdi_geometry_int_handler(u_int); -static int ps2esdi_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg); +static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer); @@ -132,7 +131,7 @@ static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] = static struct block_device_operations ps2esdi_fops = { .owner = THIS_MODULE, - .ioctl = ps2esdi_ioctl, + .getgeo = ps2esdi_getgeo, }; static struct gendisk *ps2esdi_gendisk[2]; @@ -1058,21 +1057,13 @@ static void dump_cmd_complete_status(u_int int_ret_code) } -static int ps2esdi_ioctl(struct inode *inode, - struct file *file, u_int cmd, u_long arg) +static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data; - struct ps2esdi_geometry geom; - - if (cmd != HDIO_GETGEO) - return -EINVAL; - memset(&geom, 0, sizeof(geom)); - geom.heads = p->head; - geom.sectors = p->sect; - geom.cylinders = p->cyl; - geom.start = get_start_sect(inode->i_bdev); - if (copy_to_user((void __user *)arg, &geom, sizeof(geom))) - return -EFAULT; + struct ps2esdi_i_struct *p = bdev->bd_disk->private_data; + + geo->heads = p->head; + geo->sectors = p->sect; + geo->cylinders = p->cyl; return 0; } diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 9251f4131b5..c0cdc182a8b 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -407,8 +407,7 @@ struct carm_array_info { static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void carm_remove_one (struct pci_dev *pdev); -static int carm_bdev_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg); +static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo); static struct pci_device_id carm_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, @@ -426,7 +425,7 @@ static struct pci_driver carm_driver = { static struct block_device_operations carm_bd_ops = { .owner = THIS_MODULE, - .ioctl = carm_bdev_ioctl, + .getgeo = carm_bdev_getgeo, }; static unsigned int carm_host_id; @@ -434,32 +433,14 @@ static unsigned long carm_major_alloc; -static int carm_bdev_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg) +static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - void __user *usermem = (void __user *) arg; - struct carm_port *port = ino->i_bdev->bd_disk->private_data; - struct hd_geometry geom; + struct carm_port *port = bdev->bd_disk->private_data; - switch (cmd) { - case HDIO_GETGEO: - if (!usermem) - return -EINVAL; - - geom.heads = (u8) port->dev_geom_head; - geom.sectors = (u8) port->dev_geom_sect; - geom.cylinders = port->dev_geom_cyl; - geom.start = get_start_sect(ino->i_bdev); - - if (copy_to_user(usermem, &geom, sizeof(geom))) - return -EFAULT; - return 0; - - default: - break; - } - - return -EOPNOTSUPP; + geo->heads = (u8) port->dev_geom_head; + geo->sectors = (u8) port->dev_geom_sect; + geo->cylinders = port->dev_geom_cyl; + return 0; } static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 0f48301342d..15299e7a1ad 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -809,34 +809,23 @@ static int mm_revalidate(struct gendisk *disk) set_capacity(disk, card->mm_size << 1); return 0; } -/* ------------------------------------------------------------------------------------ --- mm_ioctl ------------------------------------------------------------------------------------ -*/ -static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) + +static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - if (cmd == HDIO_GETGEO) { - struct cardinfo *card = i->i_bdev->bd_disk->private_data; - int size = card->mm_size * (1024 / MM_HARDSECT); - struct hd_geometry geo; - /* - * get geometry: we have to fake one... trim the size to a - * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, - * whatever cylinders. - */ - geo.heads = 64; - geo.sectors = 32; - geo.start = get_start_sect(i->i_bdev); - geo.cylinders = size / (geo.heads * geo.sectors); - - if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) - return -EFAULT; - return 0; - } + struct cardinfo *card = bdev->bd_disk->private_data; + int size = card->mm_size * (1024 / MM_HARDSECT); - return -EINVAL; + /* + * get geometry: we have to fake one... trim the size to a + * multiple of 2048 (1M): tell we have 32 sectors, 64 heads, + * whatever cylinders. + */ + geo->heads = 64; + geo->sectors = 32; + geo->cylinders = size / (geo->heads * geo->sectors); + return 0; } + /* ----------------------------------------------------------------------------------- -- mm_check_change @@ -855,7 +844,7 @@ static int mm_check_change(struct gendisk *disk) */ static struct block_device_operations mm_fops = { .owner = THIS_MODULE, - .ioctl = mm_ioctl, + .getgeo = mm_getgeo, .revalidate_disk= mm_revalidate, .media_changed = mm_check_change, }; diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 063f0304a16..d1aaf31bd97 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -247,43 +247,17 @@ static int viodasd_release(struct inode *ino, struct file *fil) /* External ioctl entry point. */ -static int viodasd_ioctl(struct inode *ino, struct file *fil, - unsigned int cmd, unsigned long arg) +static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - unsigned char sectors; - unsigned char heads; - unsigned short cylinders; - struct hd_geometry *geo; - struct gendisk *gendisk; - struct viodasd_device *d; + struct gendisk *disk = bdev->bd_disk; + struct viodasd_device *d = disk->private_data; - switch (cmd) { - case HDIO_GETGEO: - geo = (struct hd_geometry *)arg; - if (geo == NULL) - return -EINVAL; - if (!access_ok(VERIFY_WRITE, geo, sizeof(*geo))) - return -EFAULT; - gendisk = ino->i_bdev->bd_disk; - d = gendisk->private_data; - sectors = d->sectors; - if (sectors == 0) - sectors = 32; - heads = d->tracks; - if (heads == 0) - heads = 64; - cylinders = d->cylinders; - if (cylinders == 0) - cylinders = get_capacity(gendisk) / (sectors * heads); - if (__put_user(sectors, &geo->sectors) || - __put_user(heads, &geo->heads) || - __put_user(cylinders, &geo->cylinders) || - __put_user(get_start_sect(ino->i_bdev), &geo->start)) - return -EFAULT; - return 0; - } + geo->sectors = d->sectors ? d->sectors : 0; + geo->heads = d->tracks ? d->tracks : 64; + geo->cylinders = d->cylinders ? d->cylinders : + get_capacity(disk) / (geo->cylinders * geo->heads); - return -EINVAL; + return 0; } /* @@ -293,7 +267,7 @@ static struct block_device_operations viodasd_fops = { .owner = THIS_MODULE, .open = viodasd_open, .release = viodasd_release, - .ioctl = viodasd_ioctl, + .getgeo = viodasd_getgeo, }; /* diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 68b6d7b154c..cbce7c5e944 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -128,9 +128,12 @@ static DEFINE_SPINLOCK(xd_lock); static struct gendisk *xd_gendisk[2]; +static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo); + static struct block_device_operations xd_fops = { .owner = THIS_MODULE, .ioctl = xd_ioctl, + .getgeo = xd_getgeo, }; static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; @@ -276,11 +279,11 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address) return(1); } - for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])); i++) { + for (i = 0; i < ARRAY_SIZE(xd_bases); i++) { void __iomem *p = ioremap(xd_bases[i], 0x2000); if (!p) continue; - for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])); j++) { + for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) { const char *s = xd_sigs[j].string; if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) { *controller = j; @@ -330,22 +333,20 @@ static void do_xd_request (request_queue_t * q) } } +static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + XD_INFO *p = bdev->bd_disk->private_data; + + geo->heads = p->heads; + geo->sectors = p->sectors; + geo->cylinders = p->cylinders; + return 0; +} + /* xd_ioctl: handle device ioctl's */ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) { - XD_INFO *p = inode->i_bdev->bd_disk->private_data; - switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry g; - struct hd_geometry __user *geom= (void __user *)arg; - g.heads = p->heads; - g.sectors = p->sectors; - g.cylinders = p->cylinders; - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(geom, &g, sizeof(g)) ? -EFAULT : 0; - } case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; @@ -1017,7 +1018,7 @@ static void __init do_xd_setup (int *integers) case 2: if ((integers[2] > 0) && (integers[2] < 16)) xd_irq = integers[2]; case 1: xd_override = 1; - if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0])))) + if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs))) xd_type = integers[1]; case 0: break; default:printk("xd: too many parameters for xd\n"); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 5ebd06b1b4c..dd7e6901c57 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -220,6 +220,14 @@ config SYNCLINKMP The module will be called synclinkmp. If you want to do that, say M here. +config SYNCLINK_GT + tristate "SyncLink GT/AC support" + depends on SERIAL_NONSTANDARD + help + Support for SyncLink GT and SyncLink AC families of + synchronous and asynchronous serial adapters + manufactured by Microgate Systems, Ltd. (www.microgate.com) + config N_HDLC tristate "HDLC line discipline support" depends on SERIAL_NONSTANDARD @@ -687,7 +695,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) + depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -735,7 +743,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC + depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4aeae687e88..d973d14d8f7 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_RISCOM8) += riscom8.o obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o +obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 3f8f7fa6b0f..268f78d926d 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -7,6 +7,7 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include <linux/agp_backend.h> #include "agp.h" diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c index 49769f59ea1..b3bc2e37e61 100644 --- a/drivers/char/hw_random.c +++ b/drivers/char/hw_random.c @@ -169,6 +169,7 @@ static struct pci_device_id rng_pci_tbl[] = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, + { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 91dd669273e..5b2d1803507 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -101,6 +101,11 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t *count) return 1; } + +static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t *size) +{ + return 1; +} #endif /* @@ -228,26 +233,36 @@ static ssize_t write_mem(struct file * file, const char __user * buf, return written; } +#ifndef __HAVE_PHYS_MEM_ACCESS_PROT +static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot) +{ +#ifdef pgprot_noncached + unsigned long offset = pfn << PAGE_SHIFT; + + if (uncached_access(file, offset)) + return pgprot_noncached(vma_prot); +#endif + return vma_prot; +} +#endif + static int mmap_mem(struct file * file, struct vm_area_struct * vma) { -#if defined(__HAVE_PHYS_MEM_ACCESS_PROT) + size_t size = vma->vm_end - vma->vm_start; + + if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, &size)) + return -EINVAL; + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, - vma->vm_end - vma->vm_start, + size, vma->vm_page_prot); -#elif defined(pgprot_noncached) - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int uncached; - - uncached = uncached_access(file, offset); - if (uncached) - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end-vma->vm_start, + size, vma->vm_page_prot)) return -EAGAIN; return 0; @@ -817,7 +832,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { char *tmp; - int ret; + ssize_t ret; tmp = kmalloc(count + 1, GFP_KERNEL); if (tmp == NULL) @@ -826,6 +841,9 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf, if (!copy_from_user(tmp, buf, count)) { tmp[count] = 0; ret = printk("%s", tmp); + if (ret > count) + /* printk can add a prefix */ + ret = count; } kfree(tmp); return ret; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 51a07370e63..f8dd8527c6a 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -471,7 +471,6 @@ struct sonypi_keypress { static struct sonypi_device { struct pci_dev *dev; - struct platform_device *pdev; u16 irq; u16 bits; u16 ioport1; @@ -511,6 +510,11 @@ static struct sonypi_device { #define SONYPI_ACPI_ACTIVE 0 #endif /* CONFIG_ACPI */ +#ifdef CONFIG_ACPI +static struct acpi_device *sonypi_acpi_device; +static int acpi_enabled; +#endif + static int sonypi_ec_write(u8 addr, u8 value) { #ifdef CONFIG_ACPI_EC @@ -864,6 +868,11 @@ found: if (useinput) sonypi_report_input_event(event); +#ifdef CONFIG_ACPI + if (acpi_enabled) + acpi_bus_generate_event(sonypi_acpi_device, 1, event); +#endif + kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); wake_up_interruptible(&sonypi_device.fifo_proc_list); @@ -1165,45 +1174,38 @@ static int sonypi_disable(void) return 0; } -#ifdef CONFIG_PM -static int old_camera_power; - -static int sonypi_suspend(struct platform_device *dev, pm_message_t state) +#ifdef CONFIG_ACPI +static int sonypi_acpi_add(struct acpi_device *device) { - old_camera_power = sonypi_device.camera_power; - sonypi_disable(); - + sonypi_acpi_device = device; + strcpy(acpi_device_name(device), "Sony laptop hotkeys"); + strcpy(acpi_device_class(device), "sony/hotkey"); return 0; } -static int sonypi_resume(struct platform_device *dev) +static int sonypi_acpi_remove(struct acpi_device *device, int type) { - sonypi_enable(old_camera_power); + sonypi_acpi_device = NULL; return 0; } -#endif - -static void sonypi_shutdown(struct platform_device *dev) -{ - sonypi_disable(); -} -static struct platform_driver sonypi_driver = { -#ifdef CONFIG_PM - .suspend = sonypi_suspend, - .resume = sonypi_resume, -#endif - .shutdown = sonypi_shutdown, - .driver = { - .name = "sonypi", +static struct acpi_driver sonypi_acpi_driver = { + .name = "sonypi", + .class = "hkey", + .ids = "SNY6001", + .ops = { + .add = sonypi_acpi_add, + .remove = sonypi_acpi_remove, }, }; +#endif static int __devinit sonypi_create_input_devices(void) { struct input_dev *jog_dev; struct input_dev *key_dev; int i; + int error; sonypi_device.input_jog_dev = jog_dev = input_allocate_device(); if (!jog_dev) @@ -1219,9 +1221,8 @@ static int __devinit sonypi_create_input_devices(void) sonypi_device.input_key_dev = key_dev = input_allocate_device(); if (!key_dev) { - input_free_device(jog_dev); - sonypi_device.input_jog_dev = NULL; - return -ENOMEM; + error = -ENOMEM; + goto err_free_jogdev; } key_dev->name = "Sony Vaio Keys"; @@ -1234,56 +1235,122 @@ static int __devinit sonypi_create_input_devices(void) if (sonypi_inputkeys[i].inputev) set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); - input_register_device(jog_dev); - input_register_device(key_dev); + error = input_register_device(jog_dev); + if (error) + goto err_free_keydev; + + error = input_register_device(key_dev); + if (error) + goto err_unregister_jogdev; return 0; + + err_unregister_jogdev: + input_unregister_device(jog_dev); + /* Set to NULL so we don't free it again below */ + jog_dev = NULL; + err_free_keydev: + input_free_device(key_dev); + sonypi_device.input_key_dev = NULL; + err_free_jogdev: + input_free_device(jog_dev); + sonypi_device.input_jog_dev = NULL; + + return error; } -static int __devinit sonypi_probe(void) +static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, + const struct sonypi_ioport_list *ioport_list) { - int i, ret; - struct sonypi_ioport_list *ioport_list; - struct sonypi_irq_list *irq_list; - struct pci_dev *pcidev; + while (ioport_list->port1) { - if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) - sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; - else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) - sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; - else - sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; + if (request_region(ioport_list->port1, + sonypi_device.region_size, + "Sony Programable I/O Device")) { + dev->ioport1 = ioport_list->port1; + dev->ioport2 = ioport_list->port2; + return 0; + } + ioport_list++; + } - sonypi_device.dev = pcidev; + return -EBUSY; +} + +static int __devinit sonypi_setup_irq(struct sonypi_device *dev, + const struct sonypi_irq_list *irq_list) +{ + while (irq_list->irq) { + + if (!request_irq(irq_list->irq, sonypi_irq, + SA_SHIRQ, "sonypi", sonypi_irq)) { + dev->irq = irq_list->irq; + dev->bits = irq_list->bits; + return 0; + } + irq_list++; + } + + return -EBUSY; +} + +static void __devinit sonypi_display_info(void) +{ + printk(KERN_INFO "sonypi: detected type%d model, " + "verbose = %d, fnkeyinit = %s, camera = %s, " + "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", + sonypi_device.model, + verbose, + fnkeyinit ? "on" : "off", + camera ? "on" : "off", + compat ? "on" : "off", + mask, + useinput ? "on" : "off", + SONYPI_ACPI_ACTIVE ? "on" : "off"); + printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", + sonypi_device.irq, + sonypi_device.ioport1, sonypi_device.ioport2); + + if (minor == -1) + printk(KERN_INFO "sonypi: device allocated minor is %d\n", + sonypi_misc_device.minor); +} + +static int __devinit sonypi_probe(struct platform_device *dev) +{ + const struct sonypi_ioport_list *ioport_list; + const struct sonypi_irq_list *irq_list; + struct pci_dev *pcidev; + int error; spin_lock_init(&sonypi_device.fifo_lock); sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, &sonypi_device.fifo_lock); if (IS_ERR(sonypi_device.fifo)) { printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); - ret = PTR_ERR(sonypi_device.fifo); - goto out_fifo; + return PTR_ERR(sonypi_device.fifo); } init_waitqueue_head(&sonypi_device.fifo_proc_list); init_MUTEX(&sonypi_device.lock); sonypi_device.bluetooth_power = -1; + if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; + if (pcidev && pci_enable_device(pcidev)) { printk(KERN_ERR "sonypi: pci_enable_device failed\n"); - ret = -EIO; - goto out_pcienable; - } - - if (minor != -1) - sonypi_misc_device.minor = minor; - if ((ret = misc_register(&sonypi_misc_device))) { - printk(KERN_ERR "sonypi: misc_register failed\n"); - goto out_miscreg; + error = -EIO; + goto err_put_pcidev; } + sonypi_device.dev = pcidev; if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { ioport_list = sonypi_type1_ioport_list; @@ -1302,43 +1369,36 @@ static int __devinit sonypi_probe(void) irq_list = sonypi_type3_irq_list; } - for (i = 0; ioport_list[i].port1; i++) { - if (request_region(ioport_list[i].port1, - sonypi_device.region_size, - "Sony Programable I/O Device")) { - /* get the ioport */ - sonypi_device.ioport1 = ioport_list[i].port1; - sonypi_device.ioport2 = ioport_list[i].port2; - break; - } - } - if (!sonypi_device.ioport1) { - printk(KERN_ERR "sonypi: request_region failed\n"); - ret = -ENODEV; - goto out_reqreg; + error = sonypi_setup_ioports(&sonypi_device, ioport_list); + if (error) { + printk(KERN_ERR "sonypi: failed to request ioports\n"); + goto err_disable_pcidev; } - for (i = 0; irq_list[i].irq; i++) { - - sonypi_device.irq = irq_list[i].irq; - sonypi_device.bits = irq_list[i].bits; - - if (!request_irq(sonypi_device.irq, sonypi_irq, - SA_SHIRQ, "sonypi", sonypi_irq)) - break; + error = sonypi_setup_irq(&sonypi_device, irq_list); + if (error) { + printk(KERN_ERR "sonypi: request_irq failed\n"); + goto err_free_ioports; } - if (!irq_list[i].irq) { - printk(KERN_ERR "sonypi: request_irq failed\n"); - ret = -ENODEV; - goto out_reqirq; + if (minor != -1) + sonypi_misc_device.minor = minor; + error = misc_register(&sonypi_misc_device); + if (error) { + printk(KERN_ERR "sonypi: misc_register failed\n"); + goto err_free_irq; } + sonypi_display_info(); + if (useinput) { - ret = sonypi_create_input_devices(); - if (ret) - goto out_inputdevices; + error = sonypi_create_input_devices(); + if (error) { + printk(KERN_ERR + "sonypi: failed to create input devices\n"); + goto err_miscdev_unregister; + } spin_lock_init(&sonypi_device.input_fifo_lock); sonypi_device.input_fifo = @@ -1346,91 +1406,104 @@ static int __devinit sonypi_probe(void) &sonypi_device.input_fifo_lock); if (IS_ERR(sonypi_device.input_fifo)) { printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); - ret = PTR_ERR(sonypi_device.input_fifo); - goto out_infifo; + error = PTR_ERR(sonypi_device.input_fifo); + goto err_inpdev_unregister; } INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); } - sonypi_device.pdev = platform_device_register_simple("sonypi", -1, - NULL, 0); - if (IS_ERR(sonypi_device.pdev)) { - ret = PTR_ERR(sonypi_device.pdev); - goto out_platformdev; - } - sonypi_enable(0); - printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver" - "v%s.\n", SONYPI_DRIVER_VERSION); - printk(KERN_INFO "sonypi: detected type%d model, " - "verbose = %d, fnkeyinit = %s, camera = %s, " - "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", - sonypi_device.model, - verbose, - fnkeyinit ? "on" : "off", - camera ? "on" : "off", - compat ? "on" : "off", - mask, - useinput ? "on" : "off", - SONYPI_ACPI_ACTIVE ? "on" : "off"); - printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", - sonypi_device.irq, - sonypi_device.ioport1, sonypi_device.ioport2); - - if (minor == -1) - printk(KERN_INFO "sonypi: device allocated minor is %d\n", - sonypi_misc_device.minor); - return 0; -out_platformdev: - kfifo_free(sonypi_device.input_fifo); -out_infifo: + err_inpdev_unregister: input_unregister_device(sonypi_device.input_key_dev); input_unregister_device(sonypi_device.input_jog_dev); -out_inputdevices: + err_miscdev_unregister: + misc_deregister(&sonypi_misc_device); + err_free_irq: free_irq(sonypi_device.irq, sonypi_irq); -out_reqirq: + err_free_ioports: release_region(sonypi_device.ioport1, sonypi_device.region_size); -out_reqreg: - misc_deregister(&sonypi_misc_device); -out_miscreg: + err_disable_pcidev: if (pcidev) pci_disable_device(pcidev); -out_pcienable: + err_put_pcidev: + pci_dev_put(pcidev); kfifo_free(sonypi_device.fifo); -out_fifo: - pci_dev_put(sonypi_device.dev); - return ret; + + return error; } -static void __devexit sonypi_remove(void) +static int __devexit sonypi_remove(struct platform_device *dev) { sonypi_disable(); synchronize_sched(); /* Allow sonypi interrupt to complete. */ flush_scheduled_work(); - platform_device_unregister(sonypi_device.pdev); - if (useinput) { input_unregister_device(sonypi_device.input_key_dev); input_unregister_device(sonypi_device.input_jog_dev); kfifo_free(sonypi_device.input_fifo); } + misc_deregister(&sonypi_misc_device); + free_irq(sonypi_device.irq, sonypi_irq); release_region(sonypi_device.ioport1, sonypi_device.region_size); - misc_deregister(&sonypi_misc_device); - if (sonypi_device.dev) + + if (sonypi_device.dev) { pci_disable_device(sonypi_device.dev); + pci_dev_put(sonypi_device.dev); + } + kfifo_free(sonypi_device.fifo); - pci_dev_put(sonypi_device.dev); - printk(KERN_INFO "sonypi: removed.\n"); + + return 0; } +#ifdef CONFIG_PM +static int old_camera_power; + +static int sonypi_suspend(struct platform_device *dev, pm_message_t state) +{ + old_camera_power = sonypi_device.camera_power; + sonypi_disable(); + + return 0; +} + +static int sonypi_resume(struct platform_device *dev) +{ + sonypi_enable(old_camera_power); + return 0; +} +#else +#define sonypi_suspend NULL +#define sonypi_resume NULL +#endif + +static void sonypi_shutdown(struct platform_device *dev) +{ + sonypi_disable(); +} + +static struct platform_driver sonypi_driver = { + .driver = { + .name = "sonypi", + .owner = THIS_MODULE, + }, + .probe = sonypi_probe, + .remove = __devexit_p(sonypi_remove), + .shutdown = sonypi_shutdown, + .suspend = sonypi_suspend, + .resume = sonypi_resume, +}; + +static struct platform_device *sonypi_platform_device; + static struct dmi_system_id __initdata sonypi_dmi_table[] = { { .ident = "Sony Vaio", @@ -1451,26 +1524,52 @@ static struct dmi_system_id __initdata sonypi_dmi_table[] = { static int __init sonypi_init(void) { - int ret; + int error; + + printk(KERN_INFO + "sonypi: Sony Programmable I/O Controller Driver v%s.\n", + SONYPI_DRIVER_VERSION); if (!dmi_check_system(sonypi_dmi_table)) return -ENODEV; - ret = platform_driver_register(&sonypi_driver); - if (ret) - return ret; + error = platform_driver_register(&sonypi_driver); + if (error) + return error; - ret = sonypi_probe(); - if (ret) - platform_driver_unregister(&sonypi_driver); + sonypi_platform_device = platform_device_alloc("sonypi", -1); + if (!sonypi_platform_device) { + error = -ENOMEM; + goto err_driver_unregister; + } - return ret; + error = platform_device_add(sonypi_platform_device); + if (error) + goto err_free_device; + +#ifdef CONFIG_ACPI + if (acpi_bus_register_driver(&sonypi_acpi_driver) > 0) + acpi_enabled = 1; +#endif + + return 0; + + err_free_device: + platform_device_put(sonypi_platform_device); + err_driver_unregister: + platform_driver_unregister(&sonypi_driver); + return error; } static void __exit sonypi_exit(void) { +#ifdef CONFIG_ACPI + if (acpi_enabled) + acpi_bus_unregister_driver(&sonypi_acpi_driver); +#endif + platform_device_unregister(sonypi_platform_device); platform_driver_unregister(&sonypi_driver); - sonypi_remove(); + printk(KERN_INFO "sonypi: removed.\n"); } module_init(sonypi_init); diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c new file mode 100644 index 00000000000..2b9cde94e2f --- /dev/null +++ b/drivers/char/synclink_gt.c @@ -0,0 +1,4501 @@ +/* + * $Id: synclink_gt.c,v 4.20 2005/11/08 19:51:55 paulkf Exp $ + * + * Device driver for Microgate SyncLink GT serial adapters. + * + * written by Paul Fulghum for Microgate Corporation + * paulkf@microgate.com + * + * Microgate and SyncLink are trademarks of Microgate Corporation + * + * This code is released under the GNU General Public License (GPL) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * DEBUG OUTPUT DEFINITIONS + * + * uncomment lines below to enable specific types of debug output + * + * DBGINFO information - most verbose output + * DBGERR serious errors + * DBGBH bottom half service routine debugging + * DBGISR interrupt service routine debugging + * DBGDATA output receive and transmit data + * DBGTBUF output transmit DMA buffers and registers + * DBGRBUF output receive DMA buffers and registers + */ + +#define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt +#define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt +#define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt +#define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt +#define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label)) +//#define DBGTBUF(info) dump_tbufs(info) +//#define DBGRBUF(info) dump_rbufs(info) + + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/netdevice.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/ioctl.h> +#include <linux/termios.h> +#include <linux/bitops.h> +#include <linux/workqueue.h> +#include <linux/hdlc.h> + +#include <asm/serial.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/types.h> +#include <asm/uaccess.h> + +#include "linux/synclink.h" + +#ifdef CONFIG_HDLC_MODULE +#define CONFIG_HDLC 1 +#endif + +/* + * module identification + */ +static char *driver_name = "SyncLink GT"; +static char *driver_version = "$Revision: 4.20 $"; +static char *tty_driver_name = "synclink_gt"; +static char *tty_dev_prefix = "ttySLG"; +MODULE_LICENSE("GPL"); +#define MGSL_MAGIC 0x5401 +#define MAX_DEVICES 12 + +static struct pci_device_id pci_table[] = { + {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + {0,}, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, pci_table); + +static int init_one(struct pci_dev *dev,const struct pci_device_id *ent); +static void remove_one(struct pci_dev *dev); +static struct pci_driver pci_driver = { + .name = "synclink_gt", + .id_table = pci_table, + .probe = init_one, + .remove = __devexit_p(remove_one), +}; + +static int pci_registered; + +/* + * module configuration and status + */ +static struct slgt_info *slgt_device_list; +static int slgt_device_count; + +static int ttymajor; +static int debug_level; +static int maxframe[MAX_DEVICES]; +static int dosyncppp[MAX_DEVICES]; + +module_param(ttymajor, int, 0); +module_param(debug_level, int, 0); +module_param_array(maxframe, int, NULL, 0); +module_param_array(dosyncppp, int, NULL, 0); + +MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned"); +MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail"); +MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); +MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable"); + +/* + * tty support and callbacks + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +static struct tty_driver *serial_driver; + +static int open(struct tty_struct *tty, struct file * filp); +static void close(struct tty_struct *tty, struct file * filp); +static void hangup(struct tty_struct *tty); +static void set_termios(struct tty_struct *tty, struct termios *old_termios); + +static int write(struct tty_struct *tty, const unsigned char *buf, int count); +static void put_char(struct tty_struct *tty, unsigned char ch); +static void send_xchar(struct tty_struct *tty, char ch); +static void wait_until_sent(struct tty_struct *tty, int timeout); +static int write_room(struct tty_struct *tty); +static void flush_chars(struct tty_struct *tty); +static void flush_buffer(struct tty_struct *tty); +static void tx_hold(struct tty_struct *tty); +static void tx_release(struct tty_struct *tty); + +static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data); +static int chars_in_buffer(struct tty_struct *tty); +static void throttle(struct tty_struct * tty); +static void unthrottle(struct tty_struct * tty); +static void set_break(struct tty_struct *tty, int break_state); + +/* + * generic HDLC support and callbacks + */ +#ifdef CONFIG_HDLC +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +static void hdlcdev_tx_done(struct slgt_info *info); +static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); +static int hdlcdev_init(struct slgt_info *info); +static void hdlcdev_exit(struct slgt_info *info); +#endif + + +/* + * device specific structures, macros and functions + */ + +#define SLGT_MAX_PORTS 4 +#define SLGT_REG_SIZE 256 + +/* + * DMA buffer descriptor and access macros + */ +struct slgt_desc +{ + unsigned short count; + unsigned short status; + unsigned int pbuf; /* physical address of data buffer */ + unsigned int next; /* physical address of next descriptor */ + + /* driver book keeping */ + char *buf; /* virtual address of data buffer */ + unsigned int pdesc; /* physical address of this descriptor */ + dma_addr_t buf_dma_addr; +}; + +#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b)) +#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b)) +#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b)) +#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0)) +#define desc_count(a) (le16_to_cpu((a).count)) +#define desc_status(a) (le16_to_cpu((a).status)) +#define desc_complete(a) (le16_to_cpu((a).status) & BIT15) +#define desc_eof(a) (le16_to_cpu((a).status) & BIT2) +#define desc_crc_error(a) (le16_to_cpu((a).status) & BIT1) +#define desc_abort(a) (le16_to_cpu((a).status) & BIT0) +#define desc_residue(a) ((le16_to_cpu((a).status) & 0x38) >> 3) + +struct _input_signal_events { + int ri_up; + int ri_down; + int dsr_up; + int dsr_down; + int dcd_up; + int dcd_down; + int cts_up; + int cts_down; +}; + +/* + * device instance data structure + */ +struct slgt_info { + void *if_ptr; /* General purpose pointer (used by SPPP) */ + + struct slgt_info *next_device; /* device list link */ + + int magic; + int flags; + + char device_name[25]; + struct pci_dev *pdev; + + int port_count; /* count of ports on adapter */ + int adapter_num; /* adapter instance number */ + int port_num; /* port instance number */ + + /* array of pointers to port contexts on this adapter */ + struct slgt_info *port_array[SLGT_MAX_PORTS]; + + int count; /* count of opens */ + int line; /* tty line instance number */ + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + + struct mgsl_icount icount; + + struct tty_struct *tty; + int timeout; + int x_char; /* xon/xoff character */ + int blocked_open; /* # of blocked opens */ + unsigned int read_status_mask; + unsigned int ignore_status_mask; + + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + wait_queue_head_t status_event_wait_q; + wait_queue_head_t event_wait_q; + struct timer_list tx_timer; + struct timer_list rx_timer; + + spinlock_t lock; /* spinlock for synchronizing with ISR */ + + struct work_struct task; + u32 pending_bh; + int bh_requested; + int bh_running; + + int isr_overflow; + int irq_requested; /* nonzero if IRQ requested */ + int irq_occurred; /* for diagnostics use */ + + /* device configuration */ + + unsigned int bus_type; + unsigned int irq_level; + unsigned long irq_flags; + + unsigned char __iomem * reg_addr; /* memory mapped registers address */ + u32 phys_reg_addr; + u32 reg_offset; + int reg_addr_requested; + + MGSL_PARAMS params; /* communications parameters */ + u32 idle_mode; + u32 max_frame_size; /* as set by device config */ + + unsigned int raw_rx_size; + unsigned int if_mode; + + /* device status */ + + int rx_enabled; + int rx_restart; + + int tx_enabled; + int tx_active; + + unsigned char signals; /* serial signal states */ + unsigned int init_error; /* initialization error */ + + unsigned char *tx_buf; + int tx_count; + + char flag_buf[MAX_ASYNC_BUFFER_SIZE]; + char char_buf[MAX_ASYNC_BUFFER_SIZE]; + BOOLEAN drop_rts_on_tx_done; + struct _input_signal_events input_signal_events; + + int dcd_chkcount; /* check counts to prevent */ + int cts_chkcount; /* too many IRQs if a signal */ + int dsr_chkcount; /* is floating */ + int ri_chkcount; + + char *bufs; /* virtual address of DMA buffer lists */ + dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */ + + unsigned int rbuf_count; + struct slgt_desc *rbufs; + unsigned int rbuf_current; + unsigned int rbuf_index; + + unsigned int tbuf_count; + struct slgt_desc *tbufs; + unsigned int tbuf_current; + unsigned int tbuf_start; + + unsigned char *tmp_rbuf; + unsigned int tmp_rbuf_count; + + /* SPPP/Cisco HDLC device parts */ + + int netcount; + int dosyncppp; + spinlock_t netlock; +#ifdef CONFIG_HDLC + struct net_device *netdev; +#endif + +}; + +static MGSL_PARAMS default_params = { + .mode = MGSL_MODE_HDLC, + .loopback = 0, + .flags = HDLC_FLAG_UNDERRUN_ABORT15, + .encoding = HDLC_ENCODING_NRZI_SPACE, + .clock_speed = 0, + .addr_filter = 0xff, + .crc_type = HDLC_CRC_16_CCITT, + .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS, + .preamble = HDLC_PREAMBLE_PATTERN_NONE, + .data_rate = 9600, + .data_bits = 8, + .stop_bits = 1, + .parity = ASYNC_PARITY_NONE +}; + + +#define BH_RECEIVE 1 +#define BH_TRANSMIT 2 +#define BH_STATUS 4 +#define IO_PIN_SHUTDOWN_LIMIT 100 + +#define DMABUFSIZE 256 +#define DESC_LIST_SIZE 4096 + +#define MASK_PARITY BIT1 +#define MASK_FRAMING BIT2 +#define MASK_BREAK BIT3 +#define MASK_OVERRUN BIT4 + +#define GSR 0x00 /* global status */ +#define TDR 0x80 /* tx data */ +#define RDR 0x80 /* rx data */ +#define TCR 0x82 /* tx control */ +#define TIR 0x84 /* tx idle */ +#define TPR 0x85 /* tx preamble */ +#define RCR 0x86 /* rx control */ +#define VCR 0x88 /* V.24 control */ +#define CCR 0x89 /* clock control */ +#define BDR 0x8a /* baud divisor */ +#define SCR 0x8c /* serial control */ +#define SSR 0x8e /* serial status */ +#define RDCSR 0x90 /* rx DMA control/status */ +#define TDCSR 0x94 /* tx DMA control/status */ +#define RDDAR 0x98 /* rx DMA descriptor address */ +#define TDDAR 0x9c /* tx DMA descriptor address */ + +#define RXIDLE BIT14 +#define RXBREAK BIT14 +#define IRQ_TXDATA BIT13 +#define IRQ_TXIDLE BIT12 +#define IRQ_TXUNDER BIT11 /* HDLC */ +#define IRQ_RXDATA BIT10 +#define IRQ_RXIDLE BIT9 /* HDLC */ +#define IRQ_RXBREAK BIT9 /* async */ +#define IRQ_RXOVER BIT8 +#define IRQ_DSR BIT7 +#define IRQ_CTS BIT6 +#define IRQ_DCD BIT5 +#define IRQ_RI BIT4 +#define IRQ_ALL 0x3ff0 +#define IRQ_MASTER BIT0 + +#define slgt_irq_on(info, mask) \ + wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask))) +#define slgt_irq_off(info, mask) \ + wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask))) + +static __u8 rd_reg8(struct slgt_info *info, unsigned int addr); +static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value); +static __u16 rd_reg16(struct slgt_info *info, unsigned int addr); +static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value); +static __u32 rd_reg32(struct slgt_info *info, unsigned int addr); +static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value); + +static void msc_set_vcr(struct slgt_info *info); + +static int startup(struct slgt_info *info); +static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info); +static void shutdown(struct slgt_info *info); +static void program_hw(struct slgt_info *info); +static void change_params(struct slgt_info *info); + +static int register_test(struct slgt_info *info); +static int irq_test(struct slgt_info *info); +static int loopback_test(struct slgt_info *info); +static int adapter_test(struct slgt_info *info); + +static void reset_adapter(struct slgt_info *info); +static void reset_port(struct slgt_info *info); +static void async_mode(struct slgt_info *info); +static void hdlc_mode(struct slgt_info *info); + +static void rx_stop(struct slgt_info *info); +static void rx_start(struct slgt_info *info); +static void reset_rbufs(struct slgt_info *info); +static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); +static void rdma_reset(struct slgt_info *info); +static int rx_get_frame(struct slgt_info *info); +static int rx_get_buf(struct slgt_info *info); + +static void tx_start(struct slgt_info *info); +static void tx_stop(struct slgt_info *info); +static void tx_set_idle(struct slgt_info *info); +static unsigned int free_tbuf_count(struct slgt_info *info); +static void reset_tbufs(struct slgt_info *info); +static void tdma_reset(struct slgt_info *info); +static void tx_load(struct slgt_info *info, const char *buf, unsigned int count); + +static void get_signals(struct slgt_info *info); +static void set_signals(struct slgt_info *info); +static void enable_loopback(struct slgt_info *info); +static void set_rate(struct slgt_info *info, u32 data_rate); + +static int bh_action(struct slgt_info *info); +static void bh_handler(void* context); +static void bh_transmit(struct slgt_info *info); +static void isr_serial(struct slgt_info *info); +static void isr_rdma(struct slgt_info *info); +static void isr_txeom(struct slgt_info *info, unsigned short status); +static void isr_tdma(struct slgt_info *info); +static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs); + +static int alloc_dma_bufs(struct slgt_info *info); +static void free_dma_bufs(struct slgt_info *info); +static int alloc_desc(struct slgt_info *info); +static void free_desc(struct slgt_info *info); +static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); +static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); + +static int alloc_tmp_rbuf(struct slgt_info *info); +static void free_tmp_rbuf(struct slgt_info *info); + +static void tx_timeout(unsigned long context); +static void rx_timeout(unsigned long context); + +/* + * ioctl handlers + */ +static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount); +static int get_params(struct slgt_info *info, MGSL_PARAMS __user *params); +static int set_params(struct slgt_info *info, MGSL_PARAMS __user *params); +static int get_txidle(struct slgt_info *info, int __user *idle_mode); +static int set_txidle(struct slgt_info *info, int idle_mode); +static int tx_enable(struct slgt_info *info, int enable); +static int tx_abort(struct slgt_info *info); +static int rx_enable(struct slgt_info *info, int enable); +static int modem_input_wait(struct slgt_info *info,int arg); +static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr); +static int tiocmget(struct tty_struct *tty, struct file *file); +static int tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear); +static void set_break(struct tty_struct *tty, int break_state); +static int get_interface(struct slgt_info *info, int __user *if_mode); +static int set_interface(struct slgt_info *info, int if_mode); + +/* + * driver functions + */ +static void add_device(struct slgt_info *info); +static void device_init(int adapter_num, struct pci_dev *pdev); +static int claim_resources(struct slgt_info *info); +static void release_resources(struct slgt_info *info); + +/* + * DEBUG OUTPUT CODE + */ +#ifndef DBGINFO +#define DBGINFO(fmt) +#endif +#ifndef DBGERR +#define DBGERR(fmt) +#endif +#ifndef DBGBH +#define DBGBH(fmt) +#endif +#ifndef DBGISR +#define DBGISR(fmt) +#endif + +#ifdef DBGDATA +static void trace_block(struct slgt_info *info, const char *data, int count, const char *label) +{ + int i; + int linecount; + printk("%s %s data:\n",info->device_name, label); + while(count) { + linecount = (count > 16) ? 16 : count; + for(i=0; i < linecount; i++) + printk("%02X ",(unsigned char)data[i]); + for(;i<17;i++) + printk(" "); + for(i=0;i<linecount;i++) { + if (data[i]>=040 && data[i]<=0176) + printk("%c",data[i]); + else + printk("."); + } + printk("\n"); + data += linecount; + count -= linecount; + } +} +#else +#define DBGDATA(info, buf, size, label) +#endif + +#ifdef DBGTBUF +static void dump_tbufs(struct slgt_info *info) +{ + int i; + printk("tbuf_current=%d\n", info->tbuf_current); + for (i=0 ; i < info->tbuf_count ; i++) { + printk("%d: count=%04X status=%04X\n", + i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status)); + } +} +#else +#define DBGTBUF(info) +#endif + +#ifdef DBGRBUF +static void dump_rbufs(struct slgt_info *info) +{ + int i; + printk("rbuf_current=%d\n", info->rbuf_current); + for (i=0 ; i < info->rbuf_count ; i++) { + printk("%d: count=%04X status=%04X\n", + i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status)); + } +} +#else +#define DBGRBUF(info) +#endif + +static inline int sanity_check(struct slgt_info *info, char *devname, const char *name) +{ +#ifdef SANITY_CHECK + if (!info) { + printk("null struct slgt_info for (%s) in %s\n", devname, name); + return 1; + } + if (info->magic != MGSL_MAGIC) { + printk("bad magic number struct slgt_info (%s) in %s\n", devname, name); + return 1; + } +#else + if (!info) + return 1; +#endif + return 0; +} + +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_receive_buf - pass receive data to line discipline + */ +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + +/* tty callbacks */ + +static int open(struct tty_struct *tty, struct file *filp) +{ + struct slgt_info *info; + int retval, line; + unsigned long flags; + + line = tty->index; + if ((line < 0) || (line >= slgt_device_count)) { + DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); + return -ENODEV; + } + + info = slgt_device_list; + while(info && info->line != line) + info = info->next_device; + if (sanity_check(info, tty->name, "open")) + return -ENODEV; + if (info->init_error) { + DBGERR(("%s init error=%d\n", info->device_name, info->init_error)); + return -ENODEV; + } + + tty->driver_data = info; + info->tty = tty; + + DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->count)); + + /* If port is closing, signal caller to try again */ + if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); + goto cleanup; + } + + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + spin_lock_irqsave(&info->netlock, flags); + if (info->netcount) { + retval = -EBUSY; + spin_unlock_irqrestore(&info->netlock, flags); + goto cleanup; + } + info->count++; + spin_unlock_irqrestore(&info->netlock, flags); + + if (info->count == 1) { + /* 1st open on this device, init hardware */ + retval = startup(info); + if (retval < 0) + goto cleanup; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { + DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval)); + goto cleanup; + } + + retval = 0; + +cleanup: + if (retval) { + if (tty->count == 1) + info->tty = NULL; /* tty layer will release tty struct */ + if(info->count) + info->count--; + } + + DBGINFO(("%s open rc=%d\n", info->device_name, retval)); + return retval; +} + +static void close(struct tty_struct *tty, struct file *filp) +{ + struct slgt_info *info = tty->driver_data; + + if (sanity_check(info, tty->name, "close")) + return; + DBGINFO(("%s close entry, count=%d\n", info->device_name, info->count)); + + if (!info->count) + return; + + if (tty_hung_up_p(filp)) + goto cleanup; + + if ((tty->count == 1) && (info->count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + DBGERR(("%s close: bad refcount; tty->count=1, " + "info->count=%d\n", info->device_name, info->count)); + info->count = 1; + } + + info->count--; + + /* if at least one open remaining, leave hardware active */ + if (info->count) + goto cleanup; + + info->flags |= ASYNC_CLOSING; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + DBGINFO(("%s call tty_wait_until_sent\n", info->device_name)); + tty_wait_until_sent(tty, info->closing_wait); + } + + if (info->flags & ASYNC_INITIALIZED) + wait_until_sent(tty, info->timeout); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + tty_ldisc_flush(tty); + + shutdown(info); + + tty->closing = 0; + info->tty = NULL; + + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs(info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + + wake_up_interruptible(&info->close_wait); + +cleanup: + DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->count)); +} + +static void hangup(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + + if (sanity_check(info, tty->name, "hangup")) + return; + DBGINFO(("%s hangup\n", info->device_name)); + + flush_buffer(tty); + shutdown(info); + + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->tty = NULL; + + wake_up_interruptible(&info->open_wait); +} + +static void set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + DBGINFO(("%s set_termios\n", tty->driver->name)); + + /* just return if nothing has changed */ + if ((tty->termios->c_cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_params(info); + + /* Handle transition to B0 status */ + if (old_termios->c_cflag & CBAUD && + !(tty->termios->c_cflag & CBAUD)) { + info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + tty->termios->c_cflag & CBAUD) { + info->signals |= SerialSignal_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->signals |= SerialSignal_RTS; + } + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + /* Handle turning off CRTSCTS */ + if (old_termios->c_cflag & CRTSCTS && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + tx_release(tty); + } +} + +static int write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + int ret = 0; + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "write")) + goto cleanup; + DBGINFO(("%s write count=%d\n", info->device_name, count)); + + if (!tty || !info->tx_buf) + goto cleanup; + + if (count > info->max_frame_size) { + ret = -EIO; + goto cleanup; + } + + if (!count) + goto cleanup; + + if (info->params.mode == MGSL_MODE_RAW) { + unsigned int bufs_needed = (count/DMABUFSIZE); + unsigned int bufs_free = free_tbuf_count(info); + if (count % DMABUFSIZE) + ++bufs_needed; + if (bufs_needed > bufs_free) + goto cleanup; + } else { + if (info->tx_active) + goto cleanup; + if (info->tx_count) { + /* send accumulated data from send_char() calls */ + /* as frame and wait before accepting more data. */ + tx_load(info, info->tx_buf, info->tx_count); + goto start; + } + } + + ret = info->tx_count = count; + tx_load(info, buf, count); + goto start; + +start: + if (info->tx_count && !tty->stopped && !tty->hw_stopped) { + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + +cleanup: + DBGINFO(("%s write rc=%d\n", info->device_name, ret)); + return ret; +} + +static void put_char(struct tty_struct *tty, unsigned char ch) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "put_char")) + return; + DBGINFO(("%s put_char(%d)\n", info->device_name, ch)); + if (!tty || !info->tx_buf) + return; + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active && (info->tx_count < info->max_frame_size)) + info->tx_buf[info->tx_count++] = ch; + spin_unlock_irqrestore(&info->lock,flags); +} + +static void send_xchar(struct tty_struct *tty, char ch) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "send_xchar")) + return; + DBGINFO(("%s send_xchar(%d)\n", info->device_name, ch)); + info->x_char = ch; + if (ch) { + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_enabled) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +static void wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct slgt_info *info = tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (!info ) + return; + if (sanity_check(info, tty->name, "wait_until_sent")) + return; + DBGINFO(("%s wait_until_sent entry\n", info->device_name)); + if (!(info->flags & ASYNC_INITIALIZED)) + goto exit; + + orig_jiffies = jiffies; + + /* Set check interval to 1/5 of estimated time to + * send a character, and make it at least 1. The check + * interval should also be less than the timeout. + * Note: use tight timings here to satisfy the NIST-PCTS. + */ + + if (info->params.data_rate) { + char_time = info->timeout/(32 * 5); + if (!char_time) + char_time++; + } else + char_time = 1; + + if (timeout) + char_time = min_t(unsigned long, char_time, timeout); + + while (info->tx_active) { + msleep_interruptible(jiffies_to_msecs(char_time)); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + +exit: + DBGINFO(("%s wait_until_sent exit\n", info->device_name)); +} + +static int write_room(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + int ret; + + if (sanity_check(info, tty->name, "write_room")) + return 0; + ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; + DBGINFO(("%s write_room=%d\n", info->device_name, ret)); + return ret; +} + +static void flush_chars(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "flush_chars")) + return; + DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count)); + + if (info->tx_count <= 0 || tty->stopped || + tty->hw_stopped || !info->tx_buf) + return; + + DBGINFO(("%s flush_chars start transmit\n", info->device_name)); + + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active && info->tx_count) { + tx_load(info, info->tx_buf,info->tx_count); + tx_start(info); + } + spin_unlock_irqrestore(&info->lock,flags); +} + +static void flush_buffer(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "flush_buffer")) + return; + DBGINFO(("%s flush_buffer\n", info->device_name)); + + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + info->tx_count = 0; + spin_unlock_irqrestore(&info->lock,flags); + + wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); +} + +/* + * throttle (stop) transmitter + */ +static void tx_hold(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "tx_hold")) + return; + DBGINFO(("%s tx_hold\n", info->device_name)); + spin_lock_irqsave(&info->lock,flags); + if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC) + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); +} + +/* + * release (start) transmitter + */ +static void tx_release(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "tx_release")) + return; + DBGINFO(("%s tx_release\n", info->device_name)); + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active && info->tx_count) { + tx_load(info, info->tx_buf, info->tx_count); + tx_start(info); + } + spin_unlock_irqrestore(&info->lock,flags); +} + +/* + * Service an IOCTL request + * + * Arguments + * + * tty pointer to tty instance data + * file pointer to associated file object for device + * cmd IOCTL command code + * arg command argument/context + * + * Return 0 if success, otherwise error code + */ +static int ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct slgt_info *info = tty->driver_data; + struct mgsl_icount cnow; /* kernel counter temps */ + struct serial_icounter_struct __user *p_cuser; /* user space */ + unsigned long flags; + void __user *argp = (void __user *)arg; + + if (sanity_check(info, tty->name, "ioctl")) + return -ENODEV; + DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case MGSL_IOCGPARAMS: + return get_params(info, argp); + case MGSL_IOCSPARAMS: + return set_params(info, argp); + case MGSL_IOCGTXIDLE: + return get_txidle(info, argp); + case MGSL_IOCSTXIDLE: + return set_txidle(info, (int)arg); + case MGSL_IOCTXENABLE: + return tx_enable(info, (int)arg); + case MGSL_IOCRXENABLE: + return rx_enable(info, (int)arg); + case MGSL_IOCTXABORT: + return tx_abort(info); + case MGSL_IOCGSTATS: + return get_stats(info, argp); + case MGSL_IOCWAITEVENT: + return wait_mgsl_event(info, argp); + case TIOCMIWAIT: + return modem_input_wait(info,(int)arg); + case MGSL_IOCGIF: + return get_interface(info, argp); + case MGSL_IOCSIF: + return set_interface(info,(int)arg); + case TIOCGICOUNT: + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->lock,flags); + p_cuser = argp; + if (put_user(cnow.cts, &p_cuser->cts) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd) || + put_user(cnow.rx, &p_cuser->rx) || + put_user(cnow.tx, &p_cuser->tx) || + put_user(cnow.frame, &p_cuser->frame) || + put_user(cnow.overrun, &p_cuser->overrun) || + put_user(cnow.parity, &p_cuser->parity) || + put_user(cnow.brk, &p_cuser->brk) || + put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) + return -EFAULT; + return 0; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* + * proc fs support + */ +static inline int line_info(char *buf, struct slgt_info *info) +{ + char stat_buf[30]; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", + info->device_name, info->phys_reg_addr, + info->irq_level, info->max_frame_size); + + /* output current serial signal states */ + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (info->signals & SerialSignal_RTS) + strcat(stat_buf, "|RTS"); + if (info->signals & SerialSignal_CTS) + strcat(stat_buf, "|CTS"); + if (info->signals & SerialSignal_DTR) + strcat(stat_buf, "|DTR"); + if (info->signals & SerialSignal_DSR) + strcat(stat_buf, "|DSR"); + if (info->signals & SerialSignal_DCD) + strcat(stat_buf, "|CD"); + if (info->signals & SerialSignal_RI) + strcat(stat_buf, "|RI"); + + if (info->params.mode != MGSL_MODE_ASYNC) { + ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", + info->icount.txok, info->icount.rxok); + if (info->icount.txunder) + ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + if (info->icount.txabort) + ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + if (info->icount.rxshort) + ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + if (info->icount.rxlong) + ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + if (info->icount.rxover) + ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + if (info->icount.rxcrc) + ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); + } else { + ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", + info->icount.tx, info->icount.rx); + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + } + + /* Append serial signal status to end */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + + ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + info->tx_active,info->bh_requested,info->bh_running, + info->pending_bh); + + return ret; +} + +/* Called to print information about devices + */ +static int read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0, l; + off_t begin = 0; + struct slgt_info *info; + + len += sprintf(page, "synclink_gt driver:%s\n", driver_version); + + info = slgt_device_list; + while( info ) { + l = line_info(page + len, info); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + info = info->next_device; + } + + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * return count of bytes in transmit buffer + */ +static int chars_in_buffer(struct tty_struct *tty) +{ + struct slgt_info *info = tty->driver_data; + if (sanity_check(info, tty->name, "chars_in_buffer")) + return 0; + DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count)); + return info->tx_count; +} + +/* + * signal remote device to throttle send data (our receive data) + */ +static void throttle(struct tty_struct * tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "throttle")) + return; + DBGINFO(("%s throttle\n", info->device_name)); + if (I_IXOFF(tty)) + send_xchar(tty, STOP_CHAR(tty)); + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->lock,flags); + info->signals &= ~SerialSignal_RTS; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* + * signal remote device to stop throttling send data (our receive data) + */ +static void unthrottle(struct tty_struct * tty) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->name, "unthrottle")) + return; + DBGINFO(("%s unthrottle\n", info->device_name)); + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->lock,flags); + info->signals |= SerialSignal_RTS; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* + * set or clear transmit break condition + * break_state -1=set break condition, 0=clear + */ +static void set_break(struct tty_struct *tty, int break_state) +{ + struct slgt_info *info = tty->driver_data; + unsigned short value; + unsigned long flags; + + if (sanity_check(info, tty->name, "set_break")) + return; + DBGINFO(("%s set_break(%d)\n", info->device_name, break_state)); + + spin_lock_irqsave(&info->lock,flags); + value = rd_reg16(info, TCR); + if (break_state == -1) + value |= BIT6; + else + value &= ~BIT6; + wr_reg16(info, TCR, value); + spin_unlock_irqrestore(&info->lock,flags); +} + +#ifdef CONFIG_HDLC + +/** + * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * set encoding and frame check sequence (FCS) options + * + * dev pointer to network device structure + * encoding serial encoding setting + * parity FCS setting + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) +{ + struct slgt_info *info = dev_to_port(dev); + unsigned char new_encoding; + unsigned short new_crctype; + + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; + + DBGINFO(("%s hdlcdev_attach\n", info->device_name)); + + switch (encoding) + { + case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; + case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; + case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; + case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; + case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; + default: return -EINVAL; + } + + switch (parity) + { + case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; + case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; + case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; + default: return -EINVAL; + } + + info->params.encoding = new_encoding; + info->params.crc_type = new_crctype;; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + program_hw(info); + + return 0; +} + +/** + * called by generic HDLC layer to send frame + * + * skb socket buffer containing HDLC frame + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + + DBGINFO(("%s hdlc_xmit\n", dev->name)); + + /* stop sending until this frame completes */ + netif_stop_queue(dev); + + /* copy data to device buffers */ + info->tx_count = skb->len; + tx_load(info, skb->data, skb->len); + + /* update network statistics */ + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* done with socket buffer, so free it */ + dev_kfree_skb(skb); + + /* save start time for transmit timeout detection */ + dev->trans_start = jiffies; + + /* start hardware transmitter if necessary */ + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; +} + +/** + * called by network layer when interface enabled + * claim resources and initialize hardware + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_open(struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + int rc; + unsigned long flags; + + DBGINFO(("%s hdlcdev_open\n", dev->name)); + + /* generic HDLC layer open processing */ + if ((rc = hdlc_open(dev))) + return rc; + + /* arbitrate between network and tty opens */ + spin_lock_irqsave(&info->netlock, flags); + if (info->count != 0 || info->netcount != 0) { + DBGINFO(("%s hdlc_open busy\n", dev->name)); + spin_unlock_irqrestore(&info->netlock, flags); + return -EBUSY; + } + info->netcount=1; + spin_unlock_irqrestore(&info->netlock, flags); + + /* claim resources and init adapter */ + if ((rc = startup(info)) != 0) { + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + return rc; + } + + /* assert DTR and RTS, apply hardware settings */ + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + program_hw(info); + + /* enable network layer transmit */ + dev->trans_start = jiffies; + netif_start_queue(dev); + + /* inform generic HDLC layer of current DCD status */ + spin_lock_irqsave(&info->lock, flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock, flags); + hdlc_set_carrier(info->signals & SerialSignal_DCD, dev); + + return 0; +} + +/** + * called by network layer when interface is disabled + * shutdown hardware and release resources + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_close(struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + unsigned long flags; + + DBGINFO(("%s hdlcdev_close\n", dev->name)); + + netif_stop_queue(dev); + + /* shutdown adapter and release resources */ + shutdown(info); + + hdlc_close(dev); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + + return 0; +} + +/** + * called by network layer to process IOCTL call to network device + * + * dev pointer to network device structure + * ifr pointer to network interface request structure + * cmd IOCTL command code + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + struct slgt_info *info = dev_to_port(dev); + unsigned int flags; + + DBGINFO(("%s hdlcdev_ioctl\n", dev->name)); + + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; + + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: /* return current sync_serial_settings */ + + ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + + flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + + switch (flags){ + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; + case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; + default: new_line.clock_type = CLOCK_DEFAULT; + } + + new_line.clock_rate = info->params.clock_speed; + new_line.loopback = info->params.loopback ? 1:0; + + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + switch (new_line.clock_type) + { + case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; + case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; + case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; + case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; + case CLOCK_DEFAULT: flags = info->params.flags & + (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; + default: return -EINVAL; + } + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + info->params.flags |= flags; + + info->params.loopback = new_line.loopback; + + if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) + info->params.clock_speed = new_line.clock_rate; + else + info->params.clock_speed = 0; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + program_hw(info); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } +} + +/** + * called by network layer when transmit timeout is detected + * + * dev pointer to network device structure + */ +static void hdlcdev_tx_timeout(struct net_device *dev) +{ + struct slgt_info *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + + DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name)); + + stats->tx_errors++; + stats->tx_aborted_errors++; + + spin_lock_irqsave(&info->lock,flags); + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); + + netif_wake_queue(dev); +} + +/** + * called by device driver when transmit completes + * reenable network layer transmit if stopped + * + * info pointer to device instance information + */ +static void hdlcdev_tx_done(struct slgt_info *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +/** + * called by device driver when frame received + * pass frame to network layer + * + * info pointer to device instance information + * buf pointer to buffer contianing frame data + * size count of data bytes in buf + */ +static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) +{ + struct sk_buff *skb = dev_alloc_skb(size); + struct net_device *dev = info->netdev; + struct net_device_stats *stats = hdlc_stats(dev); + + DBGINFO(("%s hdlcdev_rx\n", dev->name)); + + if (skb == NULL) { + DBGERR(("%s: can't alloc skb, drop packet\n", dev->name)); + stats->rx_dropped++; + return; + } + + memcpy(skb_put(skb, size),buf,size); + + skb->protocol = hdlc_type_trans(skb, info->netdev); + + stats->rx_packets++; + stats->rx_bytes += size; + + netif_rx(skb); + + info->netdev->last_rx = jiffies; +} + +/** + * called by device driver when adding device instance + * do generic HDLC initialization + * + * info pointer to device instance information + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_init(struct slgt_info *info) +{ + int rc; + struct net_device *dev; + hdlc_device *hdlc; + + /* allocate and initialize network and HDLC layer objects */ + + if (!(dev = alloc_hdlcdev(info))) { + printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); + return -ENOMEM; + } + + /* for network layer reporting purposes only */ + dev->mem_start = info->phys_reg_addr; + dev->mem_end = info->phys_reg_addr + SLGT_REG_SIZE - 1; + dev->irq = info->irq_level; + + /* network layer callbacks and settings */ + dev->do_ioctl = hdlcdev_ioctl; + dev->open = hdlcdev_open; + dev->stop = hdlcdev_close; + dev->tx_timeout = hdlcdev_tx_timeout; + dev->watchdog_timeo = 10*HZ; + dev->tx_queue_len = 50; + + /* generic HDLC layer callbacks and settings */ + hdlc = dev_to_hdlc(dev); + hdlc->attach = hdlcdev_attach; + hdlc->xmit = hdlcdev_xmit; + + /* register objects with HDLC layer */ + if ((rc = register_hdlc_device(dev))) { + printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); + free_netdev(dev); + return rc; + } + + info->netdev = dev; + return 0; +} + +/** + * called by device driver when removing device instance + * do generic HDLC cleanup + * + * info pointer to device instance information + */ +static void hdlcdev_exit(struct slgt_info *info) +{ + unregister_hdlc_device(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; +} + +#endif /* ifdef CONFIG_HDLC */ + +/* + * get async data from rx DMA buffers + */ +static void rx_async(struct slgt_info *info) +{ + struct tty_struct *tty = info->tty; + struct mgsl_icount *icount = &info->icount; + unsigned int start, end; + unsigned char *p; + unsigned char status; + struct slgt_desc *bufs = info->rbufs; + int i, count; + + start = end = info->rbuf_current; + + while(desc_complete(bufs[end])) { + count = desc_count(bufs[end]) - info->rbuf_index; + p = bufs[end].buf + info->rbuf_index; + + DBGISR(("%s rx_async count=%d\n", info->device_name, count)); + DBGDATA(info, p, count, "rx"); + + for(i=0 ; i < count; i+=2, p+=2) { + if (tty) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + tty_flip_buffer_push(tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = *p; + *tty->flip.flag_buf_ptr = 0; + } + icount->rx++; + + if ((status = *(p+1) & (BIT9 + BIT8))) { + if (status & BIT9) + icount->parity++; + else if (status & BIT8) + icount->frame++; + /* discard char if tty control flags say so */ + if (status & info->ignore_status_mask) + continue; + if (tty) { + if (status & BIT9) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & BIT8) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + } + if (tty) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + } + + if (i < count) { + /* receive buffer not completed */ + info->rbuf_index += i; + info->rx_timer.expires = jiffies + 1; + add_timer(&info->rx_timer); + break; + } + + info->rbuf_index = 0; + free_rbufs(info, end, end); + + if (++end == info->rbuf_count) + end = 0; + + /* if entire list searched then no frame available */ + if (end == start) + break; + } + + if (tty && tty->flip.count) + tty_flip_buffer_push(tty); +} + +/* + * return next bottom half action to perform + */ +static int bh_action(struct slgt_info *info) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&info->lock,flags); + + if (info->pending_bh & BH_RECEIVE) { + info->pending_bh &= ~BH_RECEIVE; + rc = BH_RECEIVE; + } else if (info->pending_bh & BH_TRANSMIT) { + info->pending_bh &= ~BH_TRANSMIT; + rc = BH_TRANSMIT; + } else if (info->pending_bh & BH_STATUS) { + info->pending_bh &= ~BH_STATUS; + rc = BH_STATUS; + } else { + /* Mark BH routine as complete */ + info->bh_running = 0; + info->bh_requested = 0; + rc = 0; + } + + spin_unlock_irqrestore(&info->lock,flags); + + return rc; +} + +/* + * perform bottom half processing + */ +static void bh_handler(void* context) +{ + struct slgt_info *info = context; + int action; + + if (!info) + return; + info->bh_running = 1; + + while((action = bh_action(info))) { + switch (action) { + case BH_RECEIVE: + DBGBH(("%s bh receive\n", info->device_name)); + switch(info->params.mode) { + case MGSL_MODE_ASYNC: + rx_async(info); + break; + case MGSL_MODE_HDLC: + while(rx_get_frame(info)); + break; + case MGSL_MODE_RAW: + while(rx_get_buf(info)); + break; + } + /* restart receiver if rx DMA buffers exhausted */ + if (info->rx_restart) + rx_start(info); + break; + case BH_TRANSMIT: + bh_transmit(info); + break; + case BH_STATUS: + DBGBH(("%s bh status\n", info->device_name)); + info->ri_chkcount = 0; + info->dsr_chkcount = 0; + info->dcd_chkcount = 0; + info->cts_chkcount = 0; + break; + default: + DBGBH(("%s unknown action\n", info->device_name)); + break; + } + } + DBGBH(("%s bh_handler exit\n", info->device_name)); +} + +static void bh_transmit(struct slgt_info *info) +{ + struct tty_struct *tty = info->tty; + + DBGBH(("%s bh_transmit\n", info->device_name)); + if (tty) { + tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +static void dsr_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_DSR); + return; + } + info->icount.dsr++; + if (info->signals & SerialSignal_DSR) + info->input_signal_events.dsr_up++; + else + info->input_signal_events.dsr_down++; + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; +} + +static void cts_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_CTS); + return; + } + info->icount.cts++; + if (info->signals & SerialSignal_CTS) + info->input_signal_events.cts_up++; + else + info->input_signal_events.cts_down++; + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; + + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty) { + if (info->tty->hw_stopped) { + if (info->signals & SerialSignal_CTS) { + info->tty->hw_stopped = 0; + info->pending_bh |= BH_TRANSMIT; + return; + } + } else { + if (!(info->signals & SerialSignal_CTS)) + info->tty->hw_stopped = 1; + } + } + } +} + +static void dcd_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_DCD); + return; + } + info->icount.dcd++; + if (info->signals & SerialSignal_DCD) { + info->input_signal_events.dcd_up++; + } else { + info->input_signal_events.dcd_down++; + } +#ifdef CONFIG_HDLC + if (info->netcount) + hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev); +#endif + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; + + if (info->flags & ASYNC_CHECK_CD) { + if (info->signals & SerialSignal_DCD) + wake_up_interruptible(&info->open_wait); + else { + if (info->tty) + tty_hangup(info->tty); + } + } +} + +static void ri_change(struct slgt_info *info) +{ + get_signals(info); + DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); + if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { + slgt_irq_off(info, IRQ_RI); + return; + } + info->icount.dcd++; + if (info->signals & SerialSignal_RI) { + info->input_signal_events.ri_up++; + } else { + info->input_signal_events.ri_down++; + } + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + info->pending_bh |= BH_STATUS; +} + +static void isr_serial(struct slgt_info *info) +{ + unsigned short status = rd_reg16(info, SSR); + + DBGISR(("%s isr_serial status=%04X\n", info->device_name, status)); + + wr_reg16(info, SSR, status); /* clear pending */ + + info->irq_occurred = 1; + + if (info->params.mode == MGSL_MODE_ASYNC) { + if (status & IRQ_TXIDLE) { + if (info->tx_count) + isr_txeom(info, status); + } + if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { + info->icount.brk++; + /* process break detection if tty control allows */ + if (info->tty) { + if (!(status & info->ignore_status_mask)) { + if (info->read_status_mask & MASK_BREAK) { + *info->tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(info->tty); + } + } + } + } + } else { + if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) + isr_txeom(info, status); + + if (status & IRQ_RXIDLE) { + if (status & RXIDLE) + info->icount.rxidle++; + else + info->icount.exithunt++; + wake_up_interruptible(&info->event_wait_q); + } + + if (status & IRQ_RXOVER) + rx_start(info); + } + + if (status & IRQ_DSR) + dsr_change(info); + if (status & IRQ_CTS) + cts_change(info); + if (status & IRQ_DCD) + dcd_change(info); + if (status & IRQ_RI) + ri_change(info); +} + +static void isr_rdma(struct slgt_info *info) +{ + unsigned int status = rd_reg32(info, RDCSR); + + DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status)); + + /* RDCSR (rx DMA control/status) + * + * 31..07 reserved + * 06 save status byte to DMA buffer + * 05 error + * 04 eol (end of list) + * 03 eob (end of buffer) + * 02 IRQ enable + * 01 reset + * 00 enable + */ + wr_reg32(info, RDCSR, status); /* clear pending */ + + if (status & (BIT5 + BIT4)) { + DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); + info->rx_restart = 1; + } + info->pending_bh |= BH_RECEIVE; +} + +static void isr_tdma(struct slgt_info *info) +{ + unsigned int status = rd_reg32(info, TDCSR); + + DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status)); + + /* TDCSR (tx DMA control/status) + * + * 31..06 reserved + * 05 error + * 04 eol (end of list) + * 03 eob (end of buffer) + * 02 IRQ enable + * 01 reset + * 00 enable + */ + wr_reg32(info, TDCSR, status); /* clear pending */ + + if (status & (BIT5 + BIT4 + BIT3)) { + // another transmit buffer has completed + // run bottom half to get more send data from user + info->pending_bh |= BH_TRANSMIT; + } +} + +static void isr_txeom(struct slgt_info *info, unsigned short status) +{ + DBGISR(("%s txeom status=%04x\n", info->device_name, status)); + + slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); + tdma_reset(info); + reset_tbufs(info); + if (status & IRQ_TXUNDER) { + unsigned short val = rd_reg16(info, TCR); + wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, TCR, val); /* clear reset bit */ + } + + if (info->tx_active) { + if (info->params.mode != MGSL_MODE_ASYNC) { + if (status & IRQ_TXUNDER) + info->icount.txunder++; + else if (status & IRQ_TXIDLE) + info->icount.txok++; + } + + info->tx_active = 0; + info->tx_count = 0; + + del_timer(&info->tx_timer); + + if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { + info->signals &= ~SerialSignal_RTS; + info->drop_rts_on_tx_done = 0; + set_signals(info); + } + +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_tx_done(info); + else +#endif + { + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + tx_stop(info); + return; + } + info->pending_bh |= BH_TRANSMIT; + } + } +} + +/* interrupt service routine + * + * irq interrupt number + * dev_id device ID supplied during interrupt registration + * regs interrupted processor context + */ +static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct slgt_info *info; + unsigned int gsr; + unsigned int i; + + DBGISR(("slgt_interrupt irq=%d entry\n", irq)); + + info = dev_id; + if (!info) + return IRQ_NONE; + + spin_lock(&info->lock); + + while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { + DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); + info->irq_occurred = 1; + for(i=0; i < info->port_count ; i++) { + if (info->port_array[i] == NULL) + continue; + if (gsr & (BIT8 << i)) + isr_serial(info->port_array[i]); + if (gsr & (BIT16 << (i*2))) + isr_rdma(info->port_array[i]); + if (gsr & (BIT17 << (i*2))) + isr_tdma(info->port_array[i]); + } + } + + for(i=0; i < info->port_count ; i++) { + struct slgt_info *port = info->port_array[i]; + + if (port && (port->count || port->netcount) && + port->pending_bh && !port->bh_running && + !port->bh_requested) { + DBGISR(("%s bh queued\n", port->device_name)); + schedule_work(&port->task); + port->bh_requested = 1; + } + } + + spin_unlock(&info->lock); + + DBGISR(("slgt_interrupt irq=%d exit\n", irq)); + return IRQ_HANDLED; +} + +static int startup(struct slgt_info *info) +{ + DBGINFO(("%s startup\n", info->device_name)); + + if (info->flags & ASYNC_INITIALIZED) + return 0; + + if (!info->tx_buf) { + info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); + if (!info->tx_buf) { + DBGERR(("%s can't allocate tx buffer\n", info->device_name)); + return -ENOMEM; + } + } + + info->pending_bh = 0; + + memset(&info->icount, 0, sizeof(info->icount)); + + /* program hardware for current parameters */ + change_params(info); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags |= ASYNC_INITIALIZED; + + return 0; +} + +/* + * called by close() and hangup() to shutdown hardware + */ +static void shutdown(struct slgt_info *info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + DBGINFO(("%s shutdown\n", info->device_name)); + + /* clear status wait queue because status changes */ + /* can't happen after shutting down the hardware */ + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + + del_timer_sync(&info->tx_timer); + del_timer_sync(&info->rx_timer); + + kfree(info->tx_buf); + info->tx_buf = NULL; + + spin_lock_irqsave(&info->lock,flags); + + tx_stop(info); + rx_stop(info); + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); + + if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + set_signals(info); + } + + spin_unlock_irqrestore(&info->lock,flags); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; +} + +static void program_hw(struct slgt_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(&info->lock,flags); + + rx_stop(info); + tx_stop(info); + + if (info->params.mode == MGSL_MODE_HDLC || + info->params.mode == MGSL_MODE_RAW || + info->netcount) + hdlc_mode(info); + else + async_mode(info); + + set_signals(info); + + info->dcd_chkcount = 0; + info->cts_chkcount = 0; + info->ri_chkcount = 0; + info->dsr_chkcount = 0; + + slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR); + get_signals(info); + + if (info->netcount || + (info->tty && info->tty->termios->c_cflag & CREAD)) + rx_start(info); + + spin_unlock_irqrestore(&info->lock,flags); +} + +/* + * reconfigure adapter based on new parameters + */ +static void change_params(struct slgt_info *info) +{ + unsigned cflag; + int bits_per_char; + + if (!info->tty || !info->tty->termios) + return; + DBGINFO(("%s change_params\n", info->device_name)); + + cflag = info->tty->termios->c_cflag; + + /* if B0 rate (hangup) specified then negate DTR and RTS */ + /* otherwise assert DTR and RTS */ + if (cflag & CBAUD) + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + + /* byte size and parity */ + + switch (cflag & CSIZE) { + case CS5: info->params.data_bits = 5; break; + case CS6: info->params.data_bits = 6; break; + case CS7: info->params.data_bits = 7; break; + case CS8: info->params.data_bits = 8; break; + default: info->params.data_bits = 7; break; + } + + info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1; + + if (cflag & PARENB) + info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN; + else + info->params.parity = ASYNC_PARITY_NONE; + + /* calculate number of jiffies to transmit a full + * FIFO (32 bytes) at specified data rate + */ + bits_per_char = info->params.data_bits + + info->params.stop_bits + 1; + + info->params.data_rate = tty_get_baud_rate(info->tty); + + if (info->params.data_rate) { + info->timeout = (32*HZ*bits_per_char) / + info->params.data_rate; + } + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /* process tty input control flags */ + + info->read_status_mask = IRQ_RXOVER; + if (I_INPCK(info->tty)) + info->read_status_mask |= MASK_PARITY | MASK_FRAMING; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= MASK_BREAK; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= MASK_BREAK; + /* If ignoring parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= MASK_OVERRUN; + } + + program_hw(info); +} + +static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount) +{ + DBGINFO(("%s get_stats\n", info->device_name)); + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount))) + return -EFAULT; + } + return 0; +} + +static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params) +{ + DBGINFO(("%s get_params\n", info->device_name)); + if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS))) + return -EFAULT; + return 0; +} + +static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params) +{ + unsigned long flags; + MGSL_PARAMS tmp_params; + + DBGINFO(("%s set_params\n", info->device_name)); + if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS))) + return -EFAULT; + + spin_lock_irqsave(&info->lock, flags); + memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS)); + spin_unlock_irqrestore(&info->lock, flags); + + change_params(info); + + return 0; +} + +static int get_txidle(struct slgt_info *info, int __user *idle_mode) +{ + DBGINFO(("%s get_txidle=%d\n", info->device_name, info->idle_mode)); + if (put_user(info->idle_mode, idle_mode)) + return -EFAULT; + return 0; +} + +static int set_txidle(struct slgt_info *info, int idle_mode) +{ + unsigned long flags; + DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode)); + spin_lock_irqsave(&info->lock,flags); + info->idle_mode = idle_mode; + tx_set_idle(info); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int tx_enable(struct slgt_info *info, int enable) +{ + unsigned long flags; + DBGINFO(("%s tx_enable(%d)\n", info->device_name, enable)); + spin_lock_irqsave(&info->lock,flags); + if (enable) { + if (!info->tx_enabled) + tx_start(info); + } else { + if (info->tx_enabled) + tx_stop(info); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* + * abort transmit HDLC frame + */ +static int tx_abort(struct slgt_info *info) +{ + unsigned long flags; + DBGINFO(("%s tx_abort\n", info->device_name)); + spin_lock_irqsave(&info->lock,flags); + tdma_reset(info); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int rx_enable(struct slgt_info *info, int enable) +{ + unsigned long flags; + DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable)); + spin_lock_irqsave(&info->lock,flags); + if (enable) { + if (!info->rx_enabled) + rx_start(info); + } else { + if (info->rx_enabled) + rx_stop(info); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* + * wait for specified event to occur + */ +static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr) +{ + unsigned long flags; + int s; + int rc=0; + struct mgsl_icount cprev, cnow; + int events; + int mask; + struct _input_signal_events oldsigs, newsigs; + DECLARE_WAITQUEUE(wait, current); + + if (get_user(mask, mask_ptr)) + return -EFAULT; + + DBGINFO(("%s wait_mgsl_event(%d)\n", info->device_name, mask)); + + spin_lock_irqsave(&info->lock,flags); + + /* return immediately if state matches requested events */ + get_signals(info); + s = info->signals; + + events = mask & + ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + + ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + + ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + + ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); + if (events) { + spin_unlock_irqrestore(&info->lock,flags); + goto exit; + } + + /* save current irq counts */ + cprev = info->icount; + oldsigs = info->input_signal_events; + + /* enable hunt and idle irqs if needed */ + if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) { + unsigned short val = rd_reg16(info, SCR); + if (!(val & IRQ_RXIDLE)) + wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE)); + } + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&info->event_wait_q, &wait); + + spin_unlock_irqrestore(&info->lock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get current irq counts */ + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + newsigs = info->input_signal_events; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + /* if no change, wait aborted for some reason */ + if (newsigs.dsr_up == oldsigs.dsr_up && + newsigs.dsr_down == oldsigs.dsr_down && + newsigs.dcd_up == oldsigs.dcd_up && + newsigs.dcd_down == oldsigs.dcd_down && + newsigs.cts_up == oldsigs.cts_up && + newsigs.cts_down == oldsigs.cts_down && + newsigs.ri_up == oldsigs.ri_up && + newsigs.ri_down == oldsigs.ri_down && + cnow.exithunt == cprev.exithunt && + cnow.rxidle == cprev.rxidle) { + rc = -EIO; + break; + } + + events = mask & + ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + + (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + + (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + + (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + + (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + + (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + + (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + + (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + + (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + + (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); + if (events) + break; + + cprev = cnow; + oldsigs = newsigs; + } + + remove_wait_queue(&info->event_wait_q, &wait); + set_current_state(TASK_RUNNING); + + + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + spin_lock_irqsave(&info->lock,flags); + if (!waitqueue_active(&info->event_wait_q)) { + /* disable enable exit hunt mode/idle rcvd IRQs */ + wr_reg16(info, SCR, + (unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE)); + } + spin_unlock_irqrestore(&info->lock,flags); + } +exit: + if (rc == 0) + rc = put_user(events, mask_ptr); + return rc; +} + +static int get_interface(struct slgt_info *info, int __user *if_mode) +{ + DBGINFO(("%s get_interface=%x\n", info->device_name, info->if_mode)); + if (put_user(info->if_mode, if_mode)) + return -EFAULT; + return 0; +} + +static int set_interface(struct slgt_info *info, int if_mode) +{ + unsigned long flags; + unsigned char val; + + DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode)); + spin_lock_irqsave(&info->lock,flags); + info->if_mode = if_mode; + + msc_set_vcr(info); + + /* TCR (tx control) 07 1=RTS driver control */ + val = rd_reg16(info, TCR); + if (info->if_mode & MGSL_INTERFACE_RTS_EN) + val |= BIT7; + else + val &= ~BIT7; + wr_reg16(info, TCR, val); + + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int modem_input_wait(struct slgt_info *info,int arg) +{ + unsigned long flags; + int rc; + struct mgsl_icount cprev, cnow; + DECLARE_WAITQUEUE(wait, current); + + /* save current irq counts */ + spin_lock_irqsave(&info->lock,flags); + cprev = info->icount; + add_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get new irq counts */ + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + /* if no change, wait aborted for some reason */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; + break; + } + + /* check for change in caller specified modem input */ + if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || + (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || + (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || + (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { + rc = 0; + break; + } + + cprev = cnow; + } + remove_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_RUNNING); + return rc; +} + +/* + * return state of serial control and status signals + */ +static int tiocmget(struct tty_struct *tty, struct file *file) +{ + struct slgt_info *info = tty->driver_data; + unsigned int result; + unsigned long flags; + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) + + ((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) + + ((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) + + ((info->signals & SerialSignal_RI) ? TIOCM_RNG:0) + + ((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) + + ((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0); + + DBGINFO(("%s tiocmget value=%08X\n", info->device_name, result)); + return result; +} + +/* + * set modem control signals (DTR/RTS) + * + * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit + * TIOCMSET = set/clear signal values + * value bit mask for command + */ +static int tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct slgt_info *info = tty->driver_data; + unsigned long flags; + + DBGINFO(("%s tiocmset(%x,%x)\n", info->device_name, set, clear)); + + if (set & TIOCM_RTS) + info->signals |= SerialSignal_RTS; + if (set & TIOCM_DTR) + info->signals |= SerialSignal_DTR; + if (clear & TIOCM_RTS) + info->signals &= ~SerialSignal_RTS; + if (clear & TIOCM_DTR) + info->signals &= ~SerialSignal_DTR; + + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* + * block current process until the device is ready to open + */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct slgt_info *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + DBGINFO(("%s block_til_ready\n", tty->driver->name)); + + if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + /* nonblock mode is set or port is not enabled */ + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* Wait for carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + spin_lock_irqsave(&info->lock, flags); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + info->count--; + } + spin_unlock_irqrestore(&info->lock, flags); + info->blocked_open++; + + while (1) { + if ((tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->lock,flags); + info->signals |= SerialSignal_RTS + SerialSignal_DTR; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + set_current_state(TASK_INTERRUPTIBLE); + + if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ + retval = (info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + if (!(info->flags & ASYNC_CLOSING) && + (do_clocal || (info->signals & SerialSignal_DCD)) ) { + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + + if (extra_count) + info->count++; + info->blocked_open--; + + if (!retval) + info->flags |= ASYNC_NORMAL_ACTIVE; + + DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); + return retval; +} + +static int alloc_tmp_rbuf(struct slgt_info *info) +{ + info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL); + if (info->tmp_rbuf == NULL) + return -ENOMEM; + return 0; +} + +static void free_tmp_rbuf(struct slgt_info *info) +{ + kfree(info->tmp_rbuf); + info->tmp_rbuf = NULL; +} + +/* + * allocate DMA descriptor lists. + */ +static int alloc_desc(struct slgt_info *info) +{ + unsigned int i; + unsigned int pbufs; + + /* allocate memory to hold descriptor lists */ + info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr); + if (info->bufs == NULL) + return -ENOMEM; + + memset(info->bufs, 0, DESC_LIST_SIZE); + + info->rbufs = (struct slgt_desc*)info->bufs; + info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count; + + pbufs = (unsigned int)info->bufs_dma_addr; + + /* + * Build circular lists of descriptors + */ + + for (i=0; i < info->rbuf_count; i++) { + /* physical address of this descriptor */ + info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc)); + + /* physical address of next descriptor */ + if (i == info->rbuf_count - 1) + info->rbufs[i].next = cpu_to_le32(pbufs); + else + info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc))); + set_desc_count(info->rbufs[i], DMABUFSIZE); + } + + for (i=0; i < info->tbuf_count; i++) { + /* physical address of this descriptor */ + info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc)); + + /* physical address of next descriptor */ + if (i == info->tbuf_count - 1) + info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc)); + else + info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc))); + } + + return 0; +} + +static void free_desc(struct slgt_info *info) +{ + if (info->bufs != NULL) { + pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr); + info->bufs = NULL; + info->rbufs = NULL; + info->tbufs = NULL; + } +} + +static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) +{ + int i; + for (i=0; i < count; i++) { + if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL) + return -ENOMEM; + bufs[i].pbuf = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr); + } + return 0; +} + +static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) +{ + int i; + for (i=0; i < count; i++) { + if (bufs[i].buf == NULL) + continue; + pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr); + bufs[i].buf = NULL; + } +} + +static int alloc_dma_bufs(struct slgt_info *info) +{ + info->rbuf_count = 32; + info->tbuf_count = 32; + + if (alloc_desc(info) < 0 || + alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 || + alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 || + alloc_tmp_rbuf(info) < 0) { + DBGERR(("%s DMA buffer alloc fail\n", info->device_name)); + return -ENOMEM; + } + reset_rbufs(info); + return 0; +} + +static void free_dma_bufs(struct slgt_info *info) +{ + if (info->bufs) { + free_bufs(info, info->rbufs, info->rbuf_count); + free_bufs(info, info->tbufs, info->tbuf_count); + free_desc(info); + } + free_tmp_rbuf(info); +} + +static int claim_resources(struct slgt_info *info) +{ + if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) { + DBGERR(("%s reg addr conflict, addr=%08X\n", + info->device_name, info->phys_reg_addr)); + info->init_error = DiagStatus_AddressConflict; + goto errout; + } + else + info->reg_addr_requested = 1; + + info->reg_addr = ioremap(info->phys_reg_addr, PAGE_SIZE); + if (!info->reg_addr) { + DBGERR(("%s cant map device registers, addr=%08X\n", + info->device_name, info->phys_reg_addr)); + info->init_error = DiagStatus_CantAssignPciResources; + goto errout; + } + info->reg_addr += info->reg_offset; + return 0; + +errout: + release_resources(info); + return -ENODEV; +} + +static void release_resources(struct slgt_info *info) +{ + if (info->irq_requested) { + free_irq(info->irq_level, info); + info->irq_requested = 0; + } + + if (info->reg_addr_requested) { + release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE); + info->reg_addr_requested = 0; + } + + if (info->reg_addr) { + iounmap(info->reg_addr - info->reg_offset); + info->reg_addr = NULL; + } +} + +/* Add the specified device instance data structure to the + * global linked list of devices and increment the device count. + */ +static void add_device(struct slgt_info *info) +{ + char *devstr; + + info->next_device = NULL; + info->line = slgt_device_count; + sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line); + + if (info->line < MAX_DEVICES) { + if (maxframe[info->line]) + info->max_frame_size = maxframe[info->line]; + info->dosyncppp = dosyncppp[info->line]; + } + + slgt_device_count++; + + if (!slgt_device_list) + slgt_device_list = info; + else { + struct slgt_info *current_dev = slgt_device_list; + while(current_dev->next_device) + current_dev = current_dev->next_device; + current_dev->next_device = info; + } + + if (info->max_frame_size < 4096) + info->max_frame_size = 4096; + else if (info->max_frame_size > 65535) + info->max_frame_size = 65535; + + switch(info->pdev->device) { + case SYNCLINK_GT_DEVICE_ID: + devstr = "GT"; + break; + case SYNCLINK_GT4_DEVICE_ID: + devstr = "GT4"; + break; + case SYNCLINK_AC_DEVICE_ID: + devstr = "AC"; + info->params.mode = MGSL_MODE_ASYNC; + break; + default: + devstr = "(unknown model)"; + } + printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u\n", + devstr, info->device_name, info->phys_reg_addr, + info->irq_level, info->max_frame_size); + +#ifdef CONFIG_HDLC + hdlcdev_init(info); +#endif +} + +/* + * allocate device instance structure, return NULL on failure + */ +static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) +{ + struct slgt_info *info; + + info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL); + + if (!info) { + DBGERR(("%s device alloc failed adapter=%d port=%d\n", + driver_name, adapter_num, port_num)); + } else { + memset(info, 0, sizeof(struct slgt_info)); + info->magic = MGSL_MAGIC; + INIT_WORK(&info->task, bh_handler, info); + info->max_frame_size = 4096; + info->raw_rx_size = DMABUFSIZE; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->status_event_wait_q); + init_waitqueue_head(&info->event_wait_q); + spin_lock_init(&info->netlock); + memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); + info->idle_mode = HDLC_TXIDLE_FLAGS; + info->adapter_num = adapter_num; + info->port_num = port_num; + + init_timer(&info->tx_timer); + info->tx_timer.data = (unsigned long)info; + info->tx_timer.function = tx_timeout; + + init_timer(&info->rx_timer); + info->rx_timer.data = (unsigned long)info; + info->rx_timer.function = rx_timeout; + + /* Copy configuration info to device instance data */ + info->pdev = pdev; + info->irq_level = pdev->irq; + info->phys_reg_addr = pci_resource_start(pdev,0); + + /* veremap works on page boundaries + * map full page starting at the page boundary + */ + info->reg_offset = info->phys_reg_addr & (PAGE_SIZE-1); + info->phys_reg_addr &= ~(PAGE_SIZE-1); + + info->bus_type = MGSL_BUS_TYPE_PCI; + info->irq_flags = SA_SHIRQ; + + info->init_error = -1; /* assume error, set to 0 on successful init */ + } + + return info; +} + +static void device_init(int adapter_num, struct pci_dev *pdev) +{ + struct slgt_info *port_array[SLGT_MAX_PORTS]; + int i; + int port_count = 1; + + if (pdev->device == SYNCLINK_GT4_DEVICE_ID) + port_count = 4; + + /* allocate device instances for all ports */ + for (i=0; i < port_count; ++i) { + port_array[i] = alloc_dev(adapter_num, i, pdev); + if (port_array[i] == NULL) { + for (--i; i >= 0; --i) + kfree(port_array[i]); + return; + } + } + + /* give copy of port_array to all ports and add to device list */ + for (i=0; i < port_count; ++i) { + memcpy(port_array[i]->port_array, port_array, sizeof(port_array)); + add_device(port_array[i]); + port_array[i]->port_count = port_count; + spin_lock_init(&port_array[i]->lock); + } + + /* Allocate and claim adapter resources */ + if (!claim_resources(port_array[0])) { + + alloc_dma_bufs(port_array[0]); + + /* copy resource information from first port to others */ + for (i = 1; i < port_count; ++i) { + port_array[i]->lock = port_array[0]->lock; + port_array[i]->irq_level = port_array[0]->irq_level; + port_array[i]->reg_addr = port_array[0]->reg_addr; + alloc_dma_bufs(port_array[i]); + } + + if (request_irq(port_array[0]->irq_level, + slgt_interrupt, + port_array[0]->irq_flags, + port_array[0]->device_name, + port_array[0]) < 0) { + DBGERR(("%s request_irq failed IRQ=%d\n", + port_array[0]->device_name, + port_array[0]->irq_level)); + } else { + port_array[0]->irq_requested = 1; + adapter_test(port_array[0]); + for (i=1 ; i < port_count ; i++) + port_array[i]->init_error = port_array[0]->init_error; + } + } +} + +static int __devinit init_one(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + if (pci_enable_device(dev)) { + printk("error enabling pci device %p\n", dev); + return -EIO; + } + pci_set_master(dev); + device_init(slgt_device_count, dev); + return 0; +} + +static void __devexit remove_one(struct pci_dev *dev) +{ +} + +static struct tty_operations ops = { + .open = open, + .close = close, + .write = write, + .put_char = put_char, + .flush_chars = flush_chars, + .write_room = write_room, + .chars_in_buffer = chars_in_buffer, + .flush_buffer = flush_buffer, + .ioctl = ioctl, + .throttle = throttle, + .unthrottle = unthrottle, + .send_xchar = send_xchar, + .break_ctl = set_break, + .wait_until_sent = wait_until_sent, + .read_proc = read_proc, + .set_termios = set_termios, + .stop = tx_hold, + .start = tx_release, + .hangup = hangup, + .tiocmget = tiocmget, + .tiocmset = tiocmset, +}; + +static void slgt_cleanup(void) +{ + int rc; + struct slgt_info *info; + struct slgt_info *tmp; + + printk("unload %s %s\n", driver_name, driver_version); + + if (serial_driver) { + if ((rc = tty_unregister_driver(serial_driver))) + DBGERR(("tty_unregister_driver error=%d\n", rc)); + put_tty_driver(serial_driver); + } + + /* reset devices */ + info = slgt_device_list; + while(info) { + reset_port(info); + info = info->next_device; + } + + /* release devices */ + info = slgt_device_list; + while(info) { +#ifdef CONFIG_HDLC + hdlcdev_exit(info); +#endif + free_dma_bufs(info); + free_tmp_rbuf(info); + if (info->port_num == 0) + release_resources(info); + tmp = info; + info = info->next_device; + kfree(tmp); + } + + if (pci_registered) + pci_unregister_driver(&pci_driver); +} + +/* + * Driver initialization entry point. + */ +static int __init slgt_init(void) +{ + int rc; + + printk("%s %s\n", driver_name, driver_version); + + slgt_device_count = 0; + if ((rc = pci_register_driver(&pci_driver)) < 0) { + printk("%s pci_register_driver error=%d\n", driver_name, rc); + return rc; + } + pci_registered = 1; + + if (!slgt_device_list) { + printk("%s no devices found\n",driver_name); + return -ENODEV; + } + + serial_driver = alloc_tty_driver(MAX_DEVICES); + if (!serial_driver) { + rc = -ENOMEM; + goto error; + } + + /* Initialize the tty_driver structure */ + + serial_driver->owner = THIS_MODULE; + serial_driver->driver_name = tty_driver_name; + serial_driver->name = tty_dev_prefix; + serial_driver->major = ttymajor; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(serial_driver, &ops); + if ((rc = tty_register_driver(serial_driver)) < 0) { + DBGERR(("%s can't register serial driver\n", driver_name)); + put_tty_driver(serial_driver); + serial_driver = NULL; + goto error; + } + + printk("%s %s, tty major#%d\n", + driver_name, driver_version, + serial_driver->major); + + return 0; + +error: + slgt_cleanup(); + return rc; +} + +static void __exit slgt_exit(void) +{ + slgt_cleanup(); +} + +module_init(slgt_init); +module_exit(slgt_exit); + +/* + * register access routines + */ + +#define CALC_REGADDR() \ + unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \ + if (addr >= 0x80) \ + reg_addr += (info->port_num) * 32; + +static __u8 rd_reg8(struct slgt_info *info, unsigned int addr) +{ + CALC_REGADDR(); + return readb((void __iomem *)reg_addr); +} + +static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value) +{ + CALC_REGADDR(); + writeb(value, (void __iomem *)reg_addr); +} + +static __u16 rd_reg16(struct slgt_info *info, unsigned int addr) +{ + CALC_REGADDR(); + return readw((void __iomem *)reg_addr); +} + +static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value) +{ + CALC_REGADDR(); + writew(value, (void __iomem *)reg_addr); +} + +static __u32 rd_reg32(struct slgt_info *info, unsigned int addr) +{ + CALC_REGADDR(); + return readl((void __iomem *)reg_addr); +} + +static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value) +{ + CALC_REGADDR(); + writel(value, (void __iomem *)reg_addr); +} + +static void rdma_reset(struct slgt_info *info) +{ + unsigned int i; + + /* set reset bit */ + wr_reg32(info, RDCSR, BIT1); + + /* wait for enable bit cleared */ + for(i=0 ; i < 1000 ; i++) + if (!(rd_reg32(info, RDCSR) & BIT0)) + break; +} + +static void tdma_reset(struct slgt_info *info) +{ + unsigned int i; + + /* set reset bit */ + wr_reg32(info, TDCSR, BIT1); + + /* wait for enable bit cleared */ + for(i=0 ; i < 1000 ; i++) + if (!(rd_reg32(info, TDCSR) & BIT0)) + break; +} + +/* + * enable internal loopback + * TxCLK and RxCLK are generated from BRG + * and TxD is looped back to RxD internally. + */ +static void enable_loopback(struct slgt_info *info) +{ + /* SCR (serial control) BIT2=looopback enable */ + wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2)); + + if (info->params.mode != MGSL_MODE_ASYNC) { + /* CCR (clock control) + * 07..05 tx clock source (010 = BRG) + * 04..02 rx clock source (010 = BRG) + * 01 auxclk enable (0 = disable) + * 00 BRG enable (1 = enable) + * + * 0100 1001 + */ + wr_reg8(info, CCR, 0x49); + + /* set speed if available, otherwise use default */ + if (info->params.clock_speed) + set_rate(info, info->params.clock_speed); + else + set_rate(info, 3686400); + } +} + +/* + * set baud rate generator to specified rate + */ +static void set_rate(struct slgt_info *info, u32 rate) +{ + unsigned int div; + static unsigned int osc = 14745600; + + /* div = osc/rate - 1 + * + * Round div up if osc/rate is not integer to + * force to next slowest rate. + */ + + if (rate) { + div = osc/rate; + if (!(osc % rate) && div) + div--; + wr_reg16(info, BDR, (unsigned short)div); + } +} + +static void rx_stop(struct slgt_info *info) +{ + unsigned short val; + + /* disable and reset receiver */ + val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ + wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, RCR, val); /* clear reset bit */ + + slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE); + + /* clear pending rx interrupts */ + wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER); + + rdma_reset(info); + + info->rx_enabled = 0; + info->rx_restart = 0; +} + +static void rx_start(struct slgt_info *info) +{ + unsigned short val; + + slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA); + + /* clear pending rx overrun IRQ */ + wr_reg16(info, SSR, IRQ_RXOVER); + + /* reset and disable receiver */ + val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ + wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, RCR, val); /* clear reset bit */ + + rdma_reset(info); + reset_rbufs(info); + + /* set 1st descriptor address */ + wr_reg32(info, RDDAR, info->rbufs[0].pdesc); + + if (info->params.mode != MGSL_MODE_ASYNC) { + /* enable rx DMA and DMA interrupt */ + wr_reg32(info, RDCSR, (BIT2 + BIT0)); + } else { + /* enable saving of rx status, rx DMA and DMA interrupt */ + wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); + } + + slgt_irq_on(info, IRQ_RXOVER); + + /* enable receiver */ + wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1)); + + info->rx_restart = 0; + info->rx_enabled = 1; +} + +static void tx_start(struct slgt_info *info) +{ + if (!info->tx_enabled) { + wr_reg16(info, TCR, + (unsigned short)(rd_reg16(info, TCR) | BIT1)); + info->tx_enabled = TRUE; + } + + if (info->tx_count) { + info->drop_rts_on_tx_done = 0; + + if (info->params.mode != MGSL_MODE_ASYNC) { + if (info->params.flags & HDLC_FLAG_AUTO_RTS) { + get_signals(info); + if (!(info->signals & SerialSignal_RTS)) { + info->signals |= SerialSignal_RTS; + set_signals(info); + info->drop_rts_on_tx_done = 1; + } + } + + slgt_irq_off(info, IRQ_TXDATA); + slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); + /* clear tx idle and underrun status bits */ + wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); + + if (!(rd_reg32(info, TDCSR) & BIT0)) { + /* tx DMA stopped, restart tx DMA */ + tdma_reset(info); + /* set 1st descriptor address */ + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); + if (info->params.mode == MGSL_MODE_RAW) + wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */ + else + wr_reg32(info, TDCSR, BIT0); /* DMA enable */ + } + + if (info->params.mode != MGSL_MODE_RAW) { + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); + add_timer(&info->tx_timer); + } + } else { + tdma_reset(info); + /* set 1st descriptor address */ + wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); + + slgt_irq_off(info, IRQ_TXDATA); + slgt_irq_on(info, IRQ_TXIDLE); + /* clear tx idle status bit */ + wr_reg16(info, SSR, IRQ_TXIDLE); + + /* enable tx DMA */ + wr_reg32(info, TDCSR, BIT0); + } + + info->tx_active = 1; + } +} + +static void tx_stop(struct slgt_info *info) +{ + unsigned short val; + + del_timer(&info->tx_timer); + + tdma_reset(info); + + /* reset and disable transmitter */ + val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ + wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ + wr_reg16(info, TCR, val); /* clear reset */ + + slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); + + /* clear tx idle and underrun status bit */ + wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); + + reset_tbufs(info); + + info->tx_enabled = 0; + info->tx_active = 0; +} + +static void reset_port(struct slgt_info *info) +{ + if (!info->reg_addr) + return; + + tx_stop(info); + rx_stop(info); + + info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + set_signals(info); + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); +} + +static void reset_adapter(struct slgt_info *info) +{ + int i; + for (i=0; i < info->port_count; ++i) { + if (info->port_array[i]) + reset_port(info->port_array[i]); + } +} + +static void async_mode(struct slgt_info *info) +{ + unsigned short val; + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); + tx_stop(info); + rx_stop(info); + + /* TCR (tx control) + * + * 15..13 mode, 010=async + * 12..10 encoding, 000=NRZ + * 09 parity enable + * 08 1=odd parity, 0=even parity + * 07 1=RTS driver control + * 06 1=break enable + * 05..04 character length + * 00=5 bits + * 01=6 bits + * 10=7 bits + * 11=8 bits + * 03 0=1 stop bit, 1=2 stop bits + * 02 reset + * 01 enable + * 00 auto-CTS enable + */ + val = 0x4000; + + if (info->if_mode & MGSL_INTERFACE_RTS_EN) + val |= BIT7; + + if (info->params.parity != ASYNC_PARITY_NONE) { + val |= BIT9; + if (info->params.parity == ASYNC_PARITY_ODD) + val |= BIT8; + } + + switch (info->params.data_bits) + { + case 6: val |= BIT4; break; + case 7: val |= BIT5; break; + case 8: val |= BIT5 + BIT4; break; + } + + if (info->params.stop_bits != 1) + val |= BIT3; + + if (info->params.flags & HDLC_FLAG_AUTO_CTS) + val |= BIT0; + + wr_reg16(info, TCR, val); + + /* RCR (rx control) + * + * 15..13 mode, 010=async + * 12..10 encoding, 000=NRZ + * 09 parity enable + * 08 1=odd parity, 0=even parity + * 07..06 reserved, must be 0 + * 05..04 character length + * 00=5 bits + * 01=6 bits + * 10=7 bits + * 11=8 bits + * 03 reserved, must be zero + * 02 reset + * 01 enable + * 00 auto-DCD enable + */ + val = 0x4000; + + if (info->params.parity != ASYNC_PARITY_NONE) { + val |= BIT9; + if (info->params.parity == ASYNC_PARITY_ODD) + val |= BIT8; + } + + switch (info->params.data_bits) + { + case 6: val |= BIT4; break; + case 7: val |= BIT5; break; + case 8: val |= BIT5 + BIT4; break; + } + + if (info->params.flags & HDLC_FLAG_AUTO_DCD) + val |= BIT0; + + wr_reg16(info, RCR, val); + + /* CCR (clock control) + * + * 07..05 011 = tx clock source is BRG/16 + * 04..02 010 = rx clock source is BRG + * 01 0 = auxclk disabled + * 00 1 = BRG enabled + * + * 0110 1001 + */ + wr_reg8(info, CCR, 0x69); + + msc_set_vcr(info); + + tx_set_idle(info); + + /* SCR (serial control) + * + * 15 1=tx req on FIFO half empty + * 14 1=rx req on FIFO half full + * 13 tx data IRQ enable + * 12 tx idle IRQ enable + * 11 rx break on IRQ enable + * 10 rx data IRQ enable + * 09 rx break off IRQ enable + * 08 overrun IRQ enable + * 07 DSR IRQ enable + * 06 CTS IRQ enable + * 05 DCD IRQ enable + * 04 RI IRQ enable + * 03 reserved, must be zero + * 02 1=txd->rxd internal loopback enable + * 01 reserved, must be zero + * 00 1=master IRQ enable + */ + val = BIT15 + BIT14 + BIT0; + wr_reg16(info, SCR, val); + + slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER); + + set_rate(info, info->params.data_rate * 16); + + if (info->params.loopback) + enable_loopback(info); +} + +static void hdlc_mode(struct slgt_info *info) +{ + unsigned short val; + + slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); + tx_stop(info); + rx_stop(info); + + /* TCR (tx control) + * + * 15..13 mode, 000=HDLC 001=raw sync + * 12..10 encoding + * 09 CRC enable + * 08 CRC32 + * 07 1=RTS driver control + * 06 preamble enable + * 05..04 preamble length + * 03 share open/close flag + * 02 reset + * 01 enable + * 00 auto-CTS enable + */ + val = 0; + + if (info->params.mode == MGSL_MODE_RAW) + val |= BIT13; + if (info->if_mode & MGSL_INTERFACE_RTS_EN) + val |= BIT7; + + switch(info->params.encoding) + { + case HDLC_ENCODING_NRZB: val |= BIT10; break; + case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; + case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; + case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; + case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; + case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; + } + + switch (info->params.crc_type) + { + case HDLC_CRC_16_CCITT: val |= BIT9; break; + case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; + } + + if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) + val |= BIT6; + + switch (info->params.preamble_length) + { + case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break; + case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break; + case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break; + } + + if (info->params.flags & HDLC_FLAG_AUTO_CTS) + val |= BIT0; + + wr_reg16(info, TCR, val); + + /* TPR (transmit preamble) */ + + switch (info->params.preamble) + { + case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; + case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; + case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break; + case HDLC_PREAMBLE_PATTERN_10: val = 0x55; break; + case HDLC_PREAMBLE_PATTERN_01: val = 0xaa; break; + default: val = 0x7e; break; + } + wr_reg8(info, TPR, (unsigned char)val); + + /* RCR (rx control) + * + * 15..13 mode, 000=HDLC 001=raw sync + * 12..10 encoding + * 09 CRC enable + * 08 CRC32 + * 07..03 reserved, must be 0 + * 02 reset + * 01 enable + * 00 auto-DCD enable + */ + val = 0; + + if (info->params.mode == MGSL_MODE_RAW) + val |= BIT13; + + switch(info->params.encoding) + { + case HDLC_ENCODING_NRZB: val |= BIT10; break; + case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; + case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; + case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; + case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; + case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; + } + + switch (info->params.crc_type) + { + case HDLC_CRC_16_CCITT: val |= BIT9; break; + case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; + } + + if (info->params.flags & HDLC_FLAG_AUTO_DCD) + val |= BIT0; + + wr_reg16(info, RCR, val); + + /* CCR (clock control) + * + * 07..05 tx clock source + * 04..02 rx clock source + * 01 auxclk enable + * 00 BRG enable + */ + val = 0; + + if (info->params.flags & HDLC_FLAG_TXC_BRG) + { + // when RxC source is DPLL, BRG generates 16X DPLL + // reference clock, so take TxC from BRG/16 to get + // transmit clock at actual data rate + if (info->params.flags & HDLC_FLAG_RXC_DPLL) + val |= BIT6 + BIT5; /* 011, txclk = BRG/16 */ + else + val |= BIT6; /* 010, txclk = BRG */ + } + else if (info->params.flags & HDLC_FLAG_TXC_DPLL) + val |= BIT7; /* 100, txclk = DPLL Input */ + else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN) + val |= BIT5; /* 001, txclk = RXC Input */ + + if (info->params.flags & HDLC_FLAG_RXC_BRG) + val |= BIT3; /* 010, rxclk = BRG */ + else if (info->params.flags & HDLC_FLAG_RXC_DPLL) + val |= BIT4; /* 100, rxclk = DPLL */ + else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN) + val |= BIT2; /* 001, rxclk = TXC Input */ + + if (info->params.clock_speed) + val |= BIT1 + BIT0; + + wr_reg8(info, CCR, (unsigned char)val); + + if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL)) + { + // program DPLL mode + switch(info->params.encoding) + { + case HDLC_ENCODING_BIPHASE_MARK: + case HDLC_ENCODING_BIPHASE_SPACE: + val = BIT7; break; + case HDLC_ENCODING_BIPHASE_LEVEL: + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: + val = BIT7 + BIT6; break; + default: val = BIT6; // NRZ encodings + } + wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val)); + + // DPLL requires a 16X reference clock from BRG + set_rate(info, info->params.clock_speed * 16); + } + else + set_rate(info, info->params.clock_speed); + + tx_set_idle(info); + + msc_set_vcr(info); + + /* SCR (serial control) + * + * 15 1=tx req on FIFO half empty + * 14 1=rx req on FIFO half full + * 13 tx data IRQ enable + * 12 tx idle IRQ enable + * 11 underrun IRQ enable + * 10 rx data IRQ enable + * 09 rx idle IRQ enable + * 08 overrun IRQ enable + * 07 DSR IRQ enable + * 06 CTS IRQ enable + * 05 DCD IRQ enable + * 04 RI IRQ enable + * 03 reserved, must be zero + * 02 1=txd->rxd internal loopback enable + * 01 reserved, must be zero + * 00 1=master IRQ enable + */ + wr_reg16(info, SCR, BIT15 + BIT14 + BIT0); + + if (info->params.loopback) + enable_loopback(info); +} + +/* + * set transmit idle mode + */ +static void tx_set_idle(struct slgt_info *info) +{ + unsigned char val = 0xff; + + switch(info->idle_mode) + { + case HDLC_TXIDLE_FLAGS: val = 0x7e; break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break; + case HDLC_TXIDLE_ZEROS: val = 0x00; break; + case HDLC_TXIDLE_ONES: val = 0xff; break; + case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break; + case HDLC_TXIDLE_SPACE: val = 0x00; break; + case HDLC_TXIDLE_MARK: val = 0xff; break; + } + + wr_reg8(info, TIR, val); +} + +/* + * get state of V24 status (input) signals + */ +static void get_signals(struct slgt_info *info) +{ + unsigned short status = rd_reg16(info, SSR); + + /* clear all serial signals except DTR and RTS */ + info->signals &= SerialSignal_DTR + SerialSignal_RTS; + + if (status & BIT3) + info->signals |= SerialSignal_DSR; + if (status & BIT2) + info->signals |= SerialSignal_CTS; + if (status & BIT1) + info->signals |= SerialSignal_DCD; + if (status & BIT0) + info->signals |= SerialSignal_RI; +} + +/* + * set V.24 Control Register based on current configuration + */ +static void msc_set_vcr(struct slgt_info *info) +{ + unsigned char val = 0; + + /* VCR (V.24 control) + * + * 07..04 serial IF select + * 03 DTR + * 02 RTS + * 01 LL + * 00 RL + */ + + switch(info->if_mode & MGSL_INTERFACE_MASK) + { + case MGSL_INTERFACE_RS232: + val |= BIT5; /* 0010 */ + break; + case MGSL_INTERFACE_V35: + val |= BIT7 + BIT6 + BIT5; /* 1110 */ + break; + case MGSL_INTERFACE_RS422: + val |= BIT6; /* 0100 */ + break; + } + + if (info->signals & SerialSignal_DTR) + val |= BIT3; + if (info->signals & SerialSignal_RTS) + val |= BIT2; + if (info->if_mode & MGSL_INTERFACE_LL) + val |= BIT1; + if (info->if_mode & MGSL_INTERFACE_RL) + val |= BIT0; + wr_reg8(info, VCR, val); +} + +/* + * set state of V24 control (output) signals + */ +static void set_signals(struct slgt_info *info) +{ + unsigned char val = rd_reg8(info, VCR); + if (info->signals & SerialSignal_DTR) + val |= BIT3; + else + val &= ~BIT3; + if (info->signals & SerialSignal_RTS) + val |= BIT2; + else + val &= ~BIT2; + wr_reg8(info, VCR, val); +} + +/* + * free range of receive DMA buffers (i to last) + */ +static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last) +{ + int done = 0; + + while(!done) { + /* reset current buffer for reuse */ + info->rbufs[i].status = 0; + if (info->params.mode == MGSL_MODE_RAW) + set_desc_count(info->rbufs[i], info->raw_rx_size); + else + set_desc_count(info->rbufs[i], DMABUFSIZE); + + if (i == last) + done = 1; + if (++i == info->rbuf_count) + i = 0; + } + info->rbuf_current = i; +} + +/* + * mark all receive DMA buffers as free + */ +static void reset_rbufs(struct slgt_info *info) +{ + free_rbufs(info, 0, info->rbuf_count - 1); +} + +/* + * pass receive HDLC frame to upper layer + * + * return 1 if frame available, otherwise 0 + */ +static int rx_get_frame(struct slgt_info *info) +{ + unsigned int start, end; + unsigned short status; + unsigned int framesize = 0; + int rc = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + unsigned char addr_field = 0xff; + +check_again: + + framesize = 0; + addr_field = 0xff; + start = end = info->rbuf_current; + + for (;;) { + if (!desc_complete(info->rbufs[end])) + goto cleanup; + + if (framesize == 0 && info->params.addr_filter != 0xff) + addr_field = info->rbufs[end].buf[0]; + + framesize += desc_count(info->rbufs[end]); + + if (desc_eof(info->rbufs[end])) + break; + + if (++end == info->rbuf_count) + end = 0; + + if (end == info->rbuf_current) { + if (info->rx_enabled){ + spin_lock_irqsave(&info->lock,flags); + rx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + goto cleanup; + } + } + + /* status + * + * 15 buffer complete + * 14..06 reserved + * 05..04 residue + * 02 eof (end of frame) + * 01 CRC error + * 00 abort + */ + status = desc_status(info->rbufs[end]); + + /* ignore CRC bit if not using CRC (bit is undefined) */ + if (info->params.crc_type == HDLC_CRC_NONE) + status &= ~BIT1; + + if (framesize == 0 || + (addr_field != 0xff && addr_field != info->params.addr_filter)) { + free_rbufs(info, start, end); + goto check_again; + } + + if (framesize < 2 || status & (BIT1+BIT0)) { + if (framesize < 2 || (status & BIT0)) + info->icount.rxshort++; + else + info->icount.rxcrc++; + framesize = 0; + +#ifdef CONFIG_HDLC + { + struct net_device_stats *stats = hdlc_stats(info->netdev); + stats->rx_errors++; + stats->rx_frame_errors++; + } +#endif + } else { + /* adjust frame size for CRC, if any */ + if (info->params.crc_type == HDLC_CRC_16_CCITT) + framesize -= 2; + else if (info->params.crc_type == HDLC_CRC_32_CCITT) + framesize -= 4; + } + + DBGBH(("%s rx frame status=%04X size=%d\n", + info->device_name, status, framesize)); + DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx"); + + if (framesize) { + if (framesize > info->max_frame_size) + info->icount.rxlong++; + else { + /* copy dma buffer(s) to contiguous temp buffer */ + int copy_count = framesize; + int i = start; + unsigned char *p = info->tmp_rbuf; + info->tmp_rbuf_count = framesize; + + info->icount.rxok++; + + while(copy_count) { + int partial_count = min(copy_count, DMABUFSIZE); + memcpy(p, info->rbufs[i].buf, partial_count); + p += partial_count; + copy_count -= partial_count; + if (++i == info->rbuf_count) + i = 0; + } + +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_rx(info,info->tmp_rbuf, framesize); + else +#endif + ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize); + } + } + free_rbufs(info, start, end); + rc = 1; + +cleanup: + return rc; +} + +/* + * pass receive buffer (RAW synchronous mode) to tty layer + * return 1 if buffer available, otherwise 0 + */ +static int rx_get_buf(struct slgt_info *info) +{ + unsigned int i = info->rbuf_current; + + if (!desc_complete(info->rbufs[i])) + return 0; + DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx"); + DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i]))); + ldisc_receive_buf(info->tty, info->rbufs[i].buf, + info->flag_buf, desc_count(info->rbufs[i])); + free_rbufs(info, i, i); + return 1; +} + +static void reset_tbufs(struct slgt_info *info) +{ + unsigned int i; + info->tbuf_current = 0; + for (i=0 ; i < info->tbuf_count ; i++) { + info->tbufs[i].status = 0; + info->tbufs[i].count = 0; + } +} + +/* + * return number of free transmit DMA buffers + */ +static unsigned int free_tbuf_count(struct slgt_info *info) +{ + unsigned int count = 0; + unsigned int i = info->tbuf_current; + + do + { + if (desc_count(info->tbufs[i])) + break; /* buffer in use */ + ++count; + if (++i == info->tbuf_count) + i=0; + } while (i != info->tbuf_current); + + /* last buffer with zero count may be in use, assume it is */ + if (count) + --count; + + return count; +} + +/* + * load transmit DMA buffer(s) with data + */ +static void tx_load(struct slgt_info *info, const char *buf, unsigned int size) +{ + unsigned short count; + unsigned int i; + struct slgt_desc *d; + + if (size == 0) + return; + + DBGDATA(info, buf, size, "tx"); + + info->tbuf_start = i = info->tbuf_current; + + while (size) { + d = &info->tbufs[i]; + if (++i == info->tbuf_count) + i = 0; + + count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size); + memcpy(d->buf, buf, count); + + size -= count; + buf += count; + + if (!size && info->params.mode != MGSL_MODE_RAW) + set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */ + else + set_desc_eof(*d, 0); + + set_desc_count(*d, count); + } + + info->tbuf_current = i; +} + +static int register_test(struct slgt_info *info) +{ + static unsigned short patterns[] = + {0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696}; + static unsigned int count = sizeof(patterns)/sizeof(patterns[0]); + unsigned int i; + int rc = 0; + + for (i=0 ; i < count ; i++) { + wr_reg16(info, TIR, patterns[i]); + wr_reg16(info, BDR, patterns[(i+1)%count]); + if ((rd_reg16(info, TIR) != patterns[i]) || + (rd_reg16(info, BDR) != patterns[(i+1)%count])) { + rc = -ENODEV; + break; + } + } + + info->init_error = rc ? 0 : DiagStatus_AddressFailure; + return rc; +} + +static int irq_test(struct slgt_info *info) +{ + unsigned long timeout; + unsigned long flags; + struct tty_struct *oldtty = info->tty; + u32 speed = info->params.data_rate; + + info->params.data_rate = 921600; + info->tty = NULL; + + spin_lock_irqsave(&info->lock, flags); + async_mode(info); + slgt_irq_on(info, IRQ_TXIDLE); + + /* enable transmitter */ + wr_reg16(info, TCR, + (unsigned short)(rd_reg16(info, TCR) | BIT1)); + + /* write one byte and wait for tx idle */ + wr_reg16(info, TDR, 0); + + /* assume failure */ + info->init_error = DiagStatus_IrqFailure; + info->irq_occurred = FALSE; + + spin_unlock_irqrestore(&info->lock, flags); + + timeout=100; + while(timeout-- && !info->irq_occurred) + msleep_interruptible(10); + + spin_lock_irqsave(&info->lock,flags); + reset_port(info); + spin_unlock_irqrestore(&info->lock,flags); + + info->params.data_rate = speed; + info->tty = oldtty; + + info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure; + return info->irq_occurred ? 0 : -ENODEV; +} + +static int loopback_test_rx(struct slgt_info *info) +{ + unsigned char *src, *dest; + int count; + + if (desc_complete(info->rbufs[0])) { + count = desc_count(info->rbufs[0]); + src = info->rbufs[0].buf; + dest = info->tmp_rbuf; + + for( ; count ; count-=2, src+=2) { + /* src=data byte (src+1)=status byte */ + if (!(*(src+1) & (BIT9 + BIT8))) { + *dest = *src; + dest++; + info->tmp_rbuf_count++; + } + } + DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx"); + return 1; + } + return 0; +} + +static int loopback_test(struct slgt_info *info) +{ +#define TESTFRAMESIZE 20 + + unsigned long timeout; + u16 count = TESTFRAMESIZE; + unsigned char buf[TESTFRAMESIZE]; + int rc = -ENODEV; + unsigned long flags; + + struct tty_struct *oldtty = info->tty; + MGSL_PARAMS params; + + memcpy(¶ms, &info->params, sizeof(params)); + + info->params.mode = MGSL_MODE_ASYNC; + info->params.data_rate = 921600; + info->params.loopback = 1; + info->tty = NULL; + + /* build and send transmit frame */ + for (count = 0; count < TESTFRAMESIZE; ++count) + buf[count] = (unsigned char)count; + + info->tmp_rbuf_count = 0; + memset(info->tmp_rbuf, 0, TESTFRAMESIZE); + + /* program hardware for HDLC and enabled receiver */ + spin_lock_irqsave(&info->lock,flags); + async_mode(info); + rx_start(info); + info->tx_count = count; + tx_load(info, buf, count); + tx_start(info); + spin_unlock_irqrestore(&info->lock, flags); + + /* wait for receive complete */ + for (timeout = 100; timeout; --timeout) { + msleep_interruptible(10); + if (loopback_test_rx(info)) { + rc = 0; + break; + } + } + + /* verify received frame length and contents */ + if (!rc && (info->tmp_rbuf_count != count || + memcmp(buf, info->tmp_rbuf, count))) { + rc = -ENODEV; + } + + spin_lock_irqsave(&info->lock,flags); + reset_adapter(info); + spin_unlock_irqrestore(&info->lock,flags); + + memcpy(&info->params, ¶ms, sizeof(info->params)); + info->tty = oldtty; + + info->init_error = rc ? DiagStatus_DmaFailure : 0; + return rc; +} + +static int adapter_test(struct slgt_info *info) +{ + DBGINFO(("testing %s\n", info->device_name)); + if ((info->init_error = register_test(info)) < 0) { + printk("register test failure %s addr=%08X\n", + info->device_name, info->phys_reg_addr); + } else if ((info->init_error = irq_test(info)) < 0) { + printk("IRQ test failure %s IRQ=%d\n", + info->device_name, info->irq_level); + } else if ((info->init_error = loopback_test(info)) < 0) { + printk("loopback test failure %s\n", info->device_name); + } + return info->init_error; +} + +/* + * transmit timeout handler + */ +static void tx_timeout(unsigned long context) +{ + struct slgt_info *info = (struct slgt_info*)context; + unsigned long flags; + + DBGINFO(("%s tx_timeout\n", info->device_name)); + if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + info->icount.txtimeout++; + } + spin_lock_irqsave(&info->lock,flags); + info->tx_active = 0; + info->tx_count = 0; + spin_unlock_irqrestore(&info->lock,flags); + +#ifdef CONFIG_HDLC + if (info->netcount) + hdlcdev_tx_done(info); + else +#endif + bh_transmit(info); +} + +/* + * receive buffer polling timer + */ +static void rx_timeout(unsigned long context) +{ + struct slgt_info *info = (struct slgt_info*)context; + unsigned long flags; + + DBGINFO(("%s rx_timeout\n", info->device_name)); + spin_lock_irqsave(&info->lock, flags); + info->pending_bh |= BH_RECEIVE; + spin_unlock_irqrestore(&info->lock, flags); + bh_handler(info); +} + diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 2392e404e8d..ba4582d160f 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,6 +2,9 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o +ifdef CONFIG_ACPI + obj-$(CONFIG_TCG_TPM) += tpm_bios.o +endif obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index a9be0e8eaea..5a3870477ef 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -466,6 +466,7 @@ void tpm_remove_hardware(struct device *dev) kfree(chip->vendor->miscdev.name); sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); + tpm_bios_log_teardown(chip->bios_dir); dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); @@ -593,6 +594,8 @@ dev_num_search_complete: sysfs_create_group(&dev->kobj, chip->vendor->attr_group); + chip->bios_dir = tpm_bios_log_setup(devname); + return 0; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 159882ca69d..fd3a4beaa53 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -82,6 +82,8 @@ struct tpm_chip { struct tpm_vendor_specific *vendor; + struct dentry **bios_dir; + struct list_head list; }; @@ -107,3 +109,16 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); extern void tpm_remove_hardware(struct device *); extern int tpm_pm_suspend(struct device *, pm_message_t); extern int tpm_pm_resume(struct device *); + +#ifdef CONFIG_ACPI +extern struct dentry ** tpm_bios_log_setup(char *); +extern void tpm_bios_log_teardown(struct dentry **); +#else +static inline struct dentry* tpm_bios_log_setup(char *name) +{ + return NULL; +} +static inline void tpm_bios_log_teardown(struct dentry **dir) +{ +} +#endif diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c new file mode 100644 index 00000000000..aedf7a8e6da --- /dev/null +++ b/drivers/char/tpm/tpm_bios.c @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2005 IBM Corporation + * + * Authors: + * Seiji Munetoh <munetoh@jp.ibm.com> + * Stefan Berger <stefanb@us.ibm.com> + * Reiner Sailer <sailer@watson.ibm.com> + * Kylene Hall <kjhall@us.ibm.com> + * + * Access to the eventlog extended by the TCG BIOS of PC platform + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/seq_file.h> +#include <linux/fs.h> +#include <linux/security.h> +#include <linux/module.h> +#include <acpi/acpi.h> +#include <acpi/actypes.h> +#include <acpi/actbl.h> +#include "tpm.h" + +#define TCG_EVENT_NAME_LEN_MAX 255 +#define MAX_TEXT_EVENT 1000 /* Max event string length */ +#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ + +struct tpm_bios_log { + void *bios_event_log; + void *bios_event_log_end; +}; + +struct acpi_tcpa { + struct acpi_table_header hdr; + u16 reserved; + u32 log_max_len __attribute__ ((packed)); + u32 log_start_addr __attribute__ ((packed)); +}; + +struct tcpa_event { + u32 pcr_index; + u32 event_type; + u8 pcr_value[20]; /* SHA1 */ + u32 event_size; + u8 event_data[0]; +}; + +enum tcpa_event_types { + PREBOOT = 0, + POST_CODE, + UNUSED, + NO_ACTION, + SEPARATOR, + ACTION, + EVENT_TAG, + SCRTM_CONTENTS, + SCRTM_VERSION, + CPU_MICROCODE, + PLATFORM_CONFIG_FLAGS, + TABLE_OF_DEVICES, + COMPACT_HASH, + IPL, + IPL_PARTITION_DATA, + NONHOST_CODE, + NONHOST_CONFIG, + NONHOST_INFO, +}; + +static const char* tcpa_event_type_strings[] = { + "PREBOOT", + "POST CODE", + "", + "NO ACTION", + "SEPARATOR", + "ACTION", + "EVENT TAG", + "S-CRTM Contents", + "S-CRTM Version", + "CPU Microcode", + "Platform Config Flags", + "Table of Devices", + "Compact Hash", + "IPL", + "IPL Partition Data", + "Non-Host Code", + "Non-Host Config", + "Non-Host Info" +}; + +enum tcpa_pc_event_ids { + SMBIOS = 1, + BIS_CERT, + POST_BIOS_ROM, + ESCD, + CMOS, + NVRAM, + OPTION_ROM_EXEC, + OPTION_ROM_CONFIG, + OPTION_ROM_MICROCODE, + S_CRTM_VERSION, + S_CRTM_CONTENTS, + POST_CONTENTS, +}; + +static const char* tcpa_pc_event_id_strings[] = { + "" + "SMBIOS", + "BIS Certificate", + "POST BIOS ", + "ESCD ", + "CMOS", + "NVRAM", + "Option ROM", + "Option ROM config", + "Option ROM microcode", + "S-CRTM Version", + "S-CRTM Contents", + "S-CRTM POST Contents", +}; + +/* returns pointer to start of pos. entry of tcg log */ +static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + loff_t i; + struct tpm_bios_log *log = m->private; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; + struct tcpa_event *event; + + /* read over *pos measurements */ + for (i = 0; i < *pos; i++) { + event = addr; + + if ((addr + sizeof(struct tcpa_event)) < limit) { + if (event->event_type == 0 && event->event_size == 0) + return NULL; + addr += sizeof(struct tcpa_event) + event->event_size; + } + } + + /* now check if current entry is valid */ + if ((addr + sizeof(struct tcpa_event)) >= limit) + return NULL; + + event = addr; + + if ((event->event_type == 0 && event->event_size == 0) || + ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit)) + return NULL; + + return addr; +} + +static void *tpm_bios_measurements_next(struct seq_file *m, void *v, + loff_t *pos) +{ + struct tcpa_event *event = v; + struct tpm_bios_log *log = m->private; + void *limit = log->bios_event_log_end; + + v += sizeof(struct tcpa_event) + event->event_size; + + /* now check if current entry is valid */ + if ((v + sizeof(struct tcpa_event)) >= limit) + return NULL; + + event = v; + + if (event->event_type == 0 && event->event_size == 0) + return NULL; + + if ((event->event_type == 0 && event->event_size == 0) || + ((v + sizeof(struct tcpa_event) + event->event_size) >= limit)) + return NULL; + + (*pos)++; + return v; +} + +static void tpm_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +static int get_event_name(char *dest, struct tcpa_event *event, + unsigned char * event_entry) +{ + const char *name = ""; + char data[40] = ""; + int i, n_len = 0, d_len = 0; + u32 event_id, event_data_size; + + switch(event->event_type) { + case PREBOOT: + case POST_CODE: + case UNUSED: + case NO_ACTION: + case SCRTM_CONTENTS: + case SCRTM_VERSION: + case CPU_MICROCODE: + case PLATFORM_CONFIG_FLAGS: + case TABLE_OF_DEVICES: + case COMPACT_HASH: + case IPL: + case IPL_PARTITION_DATA: + case NONHOST_CODE: + case NONHOST_CONFIG: + case NONHOST_INFO: + name = tcpa_event_type_strings[event->event_type]; + n_len = strlen(name); + break; + case SEPARATOR: + case ACTION: + if (MAX_TEXT_EVENT > event->event_size) { + name = event_entry; + n_len = event->event_size; + } + break; + case EVENT_TAG: + event_id = be32_to_cpu(event_entry); + event_data_size = be32_to_cpu(&event_entry[4]); + + /* ToDo Row data -> Base64 */ + + switch (event_id) { + case SMBIOS: + case BIS_CERT: + case CMOS: + case NVRAM: + case OPTION_ROM_EXEC: + case OPTION_ROM_CONFIG: + case OPTION_ROM_MICROCODE: + case S_CRTM_VERSION: + case S_CRTM_CONTENTS: + case POST_CONTENTS: + name = tcpa_pc_event_id_strings[event_id]; + n_len = strlen(name); + break; + case POST_BIOS_ROM: + case ESCD: + name = tcpa_pc_event_id_strings[event_id]; + n_len = strlen(name); + for (i = 0; i < 20; i++) + d_len += sprintf(data, "%02x", + event_entry[8 + i]); + break; + default: + break; + } + default: + break; + } + + return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]", + n_len, name, d_len, data); + +} + +static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) +{ + + char *eventname; + char data[4]; + u32 help; + int i, len; + struct tcpa_event *event = (struct tcpa_event *) v; + unsigned char *event_entry = + (unsigned char *) (v + sizeof(struct tcpa_event)); + + eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); + if (!eventname) { + printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", + __func__); + return -ENOMEM; + } + + /* 1st: PCR used is in little-endian format (4 bytes) */ + help = le32_to_cpu(event->pcr_index); + memcpy(data, &help, 4); + for (i = 0; i < 4; i++) + seq_putc(m, data[i]); + + /* 2nd: SHA1 (20 bytes) */ + for (i = 0; i < 20; i++) + seq_putc(m, event->pcr_value[i]); + + /* 3rd: event type identifier (4 bytes) */ + help = le32_to_cpu(event->event_type); + memcpy(data, &help, 4); + for (i = 0; i < 4; i++) + seq_putc(m, data[i]); + + len = 0; + + len += get_event_name(eventname, event, event_entry); + + /* 4th: filename <= 255 + \'0' delimiter */ + if (len > TCG_EVENT_NAME_LEN_MAX) + len = TCG_EVENT_NAME_LEN_MAX; + + for (i = 0; i < len; i++) + seq_putc(m, eventname[i]); + + /* 5th: delimiter */ + seq_putc(m, '\0'); + + return 0; +} + +static int tpm_bios_measurements_release(struct inode *inode, + struct file *file) +{ + struct seq_file *seq = file->private_data; + struct tpm_bios_log *log = seq->private; + + if (log) { + kfree(log->bios_event_log); + kfree(log); + } + + return seq_release(inode, file); +} + +static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) +{ + int len = 0; + int i; + char *eventname; + struct tcpa_event *event = v; + unsigned char *event_entry = + (unsigned char *) (v + sizeof(struct tcpa_event)); + + eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); + if (!eventname) { + printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", + __func__); + return -EFAULT; + } + + seq_printf(m, "%2d ", event->pcr_index); + + /* 2nd: SHA1 */ + for (i = 0; i < 20; i++) + seq_printf(m, "%02x", event->pcr_value[i]); + + /* 3rd: event type identifier */ + seq_printf(m, " %02x", event->event_type); + + len += get_event_name(eventname, event, event_entry); + + /* 4th: eventname <= max + \'0' delimiter */ + seq_printf(m, " %s\n", eventname); + + return 0; +} + +static struct seq_operations tpm_ascii_b_measurments_seqops = { + .start = tpm_bios_measurements_start, + .next = tpm_bios_measurements_next, + .stop = tpm_bios_measurements_stop, + .show = tpm_ascii_bios_measurements_show, +}; + +static struct seq_operations tpm_binary_b_measurments_seqops = { + .start = tpm_bios_measurements_start, + .next = tpm_bios_measurements_next, + .stop = tpm_bios_measurements_stop, + .show = tpm_binary_bios_measurements_show, +}; + +/* read binary bios log */ +static int read_log(struct tpm_bios_log *log) +{ + struct acpi_tcpa *buff; + acpi_status status; + void *virt; + + if (log->bios_event_log != NULL) { + printk(KERN_ERR + "%s: ERROR - Eventlog already initialized\n", + __func__); + return -EFAULT; + } + + /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ + status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1, + ACPI_LOGICAL_ADDRESSING, + (struct acpi_table_header **) + &buff); + + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", + __func__); + return -EIO; + } + + if (buff->log_max_len == 0) { + printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); + return -EIO; + } + + /* malloc EventLog space */ + log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL); + if (!log->bios_event_log) { + printk + ("%s: ERROR - Not enough Memory for BIOS measurements\n", + __func__); + return -ENOMEM; + } + + log->bios_event_log_end = log->bios_event_log + buff->log_max_len; + + acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, &virt); + + memcpy(log->bios_event_log, virt, buff->log_max_len); + + acpi_os_unmap_memory(virt, buff->log_max_len); + return 0; +} + +static int tpm_ascii_bios_measurements_open(struct inode *inode, + struct file *file) +{ + int err; + struct tpm_bios_log *log; + struct seq_file *seq; + + log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); + if (!log) + return -ENOMEM; + + if ((err = read_log(log))) + return err; + + /* now register seq file */ + err = seq_open(file, &tpm_ascii_b_measurments_seqops); + if (!err) { + seq = file->private_data; + seq->private = log; + } else { + kfree(log->bios_event_log); + kfree(log); + } + return err; +} + +struct file_operations tpm_ascii_bios_measurements_ops = { + .open = tpm_ascii_bios_measurements_open, + .read = seq_read, + .llseek = seq_lseek, + .release = tpm_bios_measurements_release, +}; + +static int tpm_binary_bios_measurements_open(struct inode *inode, + struct file *file) +{ + int err; + struct tpm_bios_log *log; + struct seq_file *seq; + + log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); + if (!log) + return -ENOMEM; + + if ((err = read_log(log))) + return err; + + /* now register seq file */ + err = seq_open(file, &tpm_binary_b_measurments_seqops); + if (!err) { + seq = file->private_data; + seq->private = log; + } else { + kfree(log->bios_event_log); + kfree(log); + } + return err; +} + +struct file_operations tpm_binary_bios_measurements_ops = { + .open = tpm_binary_bios_measurements_open, + .read = seq_read, + .llseek = seq_lseek, + .release = tpm_bios_measurements_release, +}; + +struct dentry **tpm_bios_log_setup(char *name) +{ + struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; + + tpm_dir = securityfs_create_dir(name, NULL); + if (!tpm_dir) + goto out; + + bin_file = + securityfs_create_file("binary_bios_measurements", + S_IRUSR | S_IRGRP, tpm_dir, NULL, + &tpm_binary_bios_measurements_ops); + if (!bin_file) + goto out_tpm; + + ascii_file = + securityfs_create_file("ascii_bios_measurements", + S_IRUSR | S_IRGRP, tpm_dir, NULL, + &tpm_ascii_bios_measurements_ops); + if (!ascii_file) + goto out_bin; + + ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); + if (!ret) + goto out_ascii; + + ret[0] = ascii_file; + ret[1] = bin_file; + ret[2] = tpm_dir; + + return ret; + +out_ascii: + securityfs_remove(ascii_file); +out_bin: + securityfs_remove(bin_file); +out_tpm: + securityfs_remove(tpm_dir); +out: + return NULL; +} +EXPORT_SYMBOL_GPL(tpm_bios_log_setup); + +void tpm_bios_log_teardown(struct dentry **lst) +{ + int i; + + for (i = 0; i < 3; i++) + securityfs_remove(lst[i]); +} +EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 9ac6d43437b..a5b18e086a9 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c @@ -718,7 +718,7 @@ static struct platform_driver giu_device_driver = { }, }; -static int __devinit vr41xx_giu_init(void) +static int __init vr41xx_giu_init(void) { int retval; @@ -733,7 +733,7 @@ static int __devinit vr41xx_giu_init(void) return retval; } -static void __devexit vr41xx_giu_exit(void) +static void __exit vr41xx_giu_exit(void) { platform_driver_unregister(&giu_device_driver); diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c index 44d49dfacbb..3843900e94c 100644 --- a/drivers/char/watchdog/wdt977.c +++ b/drivers/char/watchdog/wdt977.c @@ -1,5 +1,5 @@ /* - * Wdt977 0.03: A Watchdog Device for Netwinder W83977AF chip + * Wdt977 0.04: A Watchdog Device for Netwinder W83977AF chip * * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>) * @@ -18,6 +18,8 @@ * from minutes to seconds. * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in * nwwatchdog_init. + * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks + * remove limitiation to be used on Netwinders only */ #include <linux/module.h> @@ -28,6 +30,7 @@ #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/init.h> +#include <linux/ioport.h> #include <linux/watchdog.h> #include <linux/notifier.h> #include <linux/reboot.h> @@ -37,8 +40,18 @@ #include <asm/mach-types.h> #include <asm/uaccess.h> -#define PFX "Wdt977: " -#define WATCHDOG_MINOR 130 +#define WATCHDOG_VERSION "0.04" +#define WATCHDOG_NAME "Wdt977" +#define PFX WATCHDOG_NAME ": " +#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" + +#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ +#define IO_DATA_PORT (IO_INDEX_PORT+1) + +#define UNLOCK_DATA 0x87 +#define LOCK_DATA 0xAA +#define DEVICE_REGISTER 0x07 + #define DEFAULT_TIMEOUT 60 /* default timeout in seconds */ @@ -47,6 +60,7 @@ static int timeoutM; /* timeout in minutes */ static unsigned long timer_alive; static int testmode; static char expect_close; +static spinlock_t spinlock; module_param(timeout, int, 0); MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); @@ -63,9 +77,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON static int wdt977_start(void) { + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 * F2 has the timeout in minutes @@ -73,28 +91,29 @@ static int wdt977_start(void) * at timeout, and to reset timer on kbd/mouse activity (not impl.) * F4 is used to just clear the TIMEOUT'ed state (bit 0) */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ - outb(0xF4,0x370); - outb(0x00,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(timeoutM, IO_DATA_PORT); + outb_p(0xF3, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */ + outb_p(0xF4, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ /* in test mode watch the bit 1 on F4 to indicate "triggered" */ if (!testmode) { - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x07, IO_DATA_PORT); + outb_p(0xE6, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); } /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); printk(KERN_INFO PFX "activated.\n"); return 0; @@ -106,35 +125,39 @@ static int wdt977_start(void) static int wdt977_stop(void) { + unsigned long flags; + spin_lock_irqsave(&spinlock, flags); + /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 * F3 is reset to its default state * F4 can clear the TIMEOUT'ed state (bit 0) - back to default * We can not use GP17 as a PowerLed, as we use its usage as a RedLed */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(0xFF,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); - outb(0xF4,0x370); - outb(0x00,0x371); - outb(0xF2,0x370); - outb(0x00,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(0xFF, IO_DATA_PORT); + outb_p(0xF3, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); + outb_p(0xF4, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(0x00, IO_DATA_PORT); /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x07, IO_DATA_PORT); + outb_p(0xE6, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); printk(KERN_INFO PFX "shutdown.\n"); return 0; @@ -147,19 +170,23 @@ static int wdt977_stop(void) static int wdt977_keepalive(void) { + unsigned long flags; + spin_lock_irqsave(&spinlock, flags); + /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and kicks watchdog reg F2 */ /* F2 has the timeout in minutes */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF2, IO_INDEX_PORT); + outb_p(timeoutM, IO_DATA_PORT); /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); return 0; } @@ -198,22 +225,26 @@ static int wdt977_set_timeout(int t) static int wdt977_get_status(int *status) { int new_status; + unsigned long flags; - *status=0; + spin_lock_irqsave(&spinlock, flags); /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); + outb_p(UNLOCK_DATA, IO_INDEX_PORT); /* select device Aux2 (device=8) and read watchdog reg F4 */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF4,0x370); - new_status = inb(0x371); + outb_p(DEVICE_REGISTER, IO_INDEX_PORT); + outb_p(0x08, IO_DATA_PORT); + outb_p(0xF4, IO_INDEX_PORT); + new_status = inb_p(IO_DATA_PORT); /* lock the SuperIO chip */ - outb(0xAA,0x370); + outb_p(LOCK_DATA, IO_INDEX_PORT); + spin_unlock_irqrestore(&spinlock, flags); + + *status=0; if (new_status & 1) *status |= WDIOF_CARDRESET; @@ -249,8 +280,8 @@ static int wdt977_release(struct inode *inode, struct file *file) wdt977_stop(); clear_bit(0,&timer_alive); } else { - printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); wdt977_keepalive(); + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); } expect_close = 0; return 0; @@ -271,14 +302,17 @@ static int wdt977_release(struct inode *inode, struct file *file) static ssize_t wdt977_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - if (count) { - if (!nowayout) { + if (count) + { + if (!nowayout) + { size_t i; /* In case it was set long ago */ expect_close = 0; - for (i = 0; i != count; i++) { + for (i = 0; i != count; i++) + { char c; if (get_user(c, buf + i)) return -EFAULT; @@ -287,6 +321,7 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, } } + /* someone wrote to us, we should restart timer */ wdt977_keepalive(); } return count; @@ -308,7 +343,7 @@ static struct watchdog_info ident = { WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .firmware_version = 1, - .identity = "Winbond 83977", + .identity = WATCHDOG_NAME, }; static int wdt977_ioctl(struct inode *inode, struct file *file, @@ -405,50 +440,81 @@ static struct notifier_block wdt977_notifier = { .notifier_call = wdt977_notify_sys, }; -static int __init nwwatchdog_init(void) +static int __init wd977_init(void) { - int retval; - if (!machine_is_netwinder()) - return -ENODEV; + int rc; + + //if (!machine_is_netwinder()) + // return -ENODEV; + + printk(KERN_INFO PFX DRIVER_VERSION); + + spin_lock_init(&spinlock); /* Check that the timeout value is within it's range ; if not reset to the default */ - if (wdt977_set_timeout(timeout)) { + if (wdt977_set_timeout(timeout)) + { wdt977_set_timeout(DEFAULT_TIMEOUT); printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n", DEFAULT_TIMEOUT); } - retval = register_reboot_notifier(&wdt977_notifier); - if (retval) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - retval); - return retval; + /* on Netwinder the IOports are already reserved by + * arch/arm/mach-footbridge/netwinder-hw.c + */ + if (!machine_is_netwinder()) + { + if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + IO_INDEX_PORT); + rc = -EIO; + goto err_out; + } } - retval = misc_register(&wdt977_miscdev); - if (retval) { + rc = misc_register(&wdt977_miscdev); + if (rc) + { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, retval); - unregister_reboot_notifier(&wdt977_notifier); - return retval; + wdt977_miscdev.minor, rc); + goto err_out_region; + } + + rc = register_reboot_notifier(&wdt977_notifier); + if (rc) + { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); + goto err_out_miscdev; } - printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n", + printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", timeout, nowayout, testmode); return 0; + +err_out_miscdev: + misc_deregister(&wdt977_miscdev); +err_out_region: + if (!machine_is_netwinder()) + release_region(IO_INDEX_PORT,2); +err_out: + return rc; } -static void __exit nwwatchdog_exit(void) +static void __exit wd977_exit(void) { + wdt977_stop(); misc_deregister(&wdt977_miscdev); unregister_reboot_notifier(&wdt977_notifier); + release_region(IO_INDEX_PORT,2); } -module_init(nwwatchdog_init); -module_exit(nwwatchdog_exit); +module_init(wd977_init); +module_exit(wd977_exit); -MODULE_AUTHOR("Woody Suwalski <woody@netwinder.org>"); +MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>"); MODULE_DESCRIPTION("W83977AF Watchdog driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 969d2b4aaec..385e52930c0 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -34,14 +34,14 @@ static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; -/* proc_counts is used as the sequence number of the netlink message */ +/* proc_event_counts is used as the sequence number of the netlink message */ static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 }; static inline void get_seq(__u32 *ts, int *cpu) { *ts = get_cpu_var(proc_event_counts)++; *cpu = smp_processor_id(); - put_cpu_var(proc_counts); + put_cpu_var(proc_event_counts); } void proc_fork_connector(struct task_struct *task) diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index e70b3db69ed..1af3dfbb808 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -494,6 +494,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) { struct tps65010 *tps; int status; + unsigned long irqflags; if (the_tps) { dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); @@ -520,13 +521,14 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) } #ifdef CONFIG_ARM + irqflags = SA_SAMPLE_RANDOM | SA_TRIGGER_LOW; if (machine_is_omap_h2()) { tps->model = TPS65010; omap_cfg_reg(W4_GPIO58); tps->irq = OMAP_GPIO_IRQ(58); omap_request_gpio(58); omap_set_gpio_direction(58, 1); - set_irq_type(tps->irq, IRQT_FALLING); + irqflags |= SA_TRIGGER_FALLING; } if (machine_is_omap_osk()) { tps->model = TPS65010; @@ -534,7 +536,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); omap_request_gpio(OMAP_MPUIO(1)); omap_set_gpio_direction(OMAP_MPUIO(1), 1); - set_irq_type(tps->irq, IRQT_FALLING); + irqflags |= SA_TRIGGER_FALLING; } if (machine_is_omap_h3()) { tps->model = TPS65013; @@ -542,13 +544,12 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) // FIXME set up this board's IRQ ... } #else -#define set_irq_type(num,trigger) do{}while(0) + irqflags = SA_SAMPLE_RANDOM; #endif if (tps->irq > 0) { - set_irq_type(tps->irq, IRQT_LOW); status = request_irq(tps->irq, tps65010_irq, - SA_SAMPLE_RANDOM, DRIVER_NAME, tps); + irqflags, DRIVER_NAME, tps); if (status < 0) { dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", tps->irq, status); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index d31117eb95a..e4d55ad32d2 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1332,8 +1332,6 @@ static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block) if (cdrom_read_from_buffer(drive)) return ide_stopped; - blk_attempt_remerge(drive->queue, rq); - /* Clear the local sector buffer. */ info->nsectors_buffered = 0; @@ -1874,14 +1872,6 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) return ide_stopped; } - /* - * for dvd-ram and such media, it's a really big deal to get - * big writes all the time. so scour the queue and attempt to - * remerge requests, often the plugging will not have had time - * to do this properly - */ - blk_attempt_remerge(drive->queue, rq); - info->nsectors_buffered = 0; /* use dma, if possible. we don't need to check more, since we diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 4b441720b6b..cab362ea033 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1130,6 +1130,17 @@ static int idedisk_release(struct inode *inode, struct file *filp) return 0; } +static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); + ide_drive_t *drive = idkp->drive; + + geo->heads = drive->bios_head; + geo->sectors = drive->bios_sect; + geo->cylinders = (u16)drive->bios_cyl; /* truncate */ + return 0; +} + static int idedisk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1164,6 +1175,7 @@ static struct block_device_operations idedisk_ops = { .open = idedisk_open, .release = idedisk_release, .ioctl = idedisk_ioctl, + .getgeo = idedisk_getgeo, .media_changed = idedisk_media_changed, .revalidate_disk= idedisk_revalidate_disk }; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index fba3fffc2d6..5945f551aaa 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -2031,6 +2031,17 @@ static int idefloppy_release(struct inode *inode, struct file *filp) return 0; } +static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk); + ide_drive_t *drive = floppy->drive; + + geo->heads = drive->bios_head; + geo->sectors = drive->bios_sect; + geo->cylinders = (u16)drive->bios_cyl; /* truncate */ + return 0; +} + static int idefloppy_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -2120,6 +2131,7 @@ static struct block_device_operations idefloppy_ops = { .open = idefloppy_open, .release = idefloppy_release, .ioctl = idefloppy_ioctl, + .getgeo = idefloppy_getgeo, .media_changed = idefloppy_media_changed, .revalidate_disk= idefloppy_revalidate_disk }; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index b5dc6df8e67..dea2d4dcc69 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -55,9 +55,22 @@ #include <asm/io.h> #include <asm/bitops.h> +void ide_softirq_done(struct request *rq) +{ + request_queue_t *q = rq->q; + + add_disk_randomness(rq->rq_disk); + end_that_request_chunk(rq, rq->errors, rq->data_len); + + spin_lock_irq(q->queue_lock); + end_that_request_last(rq, rq->errors); + spin_unlock_irq(q->queue_lock); +} + int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, int nr_sectors) { + unsigned int nbytes; int ret = 1; BUG_ON(!(rq->flags & REQ_STARTED)); @@ -81,17 +94,28 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, HWGROUP(drive)->hwif->ide_dma_on(drive); } - if (!end_that_request_first(rq, uptodate, nr_sectors)) { - add_disk_randomness(rq->rq_disk); - - if (blk_rq_tagged(rq)) - blk_queue_end_tag(drive->queue, rq); - + /* + * For partial completions (or non fs/pc requests), use the regular + * direct completion path. + */ + nbytes = nr_sectors << 9; + if (rq_all_done(rq, nbytes)) { + rq->errors = uptodate; + rq->data_len = nbytes; blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - end_that_request_last(rq, uptodate); + blk_complete_request(rq); ret = 0; + } else { + if (!end_that_request_first(rq, uptodate, nr_sectors)) { + add_disk_randomness(rq->rq_disk); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq, uptodate); + ret = 0; + } } + return ret; } EXPORT_SYMBOL(__ide_end_request); @@ -113,6 +137,10 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) unsigned long flags; int ret = 1; + /* + * room for locking improvements here, the calls below don't + * need the queue lock held at all + */ spin_lock_irqsave(&ide_lock, flags); rq = HWGROUP(drive)->rq; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 02167a5b751..1ddaa71a8f4 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1011,6 +1011,8 @@ static int ide_init_queue(ide_drive_t *drive) blk_queue_max_hw_segments(q, max_sg_entries); blk_queue_max_phys_segments(q, max_sg_entries); + blk_queue_softirq_done(q, ide_softirq_done); + /* assign drive queue */ drive->queue = q; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 4b524f6b3ec..b069b13b75a 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1278,19 +1278,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device up(&ide_setting_sem); switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry geom; - if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; - geom.heads = drive->bios_head; - geom.sectors = drive->bios_sect; - geom.cylinders = (u16)drive->bios_cyl; /* truncate */ - geom.start = get_start_sect(bdev); - if (copy_to_user(p, &geom, sizeof(struct hd_geometry))) - return -EFAULT; - return 0; - } - case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (bdev != bdev->bd_contains) diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index 242029c9c0c..6439dec6688 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -658,22 +658,14 @@ static void do_hd_request (request_queue_t * q) enable_irq(HD_IRQ); } -static int hd_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data; - struct hd_geometry __user *loc = (struct hd_geometry __user *) arg; - struct hd_geometry g; - - if (cmd != HDIO_GETGEO) - return -EINVAL; - if (!loc) - return -EINVAL; - g.heads = disk->head; - g.sectors = disk->sect; - g.cylinders = disk->cyl; - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; + struct hd_i_struct *disk = bdev->bd_disk->private_data; + + geo->heads = disk->head; + geo->sectors = disk->sect; + geo->cylinders = disk->cyl; + return 0; } /* @@ -695,7 +687,7 @@ static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) } static struct block_device_operations hd_fops = { - .ioctl = hd_ioctl, + .getgeo = hd_getgeo, }; /* diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index ff2e217a8c8..0d3073f4eab 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -69,7 +69,7 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list) static u8 svwks_ratemask (ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 mode; + u8 mode = 0; if (!svwks_revision) pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 02110e00d14..3a611fe5497 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -308,10 +308,11 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv) { unsigned long flags; int ret; + static int next_id; do { spin_lock_irqsave(&cm.lock, flags); - ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, 1, + ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++, (__force int *) &cm_id_priv->id.local_id); spin_unlock_irqrestore(&cm.lock, flags); } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); @@ -684,6 +685,13 @@ retest: cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); break; case IB_CM_REQ_SENT: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, + &cm_id_priv->av.port->cm_dev->ca_guid, + sizeof cm_id_priv->av.port->cm_dev->ca_guid, + NULL, 0); + break; case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: @@ -694,10 +702,8 @@ retest: case IB_CM_REP_RCVD: case IB_CM_MRA_REP_SENT: spin_unlock_irqrestore(&cm_id_priv->lock, flags); - ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, - &cm_id_priv->av.port->cm_dev->ca_guid, - sizeof cm_id_priv->av.port->cm_dev->ca_guid, - NULL, 0); + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); break; case IB_CM_ESTABLISHED: spin_unlock_irqrestore(&cm_id_priv->lock, flags); diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index eb7f52537cc..c908de8db5a 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -197,8 +197,8 @@ static void send_handler(struct ib_mad_agent *agent, memcpy(timeout->mad.data, packet->mad.data, sizeof (struct ib_mad_hdr)); - if (!queue_packet(file, agent, timeout)) - return; + if (queue_packet(file, agent, timeout)) + kfree(timeout); } out: kfree(packet); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a57d021d435..a02c5a05c98 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -489,6 +489,7 @@ err_idr: err_unreg: ib_dereg_mr(mr); + atomic_dec(&pd->usecnt); err_up: up(&ib_uverbs_idr_mutex); @@ -593,13 +594,18 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, if (cmd.comp_vector >= file->device->num_comp_vectors) return -EINVAL; - if (cmd.comp_channel >= 0) - ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); - uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; + if (cmd.comp_channel >= 0) { + ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); + if (!ev_file) { + ret = -EINVAL; + goto err; + } + } + uobj->uobject.user_handle = cmd.user_handle; uobj->uobject.context = file->ucontext; uobj->uverbs_file = file; @@ -663,6 +669,8 @@ err_up: ib_destroy_cq(cq); err: + if (ev_file) + ib_uverbs_release_ucq(file, ev_file, uobj); kfree(uobj); return ret; } @@ -935,6 +943,11 @@ err_idr: err_destroy: ib_destroy_qp(qp); + atomic_dec(&pd->usecnt); + atomic_dec(&attr.send_cq->usecnt); + atomic_dec(&attr.recv_cq->usecnt); + if (attr.srq) + atomic_dec(&attr.srq->usecnt); err_up: up(&ib_uverbs_idr_mutex); @@ -1448,6 +1461,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, attr.sl = cmd.attr.sl; attr.src_path_bits = cmd.attr.src_path_bits; attr.static_rate = cmd.attr.static_rate; + attr.ah_flags = cmd.attr.is_global ? IB_AH_GRH : 0; attr.port_num = cmd.attr.port_num; attr.grh.flow_label = cmd.attr.grh.flow_label; attr.grh.sgid_index = cmd.attr.grh.sgid_index; @@ -1729,6 +1743,7 @@ err_idr: err_destroy: ib_destroy_srq(srq); + atomic_dec(&pd->usecnt); err_up: up(&ib_uverbs_idr_mutex); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 4c15e112736..c857361be44 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -107,9 +107,9 @@ struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, if (wc->wc_flags & IB_WC_GRH) { ah_attr.ah_flags = IB_AH_GRH; - ah_attr.grh.dgid = grh->dgid; + ah_attr.grh.dgid = grh->sgid; - ret = ib_find_cached_gid(pd->device, &grh->sgid, &port_num, + ret = ib_find_cached_gid(pd->device, &grh->dgid, &port_num, &gid_index); if (ret) return ERR_PTR(ret); diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 9ed34587fc5..22ac72bc20c 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -937,10 +937,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, if (err) goto out; - MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); - dev_lim->max_srq_sz = (1 << field) - 1; - MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); - dev_lim->max_qp_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET); dev_lim->reserved_qps = 1 << (field & 0xf); MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET); @@ -1056,6 +1052,10 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags); if (mthca_is_memfree(dev)) { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = 1 << field; MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET); dev_lim->hca.arbel.resize_srq = field & 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET); @@ -1087,6 +1087,10 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, mthca_dbg(dev, "Max ICM size %lld MB\n", (unsigned long long) dev_lim->hca.arbel.max_icm_sz >> 20); } else { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = (1 << field) - 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = (1 << field) - 1; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET); dev_lim->hca.tavor.max_avs = 1 << (field & 0x3f); dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE; diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 4a8adcef207..96f1a86bf04 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -128,12 +128,12 @@ struct mthca_err_cqe { __be32 my_qpn; u32 reserved1[3]; u8 syndrome; - u8 reserved2; + u8 vendor_err; __be16 db_cnt; - u32 reserved3; + u32 reserved2; __be32 wqe; u8 opcode; - u8 reserved4[2]; + u8 reserved3[2]; u8 owner; }; @@ -253,6 +253,15 @@ void mthca_cq_event(struct mthca_dev *dev, u32 cqn, wake_up(&cq->wait); } +static inline int is_recv_cqe(struct mthca_cqe *cqe) +{ + if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK) + return !(cqe->opcode & 0x01); + else + return !(cqe->is_send & 0x80); +} + void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, struct mthca_srq *srq) { @@ -296,7 +305,7 @@ void mthca_cq_clean(struct mthca_dev *dev, u32 cqn, u32 qpn, while ((int) --prod_index - (int) cq->cons_index >= 0) { cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); if (cqe->my_qpn == cpu_to_be32(qpn)) { - if (srq) + if (srq && is_recv_cqe(cqe)) mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe)); ++nfreed; } else if (nfreed) @@ -333,8 +342,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, } /* - * For completions in error, only work request ID, status (and - * freed resource count for RD) have to be set. + * For completions in error, only work request ID, status, vendor error + * (and freed resource count for RD) have to be set. */ switch (cqe->syndrome) { case SYNDROME_LOCAL_LENGTH_ERR: @@ -396,6 +405,8 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, break; } + entry->vendor_err = cqe->vendor_err; + /* * Mem-free HCAs always generate one CQE per WQE, even in the * error case, so we don't have to check the doorbell count, etc. diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 497ff794ef6..795b379260b 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -43,6 +43,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/dma-mapping.h> +#include <linux/timer.h> #include <asm/semaphore.h> #include "mthca_provider.h" diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 34d68e5a72d..e8a948f087c 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -484,8 +484,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, u8 intr, struct mthca_eq *eq) { - int npages = (nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) / - PAGE_SIZE; + int npages; u64 *dma_list = NULL; dma_addr_t t; struct mthca_mailbox *mailbox; @@ -496,6 +495,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, eq->dev = dev; eq->nent = roundup_pow_of_two(max(nent, 2)); + npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE; eq->page_list = kmalloc(npages * sizeof *eq->page_list, GFP_KERNEL); diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 6f94b25f3ac..8b00d9a0f6f 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -261,6 +261,10 @@ static int __devinit mthca_init_tavor(struct mthca_dev *mdev) } err = mthca_dev_lim(mdev, &dev_lim); + if (err) { + mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); + goto err_disable; + } profile = default_profile; profile.num_uar = dev_lim.uar_size / PAGE_SIZE; diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index 2fc449da418..77bc6c746f4 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -111,7 +111,8 @@ static int find_mgm(struct mthca_dev *dev, goto out; if (status) { mthca_err(dev, "READ_MGM returned status %02x\n", status); - return -EINVAL; + err = -EINVAL; + goto out; } if (!memcmp(mgm->gid, zero_gid, 16)) { @@ -126,7 +127,7 @@ static int find_mgm(struct mthca_dev *dev, goto out; *prev = *index; - *index = be32_to_cpu(mgm->next_gid_index) >> 5; + *index = be32_to_cpu(mgm->next_gid_index) >> 6; } while (*index); *index = -1; @@ -153,8 +154,10 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return PTR_ERR(mailbox); mgm = mailbox->buf; - if (down_interruptible(&dev->mcg_table.sem)) - return -EINTR; + if (down_interruptible(&dev->mcg_table.sem)) { + err = -EINTR; + goto err_sem; + } err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); if (err) @@ -181,9 +184,8 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = -EINVAL; goto out; } - + memset(mgm, 0, sizeof *mgm); memcpy(mgm->gid, gid->raw, 16); - mgm->next_gid_index = 0; } for (i = 0; i < MTHCA_QP_PER_MGM; ++i) @@ -209,6 +211,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (status) { mthca_err(dev, "WRITE_MGM returned status %02x\n", status); err = -EINVAL; + goto out; } if (!link) @@ -223,7 +226,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) goto out; } - mgm->next_gid_index = cpu_to_be32(index << 5); + mgm->next_gid_index = cpu_to_be32(index << 6); err = mthca_WRITE_MGM(dev, prev, mailbox, &status); if (err) @@ -234,7 +237,12 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } out: + if (err && link && index != -1) { + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); + } up(&dev->mcg_table.sem); + err_sem: mthca_free_mailbox(dev, mailbox); return err; } @@ -255,8 +263,10 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return PTR_ERR(mailbox); mgm = mailbox->buf; - if (down_interruptible(&dev->mcg_table.sem)) - return -EINTR; + if (down_interruptible(&dev->mcg_table.sem)) { + err = -EINTR; + goto err_sem; + } err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); if (err) @@ -305,13 +315,11 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) if (i != 1) goto out; - goto out; - if (prev == -1) { /* Remove entry from MGM */ - if (be32_to_cpu(mgm->next_gid_index) >> 5) { - err = mthca_READ_MGM(dev, - be32_to_cpu(mgm->next_gid_index) >> 5, + int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6; + if (amgm_index_to_free) { + err = mthca_READ_MGM(dev, amgm_index_to_free, mailbox, &status); if (err) goto out; @@ -332,9 +340,13 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = -EINVAL; goto out; } + if (amgm_index_to_free) { + BUG_ON(amgm_index_to_free < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); + } } else { /* Remove entry from AMGM */ - index = be32_to_cpu(mgm->next_gid_index) >> 5; + int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; err = mthca_READ_MGM(dev, prev, mailbox, &status); if (err) goto out; @@ -344,7 +356,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) goto out; } - mgm->next_gid_index = cpu_to_be32(index << 5); + mgm->next_gid_index = cpu_to_be32(curr_next_index << 6); err = mthca_WRITE_MGM(dev, prev, mailbox, &status); if (err) @@ -354,10 +366,13 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = -EINVAL; goto out; } + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); } out: up(&dev->mcg_table.sem); + err_sem: mthca_free_mailbox(dev, mailbox); return err; } @@ -365,11 +380,12 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) int __devinit mthca_init_mcg_table(struct mthca_dev *dev) { int err; + int table_size = dev->limits.num_mgms + dev->limits.num_amgms; err = mthca_alloc_init(&dev->mcg_table.alloc, - dev->limits.num_amgms, - dev->limits.num_amgms - 1, - 0); + table_size, + table_size - 1, + dev->limits.num_mgms); if (err) return err; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index d72fe95cba0..9fb985a016e 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -233,7 +233,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj) for (i = 0; i < chunk->npages; ++i) { if (chunk->mem[i].length >= offset) { page = chunk->mem[i].page; - break; + goto out; } offset -= chunk->mem[i].length; } @@ -485,6 +485,8 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, put_page(db_tab->page[i].mem.page); } } + + kfree(db_tab); } int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 7450550db73..564b6d51c39 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -383,12 +383,10 @@ static const struct { [UC] = (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | - IB_QP_PKEY_INDEX | IB_QP_PATH_MIG_STATE), [RC] = (IB_QP_CUR_STATE | IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS | - IB_QP_PKEY_INDEX | IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE), [MLX] = (IB_QP_CUR_STATE | @@ -476,9 +474,8 @@ static const struct { .opt_param = { [UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), - [UC] = IB_QP_CUR_STATE, - [RC] = (IB_QP_CUR_STATE | - IB_QP_MIN_RNR_TIMER), + [UC] = (IB_QP_CUR_STATE | + IB_QP_ACCESS_FLAGS), [MLX] = (IB_QP_CUR_STATE | IB_QP_QKEY), } @@ -522,6 +519,55 @@ static void init_port(struct mthca_dev *dev, int port) mthca_warn(dev, "INIT_IB returned status %02x.\n", status); } +static __be32 get_hw_access_flags(struct mthca_qp *qp, struct ib_qp_attr *attr, + int attr_mask) +{ + u8 dest_rd_atomic; + u32 access_flags; + u32 hw_access_flags = 0; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + dest_rd_atomic = attr->max_dest_rd_atomic; + else + dest_rd_atomic = qp->resp_depth; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + access_flags = attr->qp_access_flags; + else + access_flags = qp->atomic_rd_en; + + if (!dest_rd_atomic) + access_flags &= IB_ACCESS_REMOTE_WRITE; + + if (access_flags & IB_ACCESS_REMOTE_READ) + hw_access_flags |= MTHCA_QP_BIT_RRE; + if (access_flags & IB_ACCESS_REMOTE_ATOMIC) + hw_access_flags |= MTHCA_QP_BIT_RAE; + if (access_flags & IB_ACCESS_REMOTE_WRITE) + hw_access_flags |= MTHCA_QP_BIT_RWE; + + return cpu_to_be32(hw_access_flags); +} + +static void mthca_path_set(struct ib_ah_attr *ah, struct mthca_qp_path *path) +{ + path->g_mylmc = ah->src_path_bits & 0x7f; + path->rlid = cpu_to_be16(ah->dlid); + path->static_rate = !!ah->static_rate; + + if (ah->ah_flags & IB_AH_GRH) { + path->g_mylmc |= 1 << 7; + path->mgid_index = ah->grh.sgid_index; + path->hop_limit = ah->grh.hop_limit; + path->sl_tclass_flowlabel = + cpu_to_be32((ah->sl << 28) | + (ah->grh.traffic_class << 20) | + (ah->grh.flow_label)); + memcpy(path->rgid, ah->grh.dgid.raw, 16); + } else + path->sl_tclass_flowlabel = cpu_to_be32(ah->sl << 28); +} + int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) { struct mthca_dev *dev = to_mdev(ibqp->device); @@ -591,6 +637,26 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) return -EINVAL; } + if ((attr_mask & IB_QP_PORT) && + (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) { + mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num); + return -EINVAL; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { + mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n", + attr->max_rd_atomic, dev->limits.max_qp_init_rdma); + return -EINVAL; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) { + mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n", + attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift); + return -EINVAL; + } + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); if (IS_ERR(mailbox)) return PTR_ERR(mailbox); @@ -665,28 +731,14 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_RNR_RETRY) { - qp_context->pri_path.rnr_retry = attr->rnr_retry << 5; - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY); + qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry = + attr->rnr_retry << 5; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | + MTHCA_QP_OPTPAR_ALT_RNR_RETRY); } if (attr_mask & IB_QP_AV) { - qp_context->pri_path.g_mylmc = attr->ah_attr.src_path_bits & 0x7f; - qp_context->pri_path.rlid = cpu_to_be16(attr->ah_attr.dlid); - qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate; - if (attr->ah_attr.ah_flags & IB_AH_GRH) { - qp_context->pri_path.g_mylmc |= 1 << 7; - qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index; - qp_context->pri_path.hop_limit = attr->ah_attr.grh.hop_limit; - qp_context->pri_path.sl_tclass_flowlabel = - cpu_to_be32((attr->ah_attr.sl << 28) | - (attr->ah_attr.grh.traffic_class << 20) | - (attr->ah_attr.grh.flow_label)); - memcpy(qp_context->pri_path.rgid, - attr->ah_attr.grh.dgid.raw, 16); - } else { - qp_context->pri_path.sl_tclass_flowlabel = - cpu_to_be32(attr->ah_attr.sl << 28); - } + mthca_path_set(&attr->ah_attr, &qp_context->pri_path); qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); } @@ -695,7 +747,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT); } - /* XXX alt_path */ + if (attr_mask & IB_QP_ALT_PATH) { + if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) { + mthca_dbg(dev, "Alternate port number (%u) is invalid\n", + attr->alt_port_num); + return -EINVAL; + } + + mthca_path_set(&attr->alt_ah_attr, &qp_context->alt_path); + qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | + attr->alt_port_num << 24); + qp_context->alt_path.ackto = attr->alt_timeout << 3; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH); + } /* leave rdd as 0 */ qp_context->pd = cpu_to_be32(to_mpd(ibqp->pd)->pd_num); @@ -703,9 +767,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_context->wqe_lkey = cpu_to_be32(qp->mr.ibmr.lkey); qp_context->params1 = cpu_to_be32((MTHCA_ACK_REQ_FREQ << 28) | (MTHCA_FLIGHT_LIMIT << 24) | - MTHCA_QP_BIT_SRE | - MTHCA_QP_BIT_SWE | - MTHCA_QP_BIT_SAE); + MTHCA_QP_BIT_SWE); if (qp->sq_policy == IB_SIGNAL_ALL_WR) qp_context->params1 |= cpu_to_be32(MTHCA_QP_BIT_SSC); if (attr_mask & IB_QP_RETRY_CNT) { @@ -714,9 +776,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { - qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ? - ffs(attr->max_rd_atomic) - 1 : 0, - 7) << 21); + if (attr->max_rd_atomic) { + qp_context->params1 |= + cpu_to_be32(MTHCA_QP_BIT_SRE | + MTHCA_QP_BIT_SAE); + qp_context->params1 |= + cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); + } qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX); } @@ -729,71 +795,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp_context->snd_db_index = cpu_to_be32(qp->sq.db_index); } - if (attr_mask & IB_QP_ACCESS_FLAGS) { - qp_context->params2 |= - cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE ? - MTHCA_QP_BIT_RWE : 0); - - /* - * Only enable RDMA reads and atomics if we have - * responder resources set to a non-zero value. - */ - if (qp->resp_depth) { - qp_context->params2 |= - cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_READ ? - MTHCA_QP_BIT_RRE : 0); - qp_context->params2 |= - cpu_to_be32(attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC ? - MTHCA_QP_BIT_RAE : 0); - } - - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE | - MTHCA_QP_OPTPAR_RRE | - MTHCA_QP_OPTPAR_RAE); - - qp->atomic_rd_en = attr->qp_access_flags; - } - if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { - u8 rra_max; - - if (qp->resp_depth && !attr->max_dest_rd_atomic) { - /* - * Lowering our responder resources to zero. - * Turn off reads RDMA and atomics as responder. - * (RRE/RAE in params2 already zero) - */ - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRE | - MTHCA_QP_OPTPAR_RAE); - } - - if (!qp->resp_depth && attr->max_dest_rd_atomic) { - /* - * Increasing our responder resources from - * zero. Turn on RDMA reads and atomics as - * appropriate. - */ + if (attr->max_dest_rd_atomic) qp_context->params2 |= - cpu_to_be32(qp->atomic_rd_en & IB_ACCESS_REMOTE_READ ? - MTHCA_QP_BIT_RRE : 0); - qp_context->params2 |= - cpu_to_be32(qp->atomic_rd_en & IB_ACCESS_REMOTE_ATOMIC ? - MTHCA_QP_BIT_RAE : 0); - - qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRE | - MTHCA_QP_OPTPAR_RAE); - } + cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); - for (rra_max = 0; - 1 << rra_max < attr->max_dest_rd_atomic && - rra_max < dev->qp_table.rdb_shift; - ++rra_max) - ; /* nothing */ - - qp_context->params2 |= cpu_to_be32(rra_max << 21); qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX); + } - qp->resp_depth = attr->max_dest_rd_atomic; + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + qp_context->params2 |= get_hw_access_flags(qp, attr, attr_mask); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE | + MTHCA_QP_OPTPAR_RRE | + MTHCA_QP_OPTPAR_RAE); } qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC); @@ -835,8 +849,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) err = -EINVAL; } - if (!err) + if (!err) { qp->state = new_state; + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->atomic_rd_en = attr->qp_access_flags; + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->resp_depth = attr->max_dest_rd_atomic; + } mthca_free_mailbox(dev, mailbox); @@ -885,18 +904,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) return err; } -static void mthca_adjust_qp_caps(struct mthca_dev *dev, - struct mthca_pd *pd, - struct mthca_qp *qp) +static int mthca_max_data_size(struct mthca_dev *dev, struct mthca_qp *qp, int desc_sz) { - int max_data_size; - /* * Calculate the maximum size of WQE s/g segments, excluding * the next segment and other non-data segments. */ - max_data_size = min(dev->limits.max_desc_sz, 1 << qp->sq.wqe_shift) - - sizeof (struct mthca_next_seg); + int max_data_size = desc_sz - sizeof (struct mthca_next_seg); switch (qp->transport) { case MLX: @@ -915,11 +929,24 @@ static void mthca_adjust_qp_caps(struct mthca_dev *dev, break; } + return max_data_size; +} + +static inline int mthca_max_inline_data(struct mthca_pd *pd, int max_data_size) +{ /* We don't support inline data for kernel QPs (yet). */ - if (!pd->ibpd.uobject) - qp->max_inline_data = 0; - else - qp->max_inline_data = max_data_size - MTHCA_INLINE_HEADER_SIZE; + return pd->ibpd.uobject ? max_data_size - MTHCA_INLINE_HEADER_SIZE : 0; +} + +static void mthca_adjust_qp_caps(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_qp *qp) +{ + int max_data_size = mthca_max_data_size(dev, qp, + min(dev->limits.max_desc_sz, + 1 << qp->sq.wqe_shift)); + + qp->max_inline_data = mthca_max_inline_data(pd, max_data_size); qp->sq.max_gs = min_t(int, dev->limits.max_sg, max_data_size / sizeof (struct mthca_data_seg)); @@ -1186,13 +1213,23 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, } static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, - struct mthca_qp *qp) + struct mthca_pd *pd, struct mthca_qp *qp) { + int max_data_size = mthca_max_data_size(dev, qp, dev->limits.max_desc_sz); + /* Sanity check QP size before proceeding */ - if (cap->max_send_wr > dev->limits.max_wqes || - cap->max_recv_wr > dev->limits.max_wqes || - cap->max_send_sge > dev->limits.max_sg || - cap->max_recv_sge > dev->limits.max_sg) + if (cap->max_send_wr > dev->limits.max_wqes || + cap->max_recv_wr > dev->limits.max_wqes || + cap->max_send_sge > dev->limits.max_sg || + cap->max_recv_sge > dev->limits.max_sg || + cap->max_inline_data > mthca_max_inline_data(pd, max_data_size)) + return -EINVAL; + + /* + * For MLX transport we need 2 extra S/G entries: + * one for the header and one for the checksum at the end + */ + if (qp->transport == MLX && cap->max_recv_sge + 2 > dev->limits.max_sg) return -EINVAL; if (mthca_is_memfree(dev)) { @@ -1211,14 +1248,6 @@ static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, MTHCA_INLINE_CHUNK_SIZE) / sizeof (struct mthca_data_seg)); - /* - * For MLX transport we need 2 extra S/G entries: - * one for the header and one for the checksum at the end - */ - if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) || - qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg) - return -EINVAL; - return 0; } @@ -1233,7 +1262,7 @@ int mthca_alloc_qp(struct mthca_dev *dev, { int err; - err = mthca_set_qp_size(dev, cap, qp); + err = mthca_set_qp_size(dev, cap, pd, qp); if (err) return err; @@ -1276,7 +1305,7 @@ int mthca_alloc_sqp(struct mthca_dev *dev, u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1; int err; - err = mthca_set_qp_size(dev, cap, &sqp->qp); + err = mthca_set_qp_size(dev, cap, pd, &sqp->qp); if (err) return err; diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index f7d234295ef..e7e153d9c4c 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -201,7 +201,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, if (mthca_is_memfree(dev)) srq->max = roundup_pow_of_two(srq->max + 1); - ds = min(64UL, + ds = max(64UL, roundup_pow_of_two(sizeof (struct mthca_next_seg) + srq->max_gs * sizeof (struct mthca_data_seg))); srq->wqe_shift = long_log2(ds); diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ee9fe226ae9..dd488d3cffa 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -39,6 +39,7 @@ #include <linux/string.h> #include <linux/parser.h> #include <linux/random.h> +#include <linux/jiffies.h> #include <asm/atomic.h> diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 64672d49122..e301ee4ca26 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -19,7 +19,6 @@ #include <linux/jiffies.h> #include <linux/module.h> #include <linux/slab.h> -#include <asm/irq.h> #include <asm/arch/corgi.h> #include <asm/arch/hardware.h> @@ -343,10 +342,9 @@ static int __init corgikbd_probe(struct platform_device *pdev) for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) { pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN); if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt, - SA_INTERRUPT, "corgikbd", corgikbd)) + SA_INTERRUPT | SA_TRIGGER_RISING, + "corgikbd", corgikbd)) printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i); - else - set_irq_type(CORGI_IRQ_GPIO_KEY_SENSE(i),IRQT_RISING); } /* Set Strobe lines as outputs - set high */ diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 6a15fe3bc52..83999d58312 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -19,7 +19,6 @@ #include <linux/jiffies.h> #include <linux/module.h> #include <linux/slab.h> -#include <asm/irq.h> #include <asm/arch/spitz.h> #include <asm/arch/hardware.h> @@ -407,10 +406,9 @@ static int __init spitzkbd_probe(struct platform_device *dev) for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) { pxa_gpio_mode(spitz_senses[i] | GPIO_IN); if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt, - SA_INTERRUPT, "Spitzkbd Sense", spitzkbd)) + SA_INTERRUPT|SA_TRIGGER_RISING, + "Spitzkbd Sense", spitzkbd)) printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i); - else - set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING); } /* Set Strobe lines as outputs - set high */ @@ -422,15 +420,18 @@ static int __init spitzkbd_probe(struct platform_device *dev) pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN); pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN); - request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd); - request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd); - request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd); - request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd); - - set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE); - set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE); - set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE); - set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE); + request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd Sync", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd PwrOn", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd SWA", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd SWB", spitzkbd); printk(KERN_INFO "input: Spitz Keyboard Registered\n"); diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 1cd7657f7e4..1be963961c1 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -60,8 +60,6 @@ static struct fasync_struct *hp_sdc_rtc_async_queue; static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); -static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin); - static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos); @@ -387,11 +385,6 @@ static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) return 0; } -static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { ssize_t retval; @@ -679,7 +672,7 @@ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, static struct file_operations hp_sdc_rtc_fops = { .owner = THIS_MODULE, - .llseek = hp_sdc_rtc_llseek, + .llseek = no_llseek, .read = hp_sdc_rtc_read, .poll = hp_sdc_rtc_poll, .ioctl = hp_sdc_rtc_ioctl, diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h index b091d1a5412..d4c50512a1f 100644 --- a/drivers/isdn/act2000/act2000.h +++ b/drivers/isdn/act2000/act2000.h @@ -181,17 +181,17 @@ typedef struct act2000_card { char regname[35]; /* Name used for request_region */ } act2000_card; -extern __inline__ void act2000_schedule_tx(act2000_card *card) +static inline void act2000_schedule_tx(act2000_card *card) { schedule_work(&card->snd_tq); } -extern __inline__ void act2000_schedule_rx(act2000_card *card) +static inline void act2000_schedule_rx(act2000_card *card) { schedule_work(&card->rcv_tq); } -extern __inline__ void act2000_schedule_poll(act2000_card *card) +static inline void act2000_schedule_poll(act2000_card *card) { schedule_work(&card->poll_tq); } diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index f6d5f530b86..49f453c53c6 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -78,29 +78,29 @@ typedef union actcapi_infoel { /* info element */ typedef struct actcapi_msn { __u8 eaz; __u8 len; /* Length of MSN */ - __u8 msn[15] __attribute__ ((packed)); -} actcapi_msn; + __u8 msn[15]; +} __attribute__((packed)) actcapi_msn; typedef struct actcapi_dlpd { __u8 len; /* Length of structure */ - __u16 dlen __attribute__ ((packed)); /* Data Length */ - __u8 laa __attribute__ ((packed)); /* Link Address A */ + __u16 dlen; /* Data Length */ + __u8 laa; /* Link Address A */ __u8 lab; /* Link Address B */ __u8 modulo; /* Modulo Mode */ __u8 win; /* Window size */ __u8 xid[100]; /* XID Information */ -} actcapi_dlpd; +} __attribute__((packed)) actcapi_dlpd; typedef struct actcapi_ncpd { __u8 len; /* Length of structure */ - __u16 lic __attribute__ ((packed)); - __u16 hic __attribute__ ((packed)); - __u16 ltc __attribute__ ((packed)); - __u16 htc __attribute__ ((packed)); - __u16 loc __attribute__ ((packed)); - __u16 hoc __attribute__ ((packed)); - __u8 modulo __attribute__ ((packed)); -} actcapi_ncpd; + __u16 lic; + __u16 hic; + __u16 ltc; + __u16 htc; + __u16 loc; + __u16 hoc; + __u8 modulo; +} __attribute__((packed)) actcapi_ncpd; #define actcapi_ncpi actcapi_ncpd /* @@ -168,19 +168,19 @@ typedef struct actcapi_msg { __u16 manuf_msg; __u16 controller; actcapi_msn msnmap; - } manufacturer_req_msn; + } __attribute ((packed)) manufacturer_req_msn; /* TODO: TraceInit-req/conf/ind/resp and * TraceDump-req/conf/ind/resp */ struct connect_req { __u8 controller; __u8 bchan; - __u32 infomask __attribute__ ((packed)); + __u32 infomask; __u8 si1; __u8 si2; __u8 eaz; actcapi_addr addr; - } connect_req; + } __attribute__ ((packed)) connect_req; struct connect_conf { __u16 plci; __u16 info; @@ -192,7 +192,7 @@ typedef struct actcapi_msg { __u8 si2; __u8 eaz; actcapi_addr addr; - } connect_ind; + } __attribute__ ((packed)) connect_ind; struct connect_resp { __u16 plci; __u8 rejectcause; @@ -200,14 +200,14 @@ typedef struct actcapi_msg { struct connect_active_ind { __u16 plci; actcapi_addr addr; - } connect_active_ind; + } __attribute__ ((packed)) connect_active_ind; struct connect_active_resp { __u16 plci; } connect_active_resp; struct connect_b3_req { __u16 plci; actcapi_ncpi ncpi; - } connect_b3_req; + } __attribute__ ((packed)) connect_b3_req; struct connect_b3_conf { __u16 plci; __u16 ncci; @@ -217,12 +217,12 @@ typedef struct actcapi_msg { __u16 ncci; __u16 plci; actcapi_ncpi ncpi; - } connect_b3_ind; + } __attribute__ ((packed)) connect_b3_ind; struct connect_b3_resp { __u16 ncci; __u8 rejectcause; - actcapi_ncpi ncpi __attribute__ ((packed)); - } connect_b3_resp; + actcapi_ncpi ncpi; + } __attribute__ ((packed)) connect_b3_resp; struct disconnect_req { __u16 plci; __u8 cause; @@ -241,14 +241,14 @@ typedef struct actcapi_msg { struct connect_b3_active_ind { __u16 ncci; actcapi_ncpi ncpi; - } connect_b3_active_ind; + } __attribute__ ((packed)) connect_b3_active_ind; struct connect_b3_active_resp { __u16 ncci; } connect_b3_active_resp; struct disconnect_b3_req { __u16 ncci; actcapi_ncpi ncpi; - } disconnect_b3_req; + } __attribute__ ((packed)) disconnect_b3_req; struct disconnect_b3_conf { __u16 ncci; __u16 info; @@ -257,7 +257,7 @@ typedef struct actcapi_msg { __u16 ncci; __u16 info; actcapi_ncpi ncpi; - } disconnect_b3_ind; + } __attribute__ ((packed)) disconnect_b3_ind; struct disconnect_b3_resp { __u16 ncci; } disconnect_b3_resp; @@ -265,7 +265,7 @@ typedef struct actcapi_msg { __u16 plci; actcapi_infonr nr; actcapi_infoel el; - } info_ind; + } __attribute__ ((packed)) info_ind; struct info_resp { __u16 plci; } info_resp; @@ -279,8 +279,8 @@ typedef struct actcapi_msg { struct select_b2_protocol_req { __u16 plci; __u8 protocol; - actcapi_dlpd dlpd __attribute__ ((packed)); - } select_b2_protocol_req; + actcapi_dlpd dlpd; + } __attribute__ ((packed)) select_b2_protocol_req; struct select_b2_protocol_conf { __u16 plci; __u16 info; @@ -288,49 +288,49 @@ typedef struct actcapi_msg { struct select_b3_protocol_req { __u16 plci; __u8 protocol; - actcapi_ncpd ncpd __attribute__ ((packed)); - } select_b3_protocol_req; + actcapi_ncpd ncpd; + } __attribute__ ((packed)) select_b3_protocol_req; struct select_b3_protocol_conf { __u16 plci; __u16 info; } select_b3_protocol_conf; struct listen_req { __u8 controller; - __u32 infomask __attribute__ ((packed)); - __u16 eazmask __attribute__ ((packed)); - __u16 simask __attribute__ ((packed)); - } listen_req; + __u32 infomask; + __u16 eazmask; + __u16 simask; + } __attribute__ ((packed)) listen_req; struct listen_conf { __u8 controller; - __u16 info __attribute__ ((packed)); - } listen_conf; + __u16 info; + } __attribute__ ((packed)) listen_conf; struct data_b3_req { __u16 fakencci; __u16 datalen; __u32 unused; __u8 blocknr; - __u16 flags __attribute__ ((packed)); - } data_b3_req; + __u16 flags; + } __attribute ((packed)) data_b3_req; struct data_b3_ind { __u16 fakencci; __u16 datalen; __u32 unused; __u8 blocknr; - __u16 flags __attribute__ ((packed)); - } data_b3_ind; + __u16 flags; + } __attribute__ ((packed)) data_b3_ind; struct data_b3_resp { __u16 ncci; __u8 blocknr; - } data_b3_resp; + } __attribute__ ((packed)) data_b3_resp; struct data_b3_conf { __u16 ncci; __u8 blocknr; - __u16 info __attribute__ ((packed)); - } data_b3_conf; + __u16 info; + } __attribute__ ((packed)) data_b3_conf; } msg; -} actcapi_msg; +} __attribute__ ((packed)) actcapi_msg; -extern __inline__ unsigned short +static inline unsigned short actcapi_nextsmsg(act2000_card *card) { unsigned long flags; diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 7b564c0dd99..207cae36625 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -17,6 +17,8 @@ #include <linux/ctype.h> #include <linux/sched.h> /* current */ +#include "capifs.h" + MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index cccfabc1117..11e6f937c1e 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -16,6 +16,7 @@ #include "diva_pci.h" #include "mi_pc.h" #include "dsrv4bri.h" +#include "helpers.h" static void *diva_xdiLoadFileFile = NULL; static dword diva_xdiLoadFileLength = 0; @@ -815,7 +816,7 @@ diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a, return (ret); } -void *xdiLoadFile(char *FileName, unsigned long *FileLength, +void *xdiLoadFile(char *FileName, dword *FileLength, unsigned long lim) { void *ret = diva_xdiLoadFileFile; diff --git a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c index 4cc44a5dd1d..f31bba5b16f 100644 --- a/drivers/isdn/hardware/eicon/os_bri.c +++ b/drivers/isdn/hardware/eicon/os_bri.c @@ -16,6 +16,7 @@ #include "diva_pci.h" #include "mi_pc.h" #include "pc_maint.h" +#include "dsrv_bri.h" /* ** IMPORTS diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c index 8ac207f75e5..a296a846f29 100644 --- a/drivers/isdn/hardware/eicon/os_pri.c +++ b/drivers/isdn/hardware/eicon/os_pri.c @@ -18,6 +18,7 @@ #include "pc_maint.h" #include "dsp_tst.h" #include "diva_dma.h" +#include "dsrv_pri.h" /* -------------------------------------------------------------------------- OS Dependent part of XDI driver for DIVA PRI Adapter diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index c82105920d7..0ef560144be 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -110,7 +110,7 @@ config HISAX_16_3 config HISAX_TELESPCI bool "Teles PCI" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Teles PCI. See <file:Documentation/isdn/README.HiSax> on how to configure it. @@ -238,7 +238,7 @@ config HISAX_MIC config HISAX_NETJET bool "NETjet card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the NetJet from Traverse Technologies. @@ -249,7 +249,7 @@ config HISAX_NETJET config HISAX_NETJET_U bool "NETspider U card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Netspider U interface ISDN card from Traverse Technologies. @@ -317,7 +317,7 @@ config HISAX_GAZEL config HISAX_HFC_PCI bool "HFC PCI-Bus cards" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the HFC-S PCI 2BDS0 based cards. @@ -344,7 +344,7 @@ config HISAX_HFC_SX config HISAX_ENTERNOW_PCI bool "Formula-n enter:now PCI card" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K)) + depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || FRV)) help This enables HiSax support for the Formula-n enter:now PCI ISDN card. diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 26c545fa223..1b85ce166af 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -396,17 +396,17 @@ struct isar_hw { struct hdlc_stat_reg { #ifdef __BIG_ENDIAN - u_char fill __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char cmd __attribute__((packed)); + u_char fill; + u_char mode; + u_char xml; + u_char cmd; #else - u_char cmd __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char fill __attribute__((packed)); + u_char cmd; + u_char xml; + u_char mode; + u_char fill; #endif -}; +} __attribute__((packed)); struct hdlc_hw { union { diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h index bd8a22e4d6a..21fbcedf3a9 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.h +++ b/drivers/isdn/hisax/hisax_fcpcipnp.h @@ -12,17 +12,17 @@ enum { struct hdlc_stat_reg { #ifdef __BIG_ENDIAN - u_char fill __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char cmd __attribute__((packed)); + u_char fill; + u_char mode; + u_char xml; + u_char cmd; #else - u_char cmd __attribute__((packed)); - u_char xml __attribute__((packed)); - u_char mode __attribute__((packed)); - u_char fill __attribute__((packed)); + u_char cmd; + u_char xml; + u_char mode; + u_char fill; #endif -}; +} __attribute__((packed)); struct fritz_bcs { struct hisax_b_if b_if; diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c index 19f2fcf0ae4..b4b24335f71 100644 --- a/drivers/isdn/sc/command.c +++ b/drivers/isdn/sc/command.c @@ -43,7 +43,6 @@ extern int send_and_receive(int, unsigned int, unsigned char, unsigned char, RspMessage *, int); extern int sendmessage(int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); -extern inline void pullphone(char *, char *); #ifdef DEBUG /* diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c index 2c3158c81ff..4d811600bda 100644 --- a/drivers/macintosh/windfarm_smu_controls.c +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/wait.h> +#include <linux/completion.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c index b558cc209d4..1a00d9c75a2 100644 --- a/drivers/macintosh/windfarm_smu_sensors.c +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/wait.h> +#include <linux/completion.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> diff --git a/drivers/md/md.c b/drivers/md/md.c index 1b76fb29fb7..e423a16ba3c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3598,12 +3598,21 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev) return 0; } +static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + mddev_t *mddev = bdev->bd_disk->private_data; + + geo->heads = 2; + geo->sectors = 4; + geo->cylinders = get_capacity(mddev->gendisk) / 8; + return 0; +} + static int md_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; void __user *argp = (void __user *)arg; - struct hd_geometry __user *loc = argp; mddev_t *mddev = NULL; if (!capable(CAP_SYS_ADMIN)) @@ -3765,24 +3774,6 @@ static int md_ioctl(struct inode *inode, struct file *file, * 4 sectors (with a BIG number of cylinders...). This drives * dosfs just mad... ;-) */ - case HDIO_GETGEO: - if (!loc) { - err = -EINVAL; - goto abort_unlock; - } - err = put_user (2, (char __user *) &loc->heads); - if (err) - goto abort_unlock; - err = put_user (4, (char __user *) &loc->sectors); - if (err) - goto abort_unlock; - err = put_user(get_capacity(mddev->gendisk)/8, - (short __user *) &loc->cylinders); - if (err) - goto abort_unlock; - err = put_user (get_start_sect(inode->i_bdev), - (long __user *) &loc->start); - goto done_unlock; } /* @@ -3911,6 +3902,7 @@ static struct block_device_operations md_fops = .open = md_open, .release = md_release, .ioctl = md_ioctl, + .getgeo = md_getgeo, .media_changed = md_media_changed, .revalidate_disk= md_revalidate, }; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index abbca150202..d03f99cf4b7 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -306,9 +306,6 @@ static int raid0_run (mddev_t *mddev) printk("raid0 : conf->hash_spacing is %llu blocks.\n", (unsigned long long)conf->hash_spacing); { -#if __GNUC__ < 3 - volatile -#endif sector_t s = mddev->array_size; sector_t space = conf->hash_spacing; int round; @@ -439,9 +436,6 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) { -#if __GNUC__ < 3 - volatile -#endif sector_t x = block >> conf->preshift; sector_div(x, (u32)conf->hash_spacing); zone = conf->hash_table[x]; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 597b8db35a1..62a7d636ef1 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -191,9 +191,7 @@ char *v4l2_type_names[] = { }; char *v4l2_ioctl_names[256] = { -#if __GNUC__ >= 3 [0 ... 255] = "UNKNOWN", -#endif [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 5b1febed313..b09fb630715 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -662,6 +662,13 @@ static int i2o_block_release(struct inode *inode, struct file *file) return 0; } +static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + i2o_block_biosparam(get_capacity(bdev->bd_disk), + &geo->cylinders, &geo->heads, &geo->sectors); + return 0; +} + /** * i2o_block_ioctl - Issue device specific ioctl calls. * @cmd: ioctl command @@ -676,7 +683,6 @@ static int i2o_block_ioctl(struct inode *inode, struct file *file, { struct gendisk *disk = inode->i_bdev->bd_disk; struct i2o_block_device *dev = disk->private_data; - void __user *argp = (void __user *)arg; /* Anyone capable of this syscall can do *real bad* things */ @@ -684,15 +690,6 @@ static int i2o_block_ioctl(struct inode *inode, struct file *file, return -EPERM; switch (cmd) { - case HDIO_GETGEO: - { - struct hd_geometry g; - i2o_block_biosparam(get_capacity(disk), - &g.cylinders, &g.heads, &g.sectors); - g.start = get_start_sect(inode->i_bdev); - return copy_to_user(argp, &g, sizeof(g)) ? -EFAULT : 0; - } - case BLKI2OGRSTRAT: return put_user(dev->rcache, (int __user *)arg); case BLKI2OGWSTRAT: @@ -962,6 +959,7 @@ static struct block_device_operations i2o_block_fops = { .open = i2o_block_open, .release = i2o_block_release, .ioctl = i2o_block_ioctl, + .getgeo = i2o_block_getgeo, .media_changed = i2o_block_media_changed }; diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index e335d54c465..b42e0fbab59 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -27,7 +27,6 @@ #include <asm/dma.h> #include <asm/hardware.h> -#include <asm/irq.h> #include "ucb1x00.h" @@ -507,14 +506,14 @@ static int ucb1x00_probe(struct mcp *mcp) goto err_free; } - ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb); + ret = request_irq(ucb->irq, ucb1x00_irq, SA_TRIGGER_RISING, + "UCB1x00", ucb); if (ret) { printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", ucb->irq, ret); goto err_free; } - set_irq_type(ucb->irq, IRQT_RISING); mcp_set_drvdata(mcp, ucb); ret = class_device_register(&ucb->cdev); diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 551061c2ead..79fd062ccb3 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -32,7 +32,6 @@ #include <linux/suspend.h> #include <linux/slab.h> #include <linux/kthread.h> -#include <linux/delay.h> #include <asm/dma.h> #include <asm/semaphore.h> diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 198561d2171..d5f28981596 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -113,31 +113,18 @@ static int mmc_blk_release(struct inode *inode, struct file *filp) } static int -mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct block_device *bdev = inode->i_bdev; - - if (cmd == HDIO_GETGEO) { - struct hd_geometry geo; - - memset(&geo, 0, sizeof(struct hd_geometry)); - - geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16); - geo.heads = 4; - geo.sectors = 16; - geo.start = get_start_sect(bdev); - - return copy_to_user((void __user *)arg, &geo, sizeof(geo)) - ? -EFAULT : 0; - } - - return -ENOTTY; + geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16); + geo->heads = 4; + geo->sectors = 16; + return 0; } static struct block_device_operations mmc_bdops = { .open = mmc_blk_open, .release = mmc_blk_release, - .ioctl = mmc_blk_ioctl, + .getgeo = mmc_blk_getgeo, .owner = THIS_MODULE, }; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 339cb1218ea..7f3ff500b68 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -194,6 +194,14 @@ static int blktrans_release(struct inode *i, struct file *f) return ret; } +static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; + + if (dev->tr->getgeo) + return dev->tr->getgeo(dev, geo); + return -ENOTTY; +} static int blktrans_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -207,22 +215,6 @@ static int blktrans_ioctl(struct inode *inode, struct file *file, return tr->flush(dev); /* The core code did the work, we had nothing to do. */ return 0; - - case HDIO_GETGEO: - if (tr->getgeo) { - struct hd_geometry g; - int ret; - - memset(&g, 0, sizeof(g)); - ret = tr->getgeo(dev, &g); - if (ret) - return ret; - - g.start = get_start_sect(inode->i_bdev); - if (copy_to_user((void __user *)arg, &g, sizeof(g))) - return -EFAULT; - return 0; - } /* else */ default: return -ENOTTY; } @@ -233,6 +225,7 @@ struct block_device_operations mtd_blktrans_ops = { .open = blktrans_open, .release = blktrans_release, .ioctl = blktrans_ioctl, + .getgeo = blktrans_getgeo, }; int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 45c077d0f06..af06a80f44d 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/platform_device.h> #include <linux/mtd/mtd.h> #include <linux/mtd/onenand.h> diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 20ce212638f..a3e00a4635a 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -18,6 +18,7 @@ #include <linux/mtd/blktrans.h> #include <linux/mtd/mtd.h> #include <linux/vmalloc.h> +#include <linux/slab.h> #include <linux/jiffies.h> #include <asm/types.h> diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 5c5eebdb691..dcc98afa65d 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -148,14 +148,6 @@ el2_pio_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: el2_close() handles free_irq */ - release_region(dev->base_addr, EL2_IO_EXTENT); - if (ei_status.mem) - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init el2_probe(int unit) { @@ -726,6 +718,14 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: el2_close() handles free_irq */ + release_region(dev->base_addr, EL2_IO_EXTENT); + if (ei_status.mem) + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h index c10f009ce9b..53b5b071df0 100644 --- a/drivers/net/3c527.h +++ b/drivers/net/3c527.h @@ -32,43 +32,43 @@ struct mc32_mailbox { - u16 mbox __attribute((packed)); - u16 data[1] __attribute((packed)); -}; + u16 mbox; + u16 data[1]; +} __attribute((packed)); struct skb_header { - u8 status __attribute((packed)); - u8 control __attribute((packed)); - u16 next __attribute((packed)); /* Do not change! */ - u16 length __attribute((packed)); - u32 data __attribute((packed)); -}; + u8 status; + u8 control; + u16 next; /* Do not change! */ + u16 length; + u32 data; +} __attribute((packed)); struct mc32_stats { /* RX Errors */ - u32 rx_crc_errors __attribute((packed)); - u32 rx_alignment_errors __attribute((packed)); - u32 rx_overrun_errors __attribute((packed)); - u32 rx_tooshort_errors __attribute((packed)); - u32 rx_toolong_errors __attribute((packed)); - u32 rx_outofresource_errors __attribute((packed)); + u32 rx_crc_errors; + u32 rx_alignment_errors; + u32 rx_overrun_errors; + u32 rx_tooshort_errors; + u32 rx_toolong_errors; + u32 rx_outofresource_errors; - u32 rx_discarded __attribute((packed)); /* via card pattern match filter */ + u32 rx_discarded; /* via card pattern match filter */ /* TX Errors */ - u32 tx_max_collisions __attribute((packed)); - u32 tx_carrier_errors __attribute((packed)); - u32 tx_underrun_errors __attribute((packed)); - u32 tx_cts_errors __attribute((packed)); - u32 tx_timeout_errors __attribute((packed)) ; + u32 tx_max_collisions; + u32 tx_carrier_errors; + u32 tx_underrun_errors; + u32 tx_cts_errors; + u32 tx_timeout_errors; /* various cruft */ - u32 dataA[6] __attribute((packed)); - u16 dataB[5] __attribute((packed)); - u32 dataC[14] __attribute((packed)); -}; + u32 dataA[6]; + u16 dataB[5]; + u32 dataC[14]; +} __attribute((packed)); #define STATUS_MASK 0x0F #define COMPLETED (1<<7) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e2fa29b612c..733bc25b2bf 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -129,7 +129,7 @@ config NET_SB1000 If you don't have this card, of course say N. - source "drivers/net/arcnet/Kconfig" +source "drivers/net/arcnet/Kconfig" source "drivers/net/phy/Kconfig" @@ -844,7 +844,7 @@ config SMC9194 config DM9000 tristate "DM9000 support" - depends on ARM && NET_ETHERNET + depends on (ARM || MIPS) && NET_ETHERNET select CRC32 select MII ---help--- @@ -1374,7 +1374,7 @@ config FORCEDETH config CS89x0 tristate "CS89x0 support" - depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 + depends on NET_PCI && (ISA || ARCH_IXDP2X01 || ARCH_PNX010X) ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 8a0af5453e2..7952dc6d77e 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -123,14 +123,6 @@ static int __init do_ac3200_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* Someday free_irq may be in ac_close_card() */ - free_irq(dev->irq, dev); - release_region(dev->base_addr, AC_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init ac3200_probe(int unit) { @@ -406,6 +398,14 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* Someday free_irq may be in ac_close_card() */ + free_irq(dev->irq, dev); + release_region(dev->base_addr, AC_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 015c7f1d1bc..f20bb85c1ea 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -205,7 +205,7 @@ struct bonding { * * Caller must hold bond lock for read */ -extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) +static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { struct slave *slave = NULL; int i; @@ -219,7 +219,7 @@ extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n return slave; } -extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) +static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) { if (!slave || !slave->dev->master) { return NULL; @@ -228,13 +228,13 @@ extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return (struct bonding *)slave->dev->master->priv; } -extern inline void bond_set_slave_inactive_flags(struct slave *slave) +static inline void bond_set_slave_inactive_flags(struct slave *slave) { slave->state = BOND_STATE_BACKUP; slave->dev->flags |= IFF_NOARP; } -extern inline void bond_set_slave_active_flags(struct slave *slave) +static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; slave->dev->flags &= ~IFF_NOARP; diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index a6078ad9b65..907c0100974 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -175,7 +175,7 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0}; #include <asm/irq.h> static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; -#elif defined(CONFIG_ARCH_PNX0105) +#elif defined(CONFIG_ARCH_PNX010X) #include <asm/irq.h> #include <asm/arch/gpio.h> #define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */ @@ -338,30 +338,86 @@ out: } #endif +#if defined(CONFIG_ARCH_IXDP2X01) static int -readreg(struct net_device *dev, int portno) +readword(unsigned long base_addr, int portno) { - outw(portno, dev->base_addr + ADD_PORT); - return inw(dev->base_addr + DATA_PORT); + return (u16)__raw_readl(base_addr + (portno << 1)); } static void -writereg(struct net_device *dev, int portno, int value) +writeword(unsigned long base_addr, int portno, int value) { - outw(portno, dev->base_addr + ADD_PORT); - outw(value, dev->base_addr + DATA_PORT); + __raw_writel((u16)value, base_addr + (portno << 1)); +} +#else +#if defined(CONFIG_ARCH_PNX010X) +static int +readword(unsigned long base_addr, int portno) +{ + return inw(base_addr + (portno << 1)); +} + +static void +writeword(unsigned long base_addr, int portno, int value) +{ + outw(value, base_addr + (portno << 1)); +} +#else +static int +readword(unsigned long base_addr, int portno) +{ + return inw(base_addr + portno); +} + +static void +writeword(unsigned long base_addr, int portno, int value) +{ + outw(value, base_addr + portno); +} +#endif +#endif + +static void +readwords(unsigned long base_addr, int portno, void *buf, int length) +{ + u8 *buf8 = (u8 *)buf; + + do { + u32 tmp32; + + tmp32 = readword(base_addr, portno); + *buf8++ = (u8)tmp32; + *buf8++ = (u8)(tmp32 >> 8); + } while (--length); +} + +static void +writewords(unsigned long base_addr, int portno, void *buf, int length) +{ + u8 *buf8 = (u8 *)buf; + + do { + u32 tmp32; + + tmp32 = *buf8++; + tmp32 |= (*buf8++) << 8; + writeword(base_addr, portno, tmp32); + } while (--length); } static int -readword(struct net_device *dev, int portno) +readreg(struct net_device *dev, int regno) { - return inw(dev->base_addr + portno); + writeword(dev->base_addr, ADD_PORT, regno); + return readword(dev->base_addr, DATA_PORT); } static void -writeword(struct net_device *dev, int portno, int value) +writereg(struct net_device *dev, int regno, int value) { - outw(value, dev->base_addr + portno); + writeword(dev->base_addr, ADD_PORT, regno); + writeword(dev->base_addr, DATA_PORT, value); } static int __init @@ -456,7 +512,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) #endif } -#ifdef CONFIG_ARCH_PNX0105 +#ifdef CONFIG_ARCH_PNX010X initialize_ebi(); /* Map GPIO registers for the pins connected to the CS8900a. */ @@ -491,8 +547,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) #ifdef CONFIG_SH_HICOSH4 /* truely reset the chip */ - outw(0x0114, ioaddr + ADD_PORT); - outw(0x0040, ioaddr + DATA_PORT); + writeword(ioaddr, ADD_PORT, 0x0114); + writeword(ioaddr, DATA_PORT, 0x0040); #endif /* if they give us an odd I/O address, then do ONE write to @@ -503,24 +559,24 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) if (net_debug > 1) printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); if ((ioaddr & 2) != 2) - if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) { + if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) { printk(KERN_ERR "%s: bad signature 0x%x\n", - dev->name, inw((ioaddr & ~3)+ ADD_PORT)); + dev->name, readword(ioaddr & ~3, ADD_PORT)); retval = -ENODEV; goto out2; } } - printk(KERN_DEBUG "PP_addr at %x: 0x%x\n", - ioaddr + ADD_PORT, inw(ioaddr + ADD_PORT)); + printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n", + ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT)); ioaddr &= ~3; - outw(PP_ChipID, ioaddr + ADD_PORT); + writeword(ioaddr, ADD_PORT, PP_ChipID); - tmp = inw(ioaddr + DATA_PORT); + tmp = readword(ioaddr, DATA_PORT); if (tmp != CHIP_EISA_ID_SIG) { - printk(KERN_DEBUG "%s: incorrect signature at %x: 0x%x!=" + printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!=" CHIP_EISA_ID_SIG_STR "\n", - dev->name, ioaddr + DATA_PORT, tmp); + dev->name, ioaddr, DATA_PORT, tmp); retval = -ENODEV; goto out2; } @@ -724,7 +780,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } else { i = lp->isa_config & INT_NO_MASK; if (lp->chip_type == CS8900) { -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) +#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X) i = cs8900_irq_map[0]; #else /* Translate the IRQ using the IRQ mapping table. */ @@ -790,7 +846,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) goto out3; return 0; out3: - outw(PP_ChipID, dev->base_addr + ADD_PORT); + writeword(dev->base_addr, ADD_PORT, PP_ChipID); out2: release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: @@ -970,11 +1026,11 @@ void __init reset_chip(struct net_device *dev) #ifndef CONFIG_ARCH_IXDP2X01 if (lp->chip_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ - outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT); + writeword(ioaddr, ADD_PORT, PP_CS8920_ISAINT); outb(dev->irq, ioaddr + DATA_PORT); outb(0, ioaddr + DATA_PORT + 1); - outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT); + writeword(ioaddr, ADD_PORT, PP_CS8920_ISAMemB); outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } @@ -1104,8 +1160,8 @@ send_test_pkt(struct net_device *dev) memcpy(test_packet, dev->dev_addr, ETH_ALEN); memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN); - writeword(dev, TX_CMD_PORT, TX_AFTER_ALL); - writeword(dev, TX_LEN_PORT, ETH_ZLEN); + writeword(dev->base_addr, TX_CMD_PORT, TX_AFTER_ALL); + writeword(dev->base_addr, TX_LEN_PORT, ETH_ZLEN); /* Test to see if the chip has allocated memory for the packet */ while (jiffies - timenow < 5) @@ -1115,7 +1171,7 @@ send_test_pkt(struct net_device *dev) return 0; /* this shouldn't happen */ /* Write the contents of the packet */ - outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); + writewords(dev->base_addr, TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); if (net_debug > 1) printk("Sending test packet "); /* wait a couple of jiffies for packet to be received */ @@ -1200,7 +1256,7 @@ net_open(struct net_device *dev) int i; int ret; -#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */ +#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX010X) /* uses irq#1, so this won't work */ if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ /* Cirrus' release had this: */ @@ -1231,7 +1287,7 @@ net_open(struct net_device *dev) else #endif { -#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) +#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X) if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); @@ -1316,7 +1372,7 @@ net_open(struct net_device *dev) case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break; default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); } -#ifdef CONFIG_ARCH_PNX0105 +#ifdef CONFIG_ARCH_PNX010X result = A_CNF_10B_T; #endif if (!result) { @@ -1457,8 +1513,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); /* initiate a transmit sequence */ - writeword(dev, TX_CMD_PORT, lp->send_cmd); - writeword(dev, TX_LEN_PORT, skb->len); + writeword(dev->base_addr, TX_CMD_PORT, lp->send_cmd); + writeword(dev->base_addr, TX_LEN_PORT, skb->len); /* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { @@ -1472,7 +1528,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) return 1; } /* Write the contents of the packet */ - outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); + writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); spin_unlock_irq(&lp->lock); lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; @@ -1512,7 +1568,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs) course, if you're on a slow machine, and packets are arriving faster than you can read them off, you're screwed. Hasta la vista, baby! */ - while ((status = readword(dev, ISQ_PORT))) { + while ((status = readword(dev->base_addr, ISQ_PORT))) { if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); handled = 1; switch(status & ISQ_EVENT_MASK) { @@ -1606,8 +1662,8 @@ net_rx(struct net_device *dev) int status, length; int ioaddr = dev->base_addr; - status = inw(ioaddr + RX_FRAME_PORT); - length = inw(ioaddr + RX_FRAME_PORT); + status = readword(ioaddr, RX_FRAME_PORT); + length = readword(ioaddr, RX_FRAME_PORT); if ((status & RX_OK) == 0) { count_rx_errors(status, lp); @@ -1626,9 +1682,9 @@ net_rx(struct net_device *dev) skb_reserve(skb, 2); /* longword align L3 header */ skb->dev = dev; - insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1); + readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1); if (length & 1) - skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT); + skb->data[length-1] = readword(ioaddr, RX_FRAME_PORT); if (net_debug > 3) { printk( "%s: received %d byte packet of type %x\n", @@ -1901,7 +1957,7 @@ void cleanup_module(void) { unregister_netdev(dev_cs89x0); - outw(PP_ChipID, dev_cs89x0->base_addr + ADD_PORT); + writeword(dev_cs89x0->base_addr, ADD_PORT, PP_ChipID); release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); free_netdev(dev_cs89x0); } diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index decea264f12..bd954aaa636 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -16,13 +16,6 @@ #include <linux/config.h> -#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) -/* IXDP2401/IXDP2801 uses dword-aligned register addressing */ -#define CS89x0_PORT(reg) ((reg) * 2) -#else -#define CS89x0_PORT(reg) (reg) -#endif - #define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ /* offset 2h -> Model/Product Number */ /* offset 3h -> Chip Revision Number */ @@ -332,16 +325,16 @@ #define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ #define PKT_START PP_TxFrame /* Start of packet RAM */ -#define RX_FRAME_PORT CS89x0_PORT(0x0000) +#define RX_FRAME_PORT 0x0000 #define TX_FRAME_PORT RX_FRAME_PORT -#define TX_CMD_PORT CS89x0_PORT(0x0004) +#define TX_CMD_PORT 0x0004 #define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ #define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ #define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ -#define TX_LEN_PORT CS89x0_PORT(0x0006) -#define ISQ_PORT CS89x0_PORT(0x0008) -#define ADD_PORT CS89x0_PORT(0x000A) -#define DATA_PORT CS89x0_PORT(0x000C) +#define TX_LEN_PORT 0x0006 +#define ISQ_PORT 0x0008 +#define ADD_PORT 0x000A +#define DATA_PORT 0x000C #define EEPROM_WRITE_EN 0x00F0 #define EEPROM_WRITE_DIS 0x0000 diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 38695d5b463..ccbbe5ad8e0 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -545,7 +545,7 @@ e1000_check_fiber_options(struct e1000_adapter *adapter) static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter) { - int speed, dplx; + int speed, dplx, an; int bd = adapter->bd_number; { /* Speed */ @@ -641,8 +641,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .p = an_list }} }; - int an = AutoNeg[bd]; - e1000_validate_option(&an, &opt, adapter); + if (num_AutoNeg > bd) { + an = AutoNeg[bd]; + e1000_validate_option(&an, &opt, adapter); + } else { + an = opt.def; + } adapter->hw.autoneg_advertised = an; } diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index f5a4dd7d856..e5c5cd2a271 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -140,13 +140,6 @@ static int __init do_e2100_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: e21_close() handles free_irq */ - iounmap(ei_status.mem); - release_region(dev->base_addr, E21_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init e2100_probe(int unit) { @@ -463,6 +456,13 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: e21_close() handles free_irq */ + iounmap(ei_status.mem); + release_region(dev->base_addr, E21_IO_EXTENT); +} + void cleanup_module(void) { diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 50f8e23bb9e..6b0ab1eac3f 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -155,13 +155,6 @@ static int __init do_es_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr, ES_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init es_probe(int unit) { @@ -456,6 +449,13 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, ES_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index c39344adecc..3682ec61e8a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -101,6 +101,7 @@ * 0.46: 20 Oct 2005: Add irq optimization modes. * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single + * 0.49: 10 Dec 2005: Fix tso for large buffers. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -112,7 +113,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.48" +#define FORCEDETH_VERSION "0.49" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -349,6 +350,8 @@ typedef union _ring_type { #define NV_TX2_VALID (1<<31) #define NV_TX2_TSO (1<<28) #define NV_TX2_TSO_SHIFT 14 +#define NV_TX2_TSO_MAX_SHIFT 14 +#define NV_TX2_TSO_MAX_SIZE (1<<NV_TX2_TSO_MAX_SHIFT) #define NV_TX2_CHECKSUM_L3 (1<<27) #define NV_TX2_CHECKSUM_L4 (1<<26) @@ -408,15 +411,15 @@ typedef union _ring_type { #define NV_WATCHDOG_TIMEO (5*HZ) #define RX_RING 128 -#define TX_RING 64 +#define TX_RING 256 /* * If your nic mysteriously hangs then try to reduce the limits * to 1/0: It might be required to set NV_TX_LASTPACKET in the * last valid ring entry. But this would be impossible to * implement - probably a disassembly error. */ -#define TX_LIMIT_STOP 63 -#define TX_LIMIT_START 62 +#define TX_LIMIT_STOP 255 +#define TX_LIMIT_START 254 /* rx/tx mac addr + type + vlan + align + slack*/ #define NV_RX_HEADERS (64) @@ -535,6 +538,7 @@ struct fe_priv { unsigned int next_tx, nic_tx; struct sk_buff *tx_skbuff[TX_RING]; dma_addr_t tx_dma[TX_RING]; + unsigned int tx_dma_len[TX_RING]; u32 tx_flags; }; @@ -935,6 +939,7 @@ static void nv_init_tx(struct net_device *dev) else np->tx_ring.ex[i].FlagLen = 0; np->tx_skbuff[i] = NULL; + np->tx_dma[i] = 0; } } @@ -945,30 +950,27 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx(dev); } -static void nv_release_txskb(struct net_device *dev, unsigned int skbnr) +static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) { struct fe_priv *np = netdev_priv(dev); - struct sk_buff *skb = np->tx_skbuff[skbnr]; - unsigned int j, entry, fragments; - - dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n", - dev->name, skbnr, np->tx_skbuff[skbnr]); - - entry = skbnr; - if ((fragments = skb_shinfo(skb)->nr_frags) != 0) { - for (j = fragments; j >= 1; j--) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1]; - pci_unmap_page(np->pci_dev, np->tx_dma[entry], - frag->size, - PCI_DMA_TODEVICE); - entry = (entry - 1) % TX_RING; - } + + dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n", + dev->name, skbnr); + + if (np->tx_dma[skbnr]) { + pci_unmap_page(np->pci_dev, np->tx_dma[skbnr], + np->tx_dma_len[skbnr], + PCI_DMA_TODEVICE); + np->tx_dma[skbnr] = 0; + } + + if (np->tx_skbuff[skbnr]) { + dev_kfree_skb_irq(np->tx_skbuff[skbnr]); + np->tx_skbuff[skbnr] = NULL; + return 1; + } else { + return 0; } - pci_unmap_single(np->pci_dev, np->tx_dma[entry], - skb->len - skb->data_len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - np->tx_skbuff[skbnr] = NULL; } static void nv_drain_tx(struct net_device *dev) @@ -981,10 +983,8 @@ static void nv_drain_tx(struct net_device *dev) np->tx_ring.orig[i].FlagLen = 0; else np->tx_ring.ex[i].FlagLen = 0; - if (np->tx_skbuff[i]) { - nv_release_txskb(dev, i); + if (nv_release_txskb(dev, i)) np->stats.tx_dropped++; - } } } @@ -1021,68 +1021,105 @@ static void drain_ring(struct net_device *dev) static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); + u32 tx_flags = 0; u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); unsigned int fragments = skb_shinfo(skb)->nr_frags; - unsigned int nr = (np->next_tx + fragments) % TX_RING; + unsigned int nr = (np->next_tx - 1) % TX_RING; + unsigned int start_nr = np->next_tx % TX_RING; unsigned int i; + u32 offset = 0; + u32 bcnt; + u32 size = skb->len-skb->data_len; + u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + + /* add fragments to entries count */ + for (i = 0; i < fragments; i++) { + entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) + + ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + } spin_lock_irq(&np->lock); - if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) { + if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) { spin_unlock_irq(&np->lock); netif_stop_queue(dev); return NETDEV_TX_BUSY; } - np->tx_skbuff[nr] = skb; - - if (fragments) { - dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments); - /* setup descriptors in reverse order */ - for (i = fragments; i >= 1; i--) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; - np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size, - PCI_DMA_TODEVICE); + /* setup the header buffer */ + do { + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + nr = (nr + 1) % TX_RING; + + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + PCI_DMA_TODEVICE); + np->tx_dma_len[nr] = bcnt; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } + tx_flags = np->tx_flags; + offset += bcnt; + size -= bcnt; + } while(size); + + /* setup the fragments */ + for (i = 0; i < fragments; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 size = frag->size; + offset = 0; + + do { + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + nr = (nr + 1) % TX_RING; + + np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->tx_dma_len[nr] = bcnt; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); } else { np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); } - - nr = (nr - 1) % TX_RING; + offset += bcnt; + size -= bcnt; + } while (size); + } - if (np->desc_ver == DESC_VER_1) - tx_flags_extra &= ~NV_TX_LASTPACKET; - else - tx_flags_extra &= ~NV_TX2_LASTPACKET; - } + /* set last fragment flag */ + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra); + } else { + np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra); } + np->tx_skbuff[nr] = skb; + #ifdef NETIF_F_TSO if (skb_shinfo(skb)->tso_size) - tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); else #endif - tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); + tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len, - PCI_DMA_TODEVICE); - + /* set tx flags */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); } else { - np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); } - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n", - dev->name, np->next_tx, tx_flags_extra); + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", + dev->name, np->next_tx, entries, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -1093,7 +1130,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dprintk("\n"); } - np->next_tx += 1 + fragments; + np->next_tx += entries; dev->trans_start = jiffies; spin_unlock_irq(&np->lock); @@ -1140,7 +1177,6 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_packets++; np->stats.tx_bytes += skb->len; } - nv_release_txskb(dev, i); } } else { if (Flags & NV_TX2_LASTPACKET) { @@ -1156,9 +1192,9 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_packets++; np->stats.tx_bytes += skb->len; } - nv_release_txskb(dev, i); } } + nv_release_txskb(dev, i); np->nic_tx++; } if (np->next_tx - np->nic_tx < TX_LIMIT_START) @@ -2456,7 +2492,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; #ifdef NETIF_F_TSO - /* disabled dev->features |= NETIF_F_TSO; */ + dev->features |= NETIF_F_TSO; #endif } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 94a91da84fb..cb9d66ac3ab 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -718,14 +718,14 @@ struct gfar_private { uint32_t msg_enable; }; -extern inline u32 gfar_read(volatile unsigned *addr) +static inline u32 gfar_read(volatile unsigned *addr) { u32 val; val = in_be32(addr); return val; } -extern inline void gfar_write(volatile unsigned *addr, u32 val) +static inline void gfar_write(volatile unsigned *addr, u32 val) { out_be32(addr, val); } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 3e9accf137e..41b3d83c2ab 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -524,6 +524,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; + spin_unlock_bh(&ax->buflock); } /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 0abf5dd08b4..74e167e7dea 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -138,12 +138,6 @@ static int __init do_hpp_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: hpp_close() handles free_irq */ - release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init hp_plus_probe(int unit) { @@ -473,6 +467,12 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: hpp_close() handles free_irq */ + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + void cleanup_module(void) { diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 59cf841b14a..cf9fb3698a6 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -102,12 +102,6 @@ static int __init do_hp_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init hp_probe(int unit) { @@ -444,6 +438,12 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); +} + void cleanup_module(void) { diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h index 644edbff4f9..c2dae6092c4 100644 --- a/drivers/net/ibm_emac/ibm_emac.h +++ b/drivers/net/ibm_emac/ibm_emac.h @@ -110,6 +110,7 @@ struct emac_regs { #define EMAC_MR1_TFS_2K 0x00080000 #define EMAC_MR1_TR0_MULT 0x00008000 #define EMAC_MR1_JPSM 0x00000000 +#define EMAC_MR1_MWSW_001 0x00000000 #define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT) #else #define EMAC_MR1_RFS_4K 0x00180000 @@ -130,7 +131,7 @@ struct emac_regs { (freq) <= 83 ? EMAC_MR1_OBCI_83 : \ (freq) <= 100 ? EMAC_MR1_OBCI_100 : EMAC_MR1_OBCI_100P) #define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR | \ - EMAC_MR1_MWSW_001 | EMAC_MR1_OBCI(opb)) + EMAC_MR1_OBCI(opb)) #endif /* EMACx_TMR0 */ diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 1da8a66f91e..591c5864ffb 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -408,7 +408,7 @@ static int emac_configure(struct ocp_enet_private *dev) /* Mode register */ r = EMAC_MR1_BASE(emac_opb_mhz()) | EMAC_MR1_VLE | EMAC_MR1_IST; if (dev->phy.duplex == DUPLEX_FULL) - r |= EMAC_MR1_FDE; + r |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001; dev->stop_timeout = STOP_TIMEOUT_10; switch (dev->phy.speed) { case SPEED_1000: diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index 741aecc655d..a82a4ba8de4 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -577,8 +577,8 @@ struct ring_descr_hw { struct { u8 addr_res[3]; volatile u8 status; /* descriptor status */ - } rd_s __attribute__((packed)); - } rd_u __attribute((packed)); + } __attribute__((packed)) rd_s; + } __attribute((packed)) rd_u; } __attribute__ ((packed)); #define rd_addr rd_u.addr diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 1d75ca0bb93..d1d714faa6c 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -309,17 +309,6 @@ static void lance_tx_timeout (struct net_device *dev); -static void cleanup_card(struct net_device *dev) -{ - struct lance_private *lp = dev->priv; - if (dev->dma != 4) - free_dma(dev->dma); - release_region(dev->base_addr, LANCE_TOTAL_SIZE); - kfree(lp->tx_bounce_buffs); - kfree((void*)lp->rx_buffs); - kfree(lp); -} - #ifdef MODULE #define MAX_CARDS 8 /* Max number of interfaces (cards) per module */ @@ -367,6 +356,17 @@ int init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + struct lance_private *lp = dev->priv; + if (dev->dma != 4) + free_dma(dev->dma); + release_region(dev->base_addr, LANCE_TOTAL_SIZE); + kfree(lp->tx_bounce_buffs); + kfree((void*)lp->rx_buffs); + kfree(lp); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 309d254842c..646e89fc356 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -145,13 +145,6 @@ static int __init do_lne390_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr, LNE390_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init lne390_probe(int unit) { @@ -440,6 +433,13 @@ int init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr, LNE390_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 3cb9b3fe0cf..22c3a37bba5 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -6,7 +6,7 @@ * Copyright (C) 2002 rabeeh@galileo.co.il * * Copyright (C) 2003 PMC-Sierra, Inc., - * written by Manish Lachwani (lachwani@pmc-sierra.com) + * written by Manish Lachwani * * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org> * diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 0de8fdd2aa8..94f782d51f0 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -212,15 +212,6 @@ static int __init do_ne_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init ne_probe(int unit) { @@ -859,6 +850,15 @@ int init_module(void) return -ENODEV; } +static void cleanup_card(struct net_device *dev) +{ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 6d62ada85de..e6df375a1d4 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -278,14 +278,6 @@ static int __init do_ne2_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - mca_mark_as_unused(ei_status.priv); - mca_set_adapter_procfn( ei_status.priv, NULL, NULL); - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); -} - #ifndef MODULE struct net_device * __init ne2_probe(int unit) { @@ -812,6 +804,14 @@ int init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + mca_mark_as_unused(ei_status.priv); + mca_set_adapter_procfn( ei_status.priv, NULL, NULL); + free_irq(dev->irq, dev); + release_region(dev->base_addr, NE_IO_EXTENT); +} + void cleanup_module(void) { int this_dev; diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 9a76ac180b1..197edd74fbb 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -282,26 +282,22 @@ SK_U32 Val) /* pointer to store the read value */ * Description: * This function initialize the PCI resources and IO * - * Returns: N/A - * + * Returns: + * 0 - indicate everything worked ok. + * != 0 - error indication */ -int SkGeInitPCI(SK_AC *pAC) +static __devinit int SkGeInitPCI(SK_AC *pAC) { struct SK_NET_DEVICE *dev = pAC->dev[0]; struct pci_dev *pdev = pAC->PciDev; int retval; - if (pci_enable_device(pdev) != 0) { - return 1; - } - dev->mem_start = pci_resource_start (pdev, 0); pci_set_master(pdev); - if (pci_request_regions(pdev, "sk98lin") != 0) { - retval = 2; - goto out_disable; - } + retval = pci_request_regions(pdev, "sk98lin"); + if (retval) + goto out; #ifdef SK_BIG_ENDIAN /* @@ -320,9 +316,8 @@ int SkGeInitPCI(SK_AC *pAC) * Remap the regs into kernel space. */ pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000); - - if (!pAC->IoBase){ - retval = 3; + if (!pAC->IoBase) { + retval = -EIO; goto out_release; } @@ -330,8 +325,7 @@ int SkGeInitPCI(SK_AC *pAC) out_release: pci_release_regions(pdev); - out_disable: - pci_disable_device(pdev); + out: return retval; } @@ -492,7 +486,7 @@ module_param_array(AutoSizing, charp, NULL, 0); * 0, if everything is ok * !=0, on error */ -static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC) +static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC) { short i; unsigned long Flags; @@ -529,7 +523,7 @@ SK_BOOL DualNet; if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) { printk("HWInit (0) failed.\n"); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - return(-EAGAIN); + return -EIO; } SkI2cInit( pAC, pAC->IoBase, SK_INIT_DATA); SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA); @@ -551,7 +545,7 @@ SK_BOOL DualNet; if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) { printk("sk98lin: HWInit (1) failed.\n"); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - return(-EAGAIN); + return -EIO; } SkI2cInit( pAC, pAC->IoBase, SK_INIT_IO); SkEventInit(pAC, pAC->IoBase, SK_INIT_IO); @@ -583,20 +577,20 @@ SK_BOOL DualNet; } else { printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n", pAC->GIni.GIMacsFound); - return -EAGAIN; + return -EIO; } if (Ret) { printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n", dev->irq); - return -EAGAIN; + return Ret; } pAC->AllocFlag |= SK_ALLOC_IRQ; /* Alloc memory for this board (Mem for RxD/TxD) : */ if(!BoardAllocMem(pAC)) { printk("No memory for descriptor rings.\n"); - return(-EAGAIN); + return -ENOMEM; } BoardInitMem(pAC); @@ -612,7 +606,7 @@ SK_BOOL DualNet; DualNet)) { BoardFreeMem(pAC); printk("sk98lin: SkGeInitAssignRamToQueues failed.\n"); - return(-EAGAIN); + return -EIO; } return (0); @@ -633,8 +627,7 @@ SK_BOOL DualNet; * SK_TRUE, if all memory could be allocated * SK_FALSE, if not */ -static SK_BOOL BoardAllocMem( -SK_AC *pAC) +static __devinit SK_BOOL BoardAllocMem(SK_AC *pAC) { caddr_t pDescrMem; /* pointer to descriptor memory area */ size_t AllocLength; /* length of complete descriptor area */ @@ -727,8 +720,7 @@ size_t AllocLength; /* length of complete descriptor area */ * * Returns: N/A */ -static void BoardInitMem( -SK_AC *pAC) /* pointer to adapter context */ +static __devinit void BoardInitMem(SK_AC *pAC) { int i; /* loop counter */ int RxDescrSize; /* the size of a rx descriptor rounded up to alignment*/ @@ -4776,32 +4768,47 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, struct net_device *dev = NULL; static int boards_found = 0; int error = -ENODEV; + int using_dac = 0; char DeviceStr[80]; if (pci_enable_device(pdev)) goto out; /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) && - pci_set_dma_mask(pdev, DMA_32BIT_MASK)) - goto out_disable_device; - + if (sizeof(dma_addr_t) > sizeof(u32) && + !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + using_dac = 1; + error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (error < 0) { + printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA " + "for consistent allocations\n", pci_name(pdev)); + goto out_disable_device; + } + } else { + error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (error) { + printk(KERN_ERR "sk98lin %s no usable DMA configuration\n", + pci_name(pdev)); + goto out_disable_device; + } + } - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { - printk(KERN_ERR "Unable to allocate etherdev " + error = -ENOMEM; + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { + printk(KERN_ERR "sk98lin: unable to allocate etherdev " "structure!\n"); goto out_disable_device; } pNet = netdev_priv(dev); - pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); + pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL); if (!pNet->pAC) { - printk(KERN_ERR "Unable to allocate adapter " + printk(KERN_ERR "sk98lin: unable to allocate adapter " "structure!\n"); goto out_free_netdev; } - memset(pNet->pAC, 0, sizeof(SK_AC)); pAC = pNet->pAC; pAC->PciDev = pdev; @@ -4810,6 +4817,7 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, pAC->CheckQueue = SK_FALSE; dev->irq = pdev->irq; + error = SkGeInitPCI(pAC); if (error) { printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error); @@ -4844,19 +4852,25 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, #endif } + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + pAC->Index = boards_found++; - if (SkGeBoardInit(dev, pAC)) + error = SkGeBoardInit(dev, pAC); + if (error) goto out_free_netdev; /* Read Adapter name from VPD */ if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) { + error = -EIO; printk(KERN_ERR "sk98lin: Could not read VPD data.\n"); goto out_free_resources; } /* Register net device */ - if (register_netdev(dev)) { + error = register_netdev(dev); + if (error) { printk(KERN_ERR "sk98lin: Could not register device.\n"); goto out_free_resources; } @@ -4883,15 +4897,17 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, boards_found++; + pci_set_drvdata(pdev, dev); + /* More then one port found */ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { - printk(KERN_ERR "Unable to allocate etherdev " + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { + printk(KERN_ERR "sk98lin: unable to allocate etherdev " "structure!\n"); - goto out; + goto single_port; } - pAC->dev[1] = dev; pNet = netdev_priv(dev); pNet->PortNr = 1; pNet->NetNr = 1; @@ -4920,20 +4936,28 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, #endif } - if (register_netdev(dev)) { - printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n"); + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + + error = register_netdev(dev); + if (error) { + printk(KERN_ERR "sk98lin: Could not register device" + " for second port. (%d)\n", error); free_netdev(dev); - pAC->dev[1] = pAC->dev[0]; - } else { - memcpy(&dev->dev_addr, - &pAC->Addr.Net[1].CurrentMacAddress, 6); - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - - printk("%s: %s\n", dev->name, DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + goto single_port; } + + pAC->dev[1] = dev; + memcpy(&dev->dev_addr, + &pAC->Addr.Net[1].CurrentMacAddress, 6); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + printk("%s: %s\n", dev->name, DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); } +single_port: + /* Save the hardware revision */ pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + (pAC->GIni.GIPciHwRev & 0x0F); @@ -4945,7 +4969,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev, memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA)); memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA)); - pci_set_drvdata(pdev, dev); return 0; out_free_resources: diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index ba8593ac3f8..3db30cd0625 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -168,18 +168,6 @@ static int __init do_ultra_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - /* NB: ultra_close_card() does free_irq */ -#ifdef __ISAPNP__ - struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; - if (idev) - pnp_device_detach(idev); -#endif - release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init ultra_probe(int unit) { @@ -594,6 +582,18 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + /* NB: ultra_close_card() does free_irq */ +#ifdef __ISAPNP__ + struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; + if (idev) + pnp_device_detach(idev); +#endif + release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 28bf2e69eb5..7ec08127c9d 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -88,7 +88,6 @@ static const char version[] = #include <linux/skbuff.h> #include <asm/io.h> -#include <asm/irq.h> #include "smc91x.h" @@ -2007,12 +2006,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) } /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev); if (retval) goto err_out; - set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); - #ifdef SMC_USE_PXA_DMA { int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 5c2824be4ee..e0efd1964e7 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -90,7 +90,7 @@ __l--; \ } \ } while (0) -#define set_irq_type(irq, type) +#define SMC_IRQ_FLAGS (0) #elif defined(CONFIG_SA1100_PLEB) /* We can only do 16-bit reads and writes in the static memory space. */ @@ -109,7 +109,7 @@ #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define set_irq_type(irq, type) do {} while (0) +#define SMC_IRQ_FLAGS (0) #elif defined(CONFIG_SA1100_ASSABET) @@ -185,11 +185,11 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #include <asm/mach-types.h> #include <asm/arch/cpu.h> -#define SMC_IRQ_TRIGGER_TYPE (( \ +#define SMC_IRQ_FLAGS (( \ machine_is_omap_h2() \ || machine_is_omap_h3() \ || (machine_is_omap_innovator() && !cpu_is_omap1510()) \ - ) ? IRQT_FALLING : IRQT_RISING) + ) ? SA_TRIGGER_FALLING : SA_TRIGGER_RISING) #elif defined(CONFIG_SH_SH4202_MICRODEV) @@ -209,7 +209,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) #define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) -#define set_irq_type(irq, type) do {} while(0) +#define SMC_IRQ_FLAGS (0) #elif defined(CONFIG_ISA) @@ -237,7 +237,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insw(a, r, p, l) insw(((u32)a) + (r), p, l) #define SMC_outsw(a, r, p, l) outsw(((u32)a) + (r), p, l) -#define set_irq_type(irq, type) do {} while(0) +#define SMC_IRQ_FLAGS (0) #define RPC_LSA_DEFAULT RPC_LED_TX_RX #define RPC_LSB_DEFAULT RPC_LED_100_10 @@ -319,7 +319,7 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) au_writew(*_p++ , _a); \ } while(0) -#define set_irq_type(irq, type) do {} while (0) +#define SMC_IRQ_FLAGS (0) #else @@ -342,8 +342,8 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) #endif -#ifndef SMC_IRQ_TRIGGER_TYPE -#define SMC_IRQ_TRIGGER_TYPE IRQT_RISING +#ifndef SMC_IRQ_FLAGS +#define SMC_IRQ_FLAGS SA_TRIGGER_RISING #endif #ifdef SMC_USE_PXA_DMA diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 125ed00e95a..c67c91251d0 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1564,7 +1564,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, dev->dev_addr, 6); } #endif -#if defined(__i386__) /* Patch up x86 BIOS bug. */ +#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */ if (last_irq) irq = last_irq; #endif diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 036adc4f8ba..22e794071cf 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -329,9 +329,9 @@ static int sdla_cpuspeed(struct net_device *dev, struct ifreq *ifr) struct _dlci_stat { - short dlci __attribute__((packed)); - char flags __attribute__((packed)); -}; + short dlci; + char flags; +} __attribute__((packed)); struct _frad_stat { diff --git a/drivers/net/wd.c b/drivers/net/wd.c index b03feae459f..7caa8dc88a5 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -127,13 +127,6 @@ static int __init do_wd_probe(struct net_device *dev) return -ENODEV; } -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); - iounmap(ei_status.mem); -} - #ifndef MODULE struct net_device * __init wd_probe(int unit) { @@ -538,6 +531,13 @@ init_module(void) return -ENXIO; } +static void cleanup_card(struct net_device *dev) +{ + free_irq(dev->irq, dev); + release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT); + iounmap(ei_status.mem); +} + void cleanup_module(void) { diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 44cd3fcd157..cf05661fb1b 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -7153,7 +7153,7 @@ static int ipw2100_wx_get_range(struct net_device *dev, /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; + range->we_version_source = 18; // range->retry_capa; /* What retry options are supported */ // range->retry_flags; /* How to decode max/min retry limit */ @@ -7184,6 +7184,9 @@ static int ipw2100_wx_get_range(struct net_device *dev, IW_EVENT_CAPA_MASK(SIOCGIWAP)); range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + IPW_DEBUG_WX("GET Range\n"); return 0; diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 531b0731314..b2e8e49c865 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -43,13 +43,16 @@ static void process_task_mortuary(void); * list for processing. Only after two full buffer syncs * does the task eventually get freed, because by then * we are sure we will not reference it again. + * Can be invoked from softirq via RCU callback due to + * call_rcu() of the task struct, hence the _irqsave. */ static int task_free_notify(struct notifier_block * self, unsigned long val, void * data) { + unsigned long flags; struct task_struct * task = data; - spin_lock(&task_mortuary); + spin_lock_irqsave(&task_mortuary, flags); list_add(&task->tasks, &dying_tasks); - spin_unlock(&task_mortuary); + spin_unlock_irqrestore(&task_mortuary, flags); return NOTIFY_OK; } @@ -431,25 +434,22 @@ static void increment_tail(struct oprofile_cpu_buffer * b) */ static void process_task_mortuary(void) { - struct list_head * pos; - struct list_head * pos2; + unsigned long flags; + LIST_HEAD(local_dead_tasks); struct task_struct * task; + struct task_struct * ttask; - spin_lock(&task_mortuary); + spin_lock_irqsave(&task_mortuary, flags); - list_for_each_safe(pos, pos2, &dead_tasks) { - task = list_entry(pos, struct task_struct, tasks); - list_del(&task->tasks); - free_task(task); - } + list_splice_init(&dead_tasks, &local_dead_tasks); + list_splice_init(&dying_tasks, &dead_tasks); - list_for_each_safe(pos, pos2, &dying_tasks) { - task = list_entry(pos, struct task_struct, tasks); + spin_unlock_irqrestore(&task_mortuary, flags); + + list_for_each_entry_safe(task, ttask, &local_dead_tasks, tasks) { list_del(&task->tasks); - list_add_tail(&task->tasks, &dead_tasks); + free_task(task); } - - spin_unlock(&task_mortuary); } diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 026f671ea55..78193e4bbdb 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -52,7 +52,8 @@ int alloc_cpu_buffers(void) for_each_online_cpu(i) { struct oprofile_cpu_buffer * b = &cpu_buffer[i]; - b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size); + b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, + cpu_to_node(i)); if (!b->buffer) goto fail; diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index b8241561da4..a665951b158 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -34,7 +34,7 @@ config PARPORT config PARPORT_PC tristate "PC-style hardware" - depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R + depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 18e85ccdae6..9302b8fd746 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2371,8 +2371,10 @@ void parport_pc_unregister_port (struct parport *p) spin_lock(&ports_lock); list_del_init(&priv->list); spin_unlock(&ports_lock); +#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) if (p->dma != PARPORT_DMA_NONE) free_dma(p->dma); +#endif if (p->irq != PARPORT_IRQ_NONE) free_irq(p->irq, p); release_region(p->base, 3); @@ -2380,14 +2382,12 @@ void parport_pc_unregister_port (struct parport *p) release_region(p->base + 3, p->size - 3); if (p->modes & PARPORT_MODE_ECP) release_region(p->base_hi, 3); -#ifdef CONFIG_PARPORT_PC_FIFO -#ifdef HAS_DMA +#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) if (priv->dma_buf) pci_free_consistent(priv->dev, PAGE_SIZE, priv->dma_buf, priv->dma_handle); #endif -#endif kfree (p->private_data); parport_put_port(p); kfree (ops); /* hope no-one cached it */ diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 6a61b9f286e..0aac6a61337 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -32,6 +32,7 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/sched.h> /* signal_pending() */ #include <linux/pcieport_if.h> #include "pci_hotplug.h" diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 0b8b26beb16..ac1e495c314 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -30,6 +30,9 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> +#include <linux/signal.h> +#include <linux/jiffies.h> +#include <linux/timer.h> #include <linux/pci.h> #include <linux/interrupt.h> diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 4f7ed4bd3be..94e30fe4b8f 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -24,6 +24,8 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/slab.h> #include "rio.h" diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 30a11436e24..bef9316e95d 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -15,6 +15,7 @@ #include <linux/rio.h> #include <linux/rio_drv.h> #include <linux/stat.h> +#include <linux/sched.h> /* for capable() */ #include "rio.h" diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 3ca1011ceaa..5e382470faa 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -23,6 +23,7 @@ #include <linux/rio_regs.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/slab.h> #include "rio.h" diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f779f674dfa..2472fa1a1be 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -18,6 +18,7 @@ #include <linux/major.h> #include <linux/slab.h> #include <linux/buffer_head.h> +#include <linux/hdreg.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -1723,12 +1724,34 @@ dasd_release(struct inode *inp, struct file *filp) return 0; } +/* + * Return disk geometry. + */ +static int +dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct dasd_device *device; + + device = bdev->bd_disk->private_data; + if (!device) + return -ENODEV; + + if (!device->discipline || + !device->discipline->fill_geometry) + return -EINVAL; + + device->discipline->fill_geometry(device, geo); + geo->start = get_start_sect(bdev) >> device->s2b_shift; + return 0; +} + struct block_device_operations dasd_device_operations = { .owner = THIS_MODULE, .open = dasd_open, .release = dasd_release, .ioctl = dasd_ioctl, + .getgeo = dasd_getgeo, }; diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 044b7537199..8e4dcd58599 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -486,33 +486,6 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) } /* - * Return disk geometry. - */ -static int -dasd_ioctl_getgeo(struct block_device *bdev, int no, long args) -{ - struct hd_geometry geo = { 0, }; - struct dasd_device *device; - - device = bdev->bd_disk->private_data; - if (device == NULL) - return -ENODEV; - - if (device == NULL || device->discipline == NULL || - device->discipline->fill_geometry == NULL) - return -EINVAL; - - geo = (struct hd_geometry) {}; - device->discipline->fill_geometry(device, &geo); - geo.start = get_start_sect(bdev) >> device->s2b_shift; - if (copy_to_user((struct hd_geometry __user *) args, &geo, - sizeof (struct hd_geometry))) - return -EFAULT; - - return 0; -} - -/* * List of static ioctls. */ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] = @@ -528,7 +501,6 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] = { BIODASDPRRST, dasd_ioctl_reset_profile }, { BLKROSET, dasd_ioctl_set_ro }, { DASDAPIVER, dasd_ioctl_api_version }, - { HDIO_GETGEO, dasd_ioctl_getgeo }, { -1, NULL } }; diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index bf3a67c3cc5..54ecd548c31 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -328,31 +328,27 @@ fail: return 0; } -static int xpram_ioctl (struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct hd_geometry __user *geo; unsigned long size; - if (cmd != HDIO_GETGEO) - return -EINVAL; + /* * get geometry: we have to fake one... trim the size to a * multiple of 64 (32k): tell we have 16 sectors, 4 heads, * whatever cylinders. Tell also that data starts at sector. 4. */ - geo = (struct hd_geometry __user *) arg; size = (xpram_pages * 8) & ~0x3f; - put_user(size >> 6, &geo->cylinders); - put_user(4, &geo->heads); - put_user(16, &geo->sectors); - put_user(4, &geo->start); + geo->cylinders = size >> 6; + geo->heads = 4; + geo->sectors = 16; + geo->start = 4; return 0; } static struct block_device_operations xpram_devops = { .owner = THIS_MODULE, - .ioctl = xpram_ioctl, + .getgeo = xpram_getgeo, }; /* diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index c0cf52cb975..bbbb55eeb73 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -29,6 +29,12 @@ * NV-specific details such as register offsets, SATA phy location, * hotplug info, etc. * + * 0.10 + * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB + * drive. Also made the check_hotplug() callbacks return whether there + * was a hotplug interrupt or not. This was not the source of the + * spurious interrupts, but is the right thing to do anyway. + * * 0.09 * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. * @@ -124,10 +130,10 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void nv_host_stop (struct ata_host_set *host_set); static void nv_enable_hotplug(struct ata_probe_ent *probe_ent); static void nv_disable_hotplug(struct ata_host_set *host_set); -static void nv_check_hotplug(struct ata_host_set *host_set); +static int nv_check_hotplug(struct ata_host_set *host_set); static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent); static void nv_disable_hotplug_ck804(struct ata_host_set *host_set); -static void nv_check_hotplug_ck804(struct ata_host_set *host_set); +static int nv_check_hotplug_ck804(struct ata_host_set *host_set); enum nv_host_type { @@ -176,7 +182,7 @@ struct nv_host_desc enum nv_host_type host_type; void (*enable_hotplug)(struct ata_probe_ent *probe_ent); void (*disable_hotplug)(struct ata_host_set *host_set); - void (*check_hotplug)(struct ata_host_set *host_set); + int (*check_hotplug)(struct ata_host_set *host_set); }; static struct nv_host_desc nv_device_tbl[] = { @@ -309,12 +315,16 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) handled += ata_host_intr(ap, qc); + else + // No request pending? Clear interrupt status + // anyway, in case there's one pending. + ap->ops->check_status(ap); } } if (host->host_desc->check_hotplug) - host->host_desc->check_hotplug(host_set); + handled += host->host_desc->check_hotplug(host_set); spin_unlock_irqrestore(&host_set->lock, flags); @@ -497,7 +507,7 @@ static void nv_disable_hotplug(struct ata_host_set *host_set) outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); } -static void nv_check_hotplug(struct ata_host_set *host_set) +static int nv_check_hotplug(struct ata_host_set *host_set) { u8 intr_status; @@ -522,7 +532,11 @@ static void nv_check_hotplug(struct ata_host_set *host_set) if (intr_status & NV_INT_STATUS_SDEV_REMOVED) printk(KERN_WARNING "nv_sata: " "Secondary device removed\n"); + + return 1; } + + return 0; } static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent) @@ -560,7 +574,7 @@ static void nv_disable_hotplug_ck804(struct ata_host_set *host_set) pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); } -static void nv_check_hotplug_ck804(struct ata_host_set *host_set) +static int nv_check_hotplug_ck804(struct ata_host_set *host_set) { u8 intr_status; @@ -585,7 +599,11 @@ static void nv_check_hotplug_ck804(struct ata_host_set *host_set) if (intr_status & NV_INT_STATUS_SDEV_REMOVED) printk(KERN_WARNING "nv_sata: " "Secondary device removed\n"); + + return 1; } + + return 0; } static int __init nv_init(void) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 180676d7115..ee5f4dfdab1 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -69,7 +69,6 @@ #include "scsi_logging.h" static void scsi_done(struct scsi_cmnd *cmd); -static int scsi_retry_command(struct scsi_cmnd *cmd); /* * Definitions and constants. @@ -752,7 +751,7 @@ static void scsi_done(struct scsi_cmnd *cmd) * isn't running --- used by scsi_times_out */ void __scsi_done(struct scsi_cmnd *cmd) { - unsigned long flags; + struct request *rq = cmd->request; /* * Set the serial numbers back to zero @@ -763,71 +762,14 @@ void __scsi_done(struct scsi_cmnd *cmd) if (cmd->result) atomic_inc(&cmd->device->ioerr_cnt); + BUG_ON(!rq); + /* - * Next, enqueue the command into the done queue. - * It is a per-CPU queue, so we just disable local interrupts - * and need no spinlock. + * The uptodate/nbytes values don't matter, as we allow partial + * completes and thus will check this in the softirq callback */ - local_irq_save(flags); - list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q)); - raise_softirq_irqoff(SCSI_SOFTIRQ); - local_irq_restore(flags); -} - -/** - * scsi_softirq - Perform post-interrupt processing of finished SCSI commands. - * - * This is the consumer of the done queue. - * - * This is called with all interrupts enabled. This should reduce - * interrupt latency, stack depth, and reentrancy of the low-level - * drivers. - */ -static void scsi_softirq(struct softirq_action *h) -{ - int disposition; - LIST_HEAD(local_q); - - local_irq_disable(); - list_splice_init(&__get_cpu_var(scsi_done_q), &local_q); - local_irq_enable(); - - while (!list_empty(&local_q)) { - struct scsi_cmnd *cmd = list_entry(local_q.next, - struct scsi_cmnd, eh_entry); - /* The longest time any command should be outstanding is the - * per command timeout multiplied by the number of retries. - * - * For a typical command, this is 2.5 minutes */ - unsigned long wait_for - = cmd->allowed * cmd->timeout_per_command; - list_del_init(&cmd->eh_entry); - - disposition = scsi_decide_disposition(cmd); - if (disposition != SUCCESS && - time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { - sdev_printk(KERN_ERR, cmd->device, - "timing out command, waited %lus\n", - wait_for/HZ); - disposition = SUCCESS; - } - - scsi_log_completion(cmd, disposition); - switch (disposition) { - case SUCCESS: - scsi_finish_command(cmd); - break; - case NEEDS_RETRY: - scsi_retry_command(cmd); - break; - case ADD_TO_MLQUEUE: - scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); - break; - default: - if (!scsi_eh_scmd_add(cmd, 0)) - scsi_finish_command(cmd); - } - } + rq->completion_data = cmd; + blk_complete_request(rq); } /* @@ -840,7 +782,7 @@ static void scsi_softirq(struct softirq_action *h) * level drivers should not become re-entrant as a result of * this. */ -static int scsi_retry_command(struct scsi_cmnd *cmd) +int scsi_retry_command(struct scsi_cmnd *cmd) { /* * Restore the SCSI command state. @@ -1273,38 +1215,6 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery) } EXPORT_SYMBOL(scsi_device_cancel); -#ifdef CONFIG_HOTPLUG_CPU -static int scsi_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - int cpu = (unsigned long)hcpu; - - switch(action) { - case CPU_DEAD: - /* Drain scsi_done_q. */ - local_irq_disable(); - list_splice_init(&per_cpu(scsi_done_q, cpu), - &__get_cpu_var(scsi_done_q)); - raise_softirq_irqoff(SCSI_SOFTIRQ); - local_irq_enable(); - break; - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block __devinitdata scsi_cpu_nb = { - .notifier_call = scsi_cpu_notify, -}; - -#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb) -#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb) -#else -#define register_scsi_cpu() -#define unregister_scsi_cpu() -#endif /* CONFIG_HOTPLUG_CPU */ - MODULE_DESCRIPTION("SCSI core"); MODULE_LICENSE("GPL"); @@ -1338,8 +1248,6 @@ static int __init init_scsi(void) INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); devfs_mk_dir("scsi"); - open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); - register_scsi_cpu(); printk(KERN_NOTICE "SCSI subsystem initialized\n"); return 0; @@ -1367,7 +1275,6 @@ static void __exit exit_scsi(void) devfs_remove("scsi"); scsi_exit_procfs(); scsi_exit_queue(); - unregister_scsi_cpu(); } subsys_initcall(init_scsi); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ba93d6e66d4..00c9bf383e2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1493,6 +1493,41 @@ static void scsi_kill_request(struct request *req, request_queue_t *q) __scsi_done(cmd); } +static void scsi_softirq_done(struct request *rq) +{ + struct scsi_cmnd *cmd = rq->completion_data; + unsigned long wait_for = cmd->allowed * cmd->timeout_per_command; + int disposition; + + INIT_LIST_HEAD(&cmd->eh_entry); + + disposition = scsi_decide_disposition(cmd); + if (disposition != SUCCESS && + time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { + sdev_printk(KERN_ERR, cmd->device, + "timing out command, waited %lus\n", + wait_for/HZ); + disposition = SUCCESS; + } + + scsi_log_completion(cmd, disposition); + + switch (disposition) { + case SUCCESS: + scsi_finish_command(cmd); + break; + case NEEDS_RETRY: + scsi_retry_command(cmd); + break; + case ADD_TO_MLQUEUE: + scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); + break; + default: + if (!scsi_eh_scmd_add(cmd, 0)) + scsi_finish_command(cmd); + } +} + /* * Function: scsi_request_fn() * @@ -1667,6 +1702,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + blk_queue_softirq_done(q, scsi_softirq_done); if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index f04e7e11f57..14a6198cb8d 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -44,6 +44,7 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq); extern void __scsi_release_request(struct scsi_request *sreq); extern void __scsi_done(struct scsi_cmnd *cmd); +extern int scsi_retry_command(struct scsi_cmnd *cmd); #ifdef CONFIG_SCSI_LOGGING void scsi_log_send(struct scsi_cmnd *cmd); void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 32d4d8d7b9f..4c5127ed379 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -527,7 +527,7 @@ static int sd_release(struct inode *inode, struct file *filp) return 0; } -static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *loc) +static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); struct scsi_device *sdp = sdkp->device; @@ -545,15 +545,9 @@ static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user * else scsicam_bios_param(bdev, sdkp->capacity, diskinfo); - if (put_user(diskinfo[0], &loc->heads)) - return -EFAULT; - if (put_user(diskinfo[1], &loc->sectors)) - return -EFAULT; - if (put_user(diskinfo[2], &loc->cylinders)) - return -EFAULT; - if (put_user((unsigned)get_start_sect(bdev), - (unsigned long __user *)&loc->start)) - return -EFAULT; + geo->heads = diskinfo[0]; + geo->sectors = diskinfo[1]; + geo->cylinders = diskinfo[2]; return 0; } @@ -593,12 +587,6 @@ static int sd_ioctl(struct inode * inode, struct file * filp, if (!scsi_block_when_processing_errors(sdp) || !error) return error; - if (cmd == HDIO_GETGEO) { - if (!arg) - return -EINVAL; - return sd_hdio_getgeo(bdev, p); - } - /* * Send SCSI addressing ioctls directly to mid level, send other * ioctls to block level and then onto mid level if they can't be @@ -800,6 +788,7 @@ static struct block_device_operations sd_fops = { .open = sd_open, .release = sd_release, .ioctl = sd_ioctl, + .getgeo = sd_getgeo, #ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl, #endif diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index c44bbedec81..4ddc453023a 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -186,7 +186,7 @@ static void update_bus(struct dentry *bus) down(&bus->d_inode->i_sem); - list_for_each_entry(dev, &bus->d_subdirs, d_child) + list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) if (dev->d_inode) update_dev(dev); @@ -203,7 +203,7 @@ static void update_sb(struct super_block *sb) down(&root->d_inode->i_sem); - list_for_each_entry(bus, &root->d_subdirs, d_child) { + list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { if (bus->d_inode) { switch (S_IFMT & bus->d_inode->i_mode) { case S_IFDIR: @@ -319,7 +319,7 @@ static int usbfs_empty (struct dentry *dentry) spin_lock(&dcache_lock); list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_child); + struct dentry *de = list_entry(list, struct dentry, d_u.d_child); if (usbfs_positive(de)) { spin_unlock(&dcache_lock); return 0; diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index d9cf3b327d9..77cd6ac07e3 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -19,6 +19,7 @@ */ #include <linux/platform_device.h> +#include <linux/signal.h> #include <asm/mach-au1x00/au1000.h> diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 3959ccc8833..0020ed7a39d 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -17,6 +17,7 @@ */ #include <linux/platform_device.h> +#include <linux/signal.h> #include <asm/hardware.h> diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 2ec6a78bd65..b2a8dfa4887 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -15,6 +15,7 @@ */ #include <linux/platform_device.h> +#include <linux/signal.h> /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index cc8e3bf5001..3f04427c902 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1151,7 +1151,7 @@ config FB_VOODOO1 config FB_CYBLA tristate "Cyberblade/i1 support" - depends on FB && PCI + depends on FB && PCI && X86_32 && !64BIT select FB_CFB_IMAGEBLIT select VIDEO_SELECT ---help--- diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index a5d09e159cd..6ee449858a5 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !ARCH_VERSATILE + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 167de397e4b..12d9329d140 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -56,6 +56,8 @@ static DEFINE_SPINLOCK(vga_lock); static int cursor_size_lastfrom; static int cursor_size_lastto; +static u32 vgacon_xres; +static u32 vgacon_yres; static struct vgastate state; #define BLANK 0x0020 @@ -69,7 +71,7 @@ static struct vgastate state; * appear. */ #undef TRIDENT_GLITCH - +#define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */ /* * Interface used by the world */ @@ -325,6 +327,10 @@ static const char __init *vgacon_startup(void) vga_scan_lines = vga_video_font_height * vga_video_num_lines; } + + vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; + vgacon_yres = vga_scan_lines; + return display_desc; } @@ -503,10 +509,18 @@ static int vgacon_doresize(struct vc_data *c, { unsigned long flags; unsigned int scanlines = height * c->vc_font.height; - u8 scanlines_lo, r7, vsync_end, mode; + u8 scanlines_lo, r7, vsync_end, mode, max_scan; spin_lock_irqsave(&vga_lock, flags); + outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg); + max_scan = inb_p(vga_video_port_val); + + if (max_scan & 0x80) + scanlines <<= 1; + + vgacon_xres = width * VGA_FONTWIDTH; + vgacon_yres = height * c->vc_font.height; outb_p(VGA_CRTC_MODE, vga_video_port_reg); mode = inb_p(vga_video_port_val); @@ -551,6 +565,10 @@ static int vgacon_doresize(struct vc_data *c, static int vgacon_switch(struct vc_data *c) { + int x = c->vc_cols * VGA_FONTWIDTH; + int y = c->vc_rows * c->vc_font.height; + int rows = ORIG_VIDEO_LINES * vga_default_font_height/ + c->vc_font.height; /* * We need to save screen size here as it's the only way * we can spot the screen has been resized and we need to @@ -566,10 +584,11 @@ static int vgacon_switch(struct vc_data *c) scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); - if (!(vga_video_num_columns % 2) && - vga_video_num_columns <= ORIG_VIDEO_COLS && - vga_video_num_lines <= (ORIG_VIDEO_LINES * - vga_default_font_height) / c->vc_font.height) + + if ((vgacon_xres != x || vgacon_yres != y) && + (!(vga_video_num_columns % 2) && + vga_video_num_columns <= ORIG_VIDEO_COLS && + vga_video_num_lines <= rows)) vgacon_doresize(c, c->vc_cols, c->vc_rows); } @@ -993,7 +1012,8 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigne if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; - if (font->width != 8 || (charcount != 256 && charcount != 512)) + if (font->width != VGA_FONTWIDTH || + (charcount != 256 && charcount != 512)) return -EINVAL; rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512); @@ -1010,7 +1030,7 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; - font->width = 8; + font->width = VGA_FONTWIDTH; font->height = c->vc_font.height; font->charcount = vga_512_chars ? 512 : 256; if (!font->data) diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c index 03fbe83d71a..e9f5dee67e3 100644 --- a/drivers/video/cyblafb.c +++ b/drivers/video/cyblafb.c @@ -7,11 +7,12 @@ * tridentfb.c by Jani Monoses * see files above for further credits * - * TODO: - * */ #define CYBLAFB_DEBUG 0 +#define CYBLAFB_KD_GRAPHICS_QUIRK 1 + +#define CYBLAFB_PIXMAPSIZE 8192 #include <linux/config.h> #include <linux/module.h> @@ -22,7 +23,7 @@ #include <asm/types.h> #include <video/cyblafb.h> -#define VERSION "0.54" +#define VERSION "0.62" struct cyblafb_par { u32 pseudo_pal[16]; @@ -32,7 +33,9 @@ struct cyblafb_par { static struct fb_fix_screeninfo cyblafb_fix __devinitdata = { .id = "CyBla", .type = FB_TYPE_PACKED_PIXELS, + .xpanstep = 1, .ypanstep = 1, + .ywrapstep = 1, .visual = FB_VISUAL_PSEUDOCOLOR, .accel = FB_ACCEL_NONE, }; @@ -43,8 +46,9 @@ static int ref __devinitdata = 75; static int fp __devinitdata; static int crt __devinitdata; static int memsize __devinitdata; -static int vesafb __devinitdata; +static int basestride; +static int vesafb; static int nativex; static int center; static int stretch; @@ -52,26 +56,50 @@ static int pciwb = 1; static int pcirb = 1; static int pciwr = 1; static int pcirr = 1; +static int disabled; static int verbosity; static int displaytype; -static void __iomem * io_virt; // iospace virtual memory address - -module_param(mode,charp,0); -module_param(bpp,int,0); -module_param(ref,int,0); -module_param(fp,int,0); -module_param(crt,int,0); -module_param(nativex,int,0); -module_param(center,int,0); -module_param(stretch,int,0); -module_param(pciwb,int,0); -module_param(pcirb,int,0); -module_param(pciwr,int,0); -module_param(pcirr,int,0); -module_param(memsize,int,0); -module_param(verbosity,int,0); -module_param(vesafb,int,0); +static void __iomem *io_virt; // iospace virtual memory address + +module_param(mode, charp, 0); +module_param(bpp, int, 0); +module_param(ref, int, 0); +module_param(fp, int, 0); +module_param(crt, int, 0); +module_param(nativex, int, 0); +module_param(center, int, 0); +module_param(stretch, int, 0); +module_param(pciwb, int, 0); +module_param(pcirb, int, 0); +module_param(pciwr, int, 0); +module_param(pcirr, int, 0); +module_param(memsize, int, 0); +module_param(verbosity, int, 0); + +//========================================= +// +// Well, we have to fix the upper layers. +// Until this has been done, we work around +// the bugs. +// +//========================================= + +#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG) + if (disabled) { \ + printk("********\n");\ + dump_stack();\ + return val;\ + } + +#elif CYBLAFB_KD_GRAPHICS_QUIRK +#define KD_GRAPHICS_RETURN(val)\ + if (disabled) {\ + return val;\ + } +#else +#define KD_GRAPHICS_RETURN(val) +#endif //========================================= // @@ -79,10 +107,10 @@ module_param(vesafb,int,0); // //========================================= -#define out8(r,v) writeb(v,io_virt+r) -#define out32(r,v) writel(v,io_virt+r) -#define in8(r) readb(io_virt+r) -#define in32(r) readl(io_virt+r) +#define out8(r, v) writeb(v, io_virt + r) +#define out32(r, v) writel(v, io_virt + r) +#define in8(r) readb(io_virt + r) +#define in32(r) readl(io_virt + r) //====================================== // @@ -90,47 +118,47 @@ module_param(vesafb,int,0); // //====================================== -static inline unsigned char read3X4(int reg) +static inline u8 read3X4(u32 reg) { - out8(0x3D4,reg); + out8(0x3D4, reg); return in8(0x3D5); } -static inline unsigned char read3C4(int reg) +static inline u8 read3C4(u32 reg) { - out8(0x3C4,reg); + out8(0x3C4, reg); return in8(0x3C5); } -static inline unsigned char read3CE(int reg) +static inline u8 read3CE(u32 reg) { - out8(0x3CE,reg); + out8(0x3CE, reg); return in8(0x3CF); } -static inline void write3X4(int reg,unsigned char val) +static inline void write3X4(u32 reg, u8 val) { - out8(0x3D4,reg); - out8(0x3D5,val); + out8(0x3D4, reg); + out8(0x3D5, val); } -static inline void write3C4(int reg,unsigned char val) +static inline void write3C4(u32 reg, u8 val) { - out8(0x3C4,reg); - out8(0x3C5,val); + out8(0x3C4, reg); + out8(0x3C5, val); } -static inline void write3CE(int reg,unsigned char val) +static inline void write3CE(u32 reg, u8 val) { - out8(0x3CE,reg); - out8(0x3CF,val); + out8(0x3CE, reg); + out8(0x3CF, val); } -static inline void write3C0(int reg,unsigned char val) +static inline void write3C0(u32 reg, u8 val) { - in8(0x3DA); // read to reset index - out8(0x3C0,reg); - out8(0x3C0,val); + in8(0x3DA); // read to reset index + out8(0x3C0, reg); + out8(0x3C0, val); } //================================================= @@ -139,58 +167,62 @@ static inline void write3C0(int reg,unsigned char val) // //================================================= -static inline void enable_mmio(void) +static void enable_mmio(void) { - int tmp; + u8 tmp; - outb(0x0B,0x3C4); + outb(0x0B, 0x3C4); inb(0x3C5); // Set NEW mode - outb(SR0E,0x3C4); // write enable a lot of extended ports - outb(0x80,0x3C5); + outb(SR0E, 0x3C4); // write enable a lot of extended ports + outb(0x80, 0x3C5); - outb(SR11,0x3C4); // write enable those extended ports that - outb(0x87,0x3C5); // are not affected by SR0E_New + outb(SR11, 0x3C4); // write enable those extended ports that + outb(0x87, 0x3C5); // are not affected by SR0E_New - outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2 - tmp=inb(0x3d5) & 0xBF; - outb(CR1E,0x3d4); - outb(tmp,0x3d5); + outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2 + tmp = inb(0x3d5) & 0xBF; + outb(CR1E, 0x3d4); + outb(tmp, 0x3d5); - outb(CR39,0x3D4); - outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched + outb(CR39, 0x3D4); + outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio } //================================================= // // Set pixel clock VCLK1 -// - multipliers set elswhere -// - freq in units of 0.01 MHz +// - multipliers set elswhere +// - freq in units of 0.01 MHz +// +// Hardware bug: SR18 >= 250 is broken for the +// cyberblade/i1 // //================================================= static void set_vclk(struct cyblafb_par *par, int freq) { - u32 m,n,k; - int f,fi,d,di; - u8 lo=0,hi=0; + u32 m, n, k; + int f, fi, d, di; + u8 lo = 0, hi = 0; d = 2000; k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3; - for(m = 0;m<64;m++) - for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 ! - fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12); - if ((di = abs(fi - freq)) < d) { - d = di; - f = fi; - lo = (u8) n; - hi = (u8) ((k<<6) | m); + for (m = 0; m < 64; m++) + for (n = 0; n < 250; n++) { + fi = (int)(((5864727 * (n + 8)) / + ((m + 2) * (1 << k))) >> 12); + if ((di = abs(fi - freq)) < d) { + d = di; + f = fi; + lo = (u8) n; + hi = (u8) ((k << 6) | m); + } } - } - write3C4(SR19,hi); - write3C4(SR18,lo); - if(verbosity > 1) + write3C4(SR19, hi); + write3C4(SR18, lo); + if (verbosity > 0) output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n", - freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo); + freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo); } //================================================ @@ -199,83 +231,83 @@ static void set_vclk(struct cyblafb_par *par, int freq) // //================================================ -static void cyblafb_setup_GE(int pitch,int bpp) +static void cyblafb_setup_GE(int pitch, int bpp) { - int base = (pitch>>3)<<20; + KD_GRAPHICS_RETURN(); switch (bpp) { - case 8: base |= (0<<29); break; - case 15: base |= (5<<29); break; - case 16: base |= (1<<29); break; - case 24: - case 32: base |= (2<<29); break; + case 8: + basestride = ((pitch >> 3) << 20) | (0 << 29); + break; + case 15: + basestride = ((pitch >> 3) << 20) | (5 << 29); + break; + case 16: + basestride = ((pitch >> 3) << 20) | (1 << 29); + break; + case 24: + case 32: + basestride = ((pitch >> 3) << 20) | (2 << 29); + break; } - write3X4(CR36,0x90); // reset GE - write3X4(CR36,0x80); // enable GE - - out32(GE24,1<<7); // reset all GE pointers - out32(GE24,0); - - write3X4(CR2D,0x00); // GE Timinigs, no delays - - out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133 - out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133 - out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133 - out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133 - out32(GEC8,base); // Source Stride / Buffer Base 0, p 133 - out32(GECC,base); // Source Stride / Buffer Base 1, p 133 - out32(GED0,base); // Source Stride / Buffer Base 2, p 133 - out32(GED4,base); // Source Stride / Buffer Base 3, p 133 - out32(GE6C,0); // Pattern and Style, p 129, ok + write3X4(CR36, 0x90); // reset GE + write3X4(CR36, 0x80); // enable GE + out32(GE24, 1 << 7); // reset all GE pointers by toggling + out32(GE24, 0); // d7 of GE24 + write3X4(CR2D, 0x00); // GE Timinigs, no delays + out32(GE6C, 0); // Pattern and Style, p 129, ok } //===================================================================== // -// Although this is a .fb_sync function that could be enabled in -// cyblafb_ops, we do not include it there. We sync immediately before -// new GE operations to improve performance. +// Cyberblade specific syncing +// +// A timeout might be caused by disabled mmio. +// Cause: +// - bit CR39 & 1 == 0 upon return, X trident driver bug +// - kdm bug (KD_GRAPHICS not set on first switch) +// - kernel design flaw (it believes in the correctness +// of kdm/X +// First we try to sync ignoring that problem, as most of the +// time that will succeed immediately and the enable_mmio() +// would only degrade performance. // //===================================================================== static int cyblafb_sync(struct fb_info *info) { - int status, i=100000; - while( ((status=in32(GE20)) & 0xFA800000) && i != 0) + u32 status, i = 100000; + + KD_GRAPHICS_RETURN(0); + + while (((status = in32(GE20)) & 0xFe800000) && i != 0) i--; if (i == 0) { - // The timeout might be caused by disabled mmio. - // Cause: - // - bit CR39 & 1 == 0 upon return, X trident driver bug - // - kdm bug (KD_GRAPHICS not set on first switch) - // - kernel design flaw (it believes in the correctness - // of kdm/X - // So we make sure that mmio is enabled first ... enable_mmio(); -// show_trace(NULL,&status); - i=1000000; - while( ((status=in32(GE20)) & 0xFA800000) && i != 0) + i = 1000000; + while (((status = in32(GE20)) & 0xFA800000) && i != 0) i--; if (i == 0) { - output("GE Timeout, status: %x\n",status); - if(status & 0x80000000) + output("GE Timeout, status: %x\n", status); + if (status & 0x80000000) output("Bresenham Engine : Busy\n"); - if(status & 0x40000000) + if (status & 0x40000000) output("Setup Engine : Busy\n"); - if(status & 0x20000000) + if (status & 0x20000000) output("SP / DPE : Busy\n"); - if(status & 0x10000000) + if (status & 0x10000000) output("Memory Interface : Busy\n"); - if(status & 0x08000000) + if (status & 0x08000000) output("Com Lst Proc : Busy\n"); - if(status & 0x04000000) + if (status & 0x04000000) output("Block Write : Busy\n"); - if(status & 0x02000000) + if (status & 0x02000000) output("Command Buffer : Full\n"); - if(status & 0x01000000) + if (status & 0x01000000) output("RESERVED : Busy\n"); - if(status & 0x00800000) + if (status & 0x00800000) output("PCI Write Buffer : Busy\n"); cyblafb_setup_GE(info->var.xres, info->var.bits_per_pixel); @@ -291,142 +323,193 @@ static int cyblafb_sync(struct fb_info *info) // //============================== -static void cyblafb_fillrect(struct fb_info * info, - const struct fb_fillrect *fr) +static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr) { - int bpp = info->var.bits_per_pixel; - int col; + u32 bpp = info->var.bits_per_pixel, col, desty, height; + + KD_GRAPHICS_RETURN(); switch (bpp) { - default: - case 8: col = fr->color; - col |= col <<8; - col |= col <<16; - break; - case 16: col = ((u32 *)(info->pseudo_palette))[fr->color]; - col |= col <<16; - break; - case 32: col = ((u32 *)(info->pseudo_palette))[fr->color]; - break; + default: + case 8: + col = fr->color; + col |= col << 8; + col |= col << 16; + break; + case 16: + col = ((u32 *) (info->pseudo_palette))[fr->color]; + col |= col << 16; + break; + case 32: + col = ((u32 *) (info->pseudo_palette))[fr->color]; + break; } - cyblafb_sync(info); - - out32(GE60,col); - out32(GE48,fr->rop ? 0x66:ROP_S); - out32(GE44,0x20000000|1<<19|1<<4|2<<2); - out32(GE08,point(fr->dx,fr->dy)); - out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1)); - + desty = fr->dy; + height = fr->height; + while (height) { + out32(GEB8, basestride | ((desty * info->var.xres_virtual * + bpp) >> 6)); + out32(GE60, col); + out32(GE48, fr->rop ? 0x66 : ROP_S); + out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); + out32(GE08, point(fr->dx, 0)); + out32(GE0C, point(fr->dx + fr->width - 1, + height > 4096 ? 4095 : height - 1)); + if (likely(height <= 4096)) + return; + desty += 4096; + height -= 4096; + } } -//============================== +//================================================ // // Cyberblade specific copyarea // -//============================== +// This function silently assumes that it never +// will be called with width or height exceeding +// 4096. +// +//================================================ -static void cyblafb_copyarea(struct fb_info *info, - const struct fb_copyarea *ca) +static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) { - __u32 s1,s2,d1,d2; - int direction; + u32 s1, s2, d1, d2, direction; + + KD_GRAPHICS_RETURN(); + + s1 = point(ca->sx, 0); + s2 = point(ca->sx + ca->width - 1, ca->height - 1); + d1 = point(ca->dx, 0); + d2 = point(ca->dx + ca->width - 1, ca->height - 1); - s1 = point(ca->sx,ca->sy); - s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1); - d1 = point(ca->dx,ca->dy); - d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1); if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx))) direction = 0; else direction = 2; - cyblafb_sync(info); - - out32(GE44,0xa0000000|1<<19|1<<2|direction); - out32(GE00,direction?s2:s1); - out32(GE04,direction?s1:s2); - out32(GE08,direction?d2:d1); - out32(GE0C,direction?d1:d2); - + out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual * + info->var.bits_per_pixel) >> 6)); + out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual * + info->var.bits_per_pixel) >> 6)); + out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction); + out32(GE00, direction ? s2 : s1); + out32(GE04, direction ? s1 : s2); + out32(GE08, direction ? d2 : d1); + out32(GE0C, direction ? d1 : d2); } //======================================================================= // // Cyberblade specific imageblit // -// Accelerated for the most usual case, blitting 1-bit deep character -// character images. Everything else is passed to the generic imageblit. +// Accelerated for the most usual case, blitting 1 - bit deep +// character images. Everything else is passed to the generic imageblit +// unless it is so insane that it is better to printk an alert. +// +// Hardware bug: _Never_ blit across pixel column 2048, that will lock +// the system. We split those blit requests into three blitting +// operations. // //======================================================================= static void cyblafb_imageblit(struct fb_info *info, const struct fb_image *image) { - u32 fgcol, bgcol; + u32 *pd = (u32 *) image->data; + u32 bpp = info->var.bits_per_pixel; - int i; - int bpp = info->var.bits_per_pixel; - int index = 0; - int index_end=image->height * image->width / 8; - int width_dds=image->width / 32; - int width_dbs=image->width % 32; - - if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 || - image->width % 8 != 0 || image->width == 0 || image->height == 0) { - cfb_imageblit(info,image); + KD_GRAPHICS_RETURN(); + + // Used only for drawing the penguine (image->depth > 1) + if (image->depth != 1) { + cfb_imageblit(info, image); + return; + } + // That should never happen, but it would be fatal + if (image->width == 0 || image->height == 0) { + output("imageblit: width/height 0 detected\n"); return; } if (info->fix.visual == FB_VISUAL_TRUECOLOR || info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - fgcol = ((u32*)(info->pseudo_palette))[image->fg_color]; - bgcol = ((u32*)(info->pseudo_palette))[image->bg_color]; + fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color]; + bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color]; } else { fgcol = image->fg_color; bgcol = image->bg_color; } switch (bpp) { - case 8: - fgcol |= fgcol <<8; fgcol |= fgcol <<16; - bgcol |= bgcol <<8; bgcol |= bgcol <<16; - break; - case 16: - fgcol |= fgcol <<16; - bgcol |= bgcol <<16; - break; - default: - break; + case 8: + fgcol |= fgcol << 8; + bgcol |= bgcol << 8; + case 16: + fgcol |= fgcol << 16; + bgcol |= bgcol << 16; + default: + break; } - cyblafb_sync(info); - - out32(GE60,fgcol); - out32(GE64,bgcol); - out32(GE44,0xa0000000 | 1<<20 | 1<<19); - out32(GE08,point(image->dx,image->dy)); - out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1)); + out32(GEB8, basestride | ((image->dy * info->var.xres_virtual * + bpp) >> 6)); + out32(GE60, fgcol); + out32(GE64, bgcol); + + if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) { + u32 dds = ((image->width + 31) >> 5) * image->height; + out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); + out32(GE08, point(image->dx, 0)); + out32(GE0C, point(image->dx + image->width - 1, + image->height - 1)); + while (dds--) + out32(GE9C, *pd++); + } else { + int i, j; + u32 ddstotal = (image->width + 31) >> 5; + u32 ddsleft = (2048 - image->dx + 31) >> 5; + u32 skipleft = ddstotal - ddsleft; + + out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); + out32(GE08, point(image->dx, 0)); + out32(GE0C, point(2048 - 1, image->height - 1)); + for (i = 0; i < image->height; i++) { + for (j = 0; j < ddsleft; j++) + out32(GE9C, *pd++); + pd += skipleft; + } - while(index < index_end) { - const char *p = image->data + index; - for(i=0;i<width_dds;i++) { - out32(GE9C,*(u32*)p); - p+=4; - index+=4; + if (image->dx % 32) { + out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); + out32(GE08, point(2048, 0)); + if (image->width > ddsleft << 5) + out32(GE0C, point(image->dx + (ddsleft << 5) - + 1, image->height - 1)); + else + out32(GE0C, point(image->dx + image->width - 1, + image->height - 1)); + pd = ((u32 *) image->data) + ddstotal - skipleft - 1; + for (i = 0; i < image->height; i++) { + out32(GE9C, swab32(swab32(*pd) << ((32 - + (image->dx & 31)) & 31))); + pd += ddstotal; + } } - switch(width_dbs) { - case 0: break; - case 8: out32(GE9C,*(u8*)p); - index+=1; - break; - case 16: out32(GE9C,*(u16*)p); - index+=2; - break; - case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16); - index+=3; - break; + + if (skipleft) { + out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19); + out32(GE08, point(image->dx + (ddsleft << 5), 0)); + out32(GE0C, point(image->dx + image->width - 1, + image->height - 1)); + pd = (u32 *) image->data; + for (i = 0; i < image->height; i++) { + pd += ddsleft; + for (j = 0; j < skipleft; j++) + out32(GE9C, *pd++); + } } } } @@ -443,7 +526,6 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { int bpp = var->bits_per_pixel; - int s,t,maxvyres; // // we try to support 8, 16, 24 and 32 bpp modes, @@ -453,9 +535,9 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var, // (This is what tridentfb does ... will be changed in the future) // // - if ( bpp % 8 != 0 || bpp < 8 || bpp >32) + if (bpp % 8 != 0 || bpp < 8 || bpp > 32) bpp = 8; - if (bpp == 24 ) + if (bpp == 24) bpp = var->bits_per_pixel = 32; // @@ -472,65 +554,93 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var, return -EINVAL; // - // xres != xres_virtual is broken, fail if such an - // unusual mode is requested + // we do not allow vclk to exceed 230 MHz. If the requested + // vclk is too high, we default to 200 MHz // - if (var->xres != var->xres_virtual) - return -EINVAL; + if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000) + var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000; // - // we do not allow vclk to exceed 230 MHz + // enforce (h|v)sync_len limits // - if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000) - return -EINVAL; + var->hsync_len &= ~7; + if(var->hsync_len > 248) + var->hsync_len = 248; + + var->vsync_len &= 15; // - // calc max yres_virtual that would fit in memory - // and max yres_virtual that could be used for scrolling - // and use minimum of the results as maxvyres - // - // adjust vyres_virtual to maxvyres if necessary - // fail if requested yres is bigger than maxvyres + // Enforce horizontal and vertical hardware limits. + // 1600x1200 is mentioned as a maximum, but higher resolutions could + // work with slow refresh, small margins and short sync. // - s = (0x1fffff / (var->xres * bpp/8)) + var->yres; - t = info->fix.smem_len / (var->xres * bpp/8); - maxvyres = t < s ? t : s; - if (maxvyres < var->yres_virtual) - var->yres_virtual=maxvyres; - if (maxvyres < var->yres) + var->xres &= ~7; + + if (((var->xres + var->left_margin + var->right_margin + + var->hsync_len) > (bpp == 32 ? 2040 : 4088)) || + ((var->yres + var->upper_margin + var->lower_margin + + var->vsync_len) > 2047)) return -EINVAL; - switch (bpp) { - case 8: - var->red.offset = 0; - var->green.offset = 0; - var->blue.offset = 0; - var->red.length = 6; - var->green.length = 6; - var->blue.length = 6; - break; - case 16: - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - break; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - break; - default: + if ((var->xres > 1600) || (var->yres > 1200)) + output("Mode %dx%d exceeds documented limits.\n", + var->xres, var->yres); + // + // try to be smart about (x|y)res_virtual problems. + // + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + + if (bpp == 8 || bpp == 16) { + if (var->xres_virtual > 4088) + var->xres_virtual = 4088; + } else { + if (var->xres_virtual > 2040) + var->xres_virtual = 2040; + } + var->xres_virtual &= ~7; + while (var->xres_virtual * var->yres_virtual * bpp / 8 > + info->fix.smem_len) { + if (var->yres_virtual > var->yres) + var->yres_virtual--; + else if (var->xres_virtual > var->xres) + var->xres_virtual -= 8; + else return -EINVAL; } - return 0; + switch (bpp) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + default: + return -EINVAL; + } + return 0; } //===================================================================== @@ -543,23 +653,25 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var, // it, so it is also safe to be used here. BTW: datasheet CR0E on page // 90 really is CR1E, the real CRE is documented on page 72. // +// BUT: +// +// As of internal version 0.60 we do not use vga panning any longer. +// Vga panning did not allow us the use of all available video memory +// and thus prevented ywrap scrolling. We do use the "right view" +// register now. +// +// //===================================================================== static int cyblafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - unsigned int offset; + KD_GRAPHICS_RETURN(0); - offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; - - write3X4(CR0D,offset & 0xFF); - write3X4(CR0C,(offset & 0xFF00) >> 8); - write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11)); - write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17)); - write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15)); - + out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset * + var->xres_virtual)) * var->bits_per_pixel / 32)); return 0; } @@ -578,56 +690,96 @@ static void regdump(struct cyblafb_par *par) return; printk("\n"); - for(i=0; i<=0xff; i++) { - outb(i,0x3d4); - printk("CR%02x=%02x ",i,inb(0x3d5)); - if (i%16==15) + for (i = 0; i <= 0xff; i++) { + outb(i, 0x3d4); + printk("CR%02x=%02x ", i, inb(0x3d5)); + if (i % 16 == 15) printk("\n"); } - outb(0x30,0x3ce); - outb(inb(0x3cf) | 0x40,0x3cf); - for(i=0; i<=0x1f; i++) { - if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) { - outb(i,0x3d4); - printk("CR%02x=%02x ",i,inb(0x3d5)); + outb(0x30, 0x3ce); + outb(inb(0x3cf) | 0x40, 0x3cf); + for (i = 0; i <= 0x1f; i++) { + if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11 + || i == 0x16) { + outb(i, 0x3d4); + printk("CR%02x=%02x ", i, inb(0x3d5)); } else printk("------- "); - if (i%16==15) + if (i % 16 == 15) printk("\n"); } - outb(0x30,0x3ce); - outb(inb(0x3cf) & 0xbf,0x3cf); + outb(0x30, 0x3ce); + outb(inb(0x3cf) & 0xbf, 0x3cf); printk("\n"); - for(i=0; i<=0x7f; i++) { - outb(i,0x3ce); - printk("GR%02x=%02x ",i,inb(0x3cf)); - if (i%16==15) + for (i = 0; i <= 0x7f; i++) { + outb(i, 0x3ce); + printk("GR%02x=%02x ", i, inb(0x3cf)); + if (i % 16 == 15) printk("\n"); } printk("\n"); - for(i=0; i<=0xff; i++) { - outb(i,0x3c4); - printk("SR%02x=%02x ",i,inb(0x3c5)); - if (i%16==15) + for (i = 0; i <= 0xff; i++) { + outb(i, 0x3c4); + printk("SR%02x=%02x ", i, inb(0x3c5)); + if (i % 16 == 15) printk("\n"); } printk("\n"); - for(i=0; i <= 0x1F; i++) { - inb(0x3da); // next access is index! - outb(i,0x3c0); - printk("AR%02x=%02x ",i,inb(0x3c1)); - if (i%16==15) + for (i = 0; i <= 0x1F; i++) { + inb(0x3da); // next access is index! + outb(i, 0x3c0); + printk("AR%02x=%02x ", i, inb(0x3c1)); + if (i % 16 == 15) printk("\n"); } printk("\n"); - inb(0x3DA); // reset internal flag to 3c0 index - outb(0x20,0x3C0); // enable attr + inb(0x3DA); // reset internal flag to 3c0 index + outb(0x20, 0x3C0); // enable attr + + return; +} + +//======================================================================= +// +// Save State +// +// This function is called while a switch to KD_TEXT is in progress, +// before any of the other functions are called. +// +//======================================================================= +static void cyblafb_save_state(struct fb_info *info) +{ + struct cyblafb_par *par = info->par; + if (verbosity > 0) + output("Switching to KD_TEXT\n"); + disabled = 0; + regdump(par); + enable_mmio(); + return; +} + +//======================================================================= +// +// Restore State +// +// This function is called while a switch to KD_GRAPHICS is in progress, +// We have to turn on vga style panning registers again because the +// trident driver of X does not know about GE10. +// +//======================================================================= + +static void cyblafb_restore_state(struct fb_info *info) +{ + if (verbosity > 0) + output("Switching to KD_GRAPHICS\n"); + out32(GE10, 0); + disabled = 1; return; } @@ -640,32 +792,34 @@ static void regdump(struct cyblafb_par *par) static int cyblafb_set_par(struct fb_info *info) { struct cyblafb_par *par = info->par; - u32 - htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch, - vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend; + u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, + hblankend, preendfetch, vtotal, vdispend, vsyncstart, + vsyncend, vblankstart, vblankend; struct fb_var_screeninfo *var = &info->var; int bpp = var->bits_per_pixel; int i; + KD_GRAPHICS_RETURN(0); + if (verbosity > 0) output("Switching to new mode: " "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n", - var->xres,var->yres,var->xres_virtual, - var->yres_virtual,var->bits_per_pixel,var->pixclock, - var->left_margin,var->right_margin,var->upper_margin, - var->lower_margin,var->hsync_len,var->vsync_len); + var->xres, var->yres, var->xres_virtual, + var->yres_virtual, var->bits_per_pixel, var->pixclock, + var->left_margin, var->right_margin, var->upper_margin, + var->lower_margin, var->hsync_len, var->vsync_len); htotal = (var->xres + var->left_margin + var->right_margin + - var->hsync_len) / 8 - 5; - hdispend = var->xres/8 - 1; - hsyncstart = (var->xres + var->right_margin)/8; - hsyncend = var->hsync_len/8; + var->hsync_len) / 8 - 5; + hdispend = var->xres / 8 - 1; + hsyncstart = (var->xres + var->right_margin) / 8; + hsyncend = var->hsync_len / 8; hblankstart = hdispend + 1; hblankend = htotal + 3; // should be htotal + 5, bios does it this way - preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3); + preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3); vtotal = var->yres + var->upper_margin + var->lower_margin + - var->vsync_len - 2; + var->vsync_len - 2; vdispend = var->yres - 1; vsyncstart = var->yres + var->lower_margin; vblankstart = var->yres; @@ -674,101 +828,99 @@ static int cyblafb_set_par(struct fb_info *info) enable_mmio(); // necessary! ... check X ... - write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07 + write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07 - write3CE(GR30,8); + write3CE(GR30, 8); if ((displaytype == DISPLAY_FP) && var->xres < nativex) { // stretch or center ? - out8(0x3C2,0xEB); + out8(0x3C2, 0xEB); - write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on + write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on if (center) { - write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80); - write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80); - } - else if (stretch) { - write3CE(GR5D,0); - write3CE(GR52,(read3CE(GR52) & 0x7C) | 1); - write3CE(GR53,(read3CE(GR53) & 0x7C) | 1); + write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80); + write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80); + } else if (stretch) { + write3CE(GR5D, 0); + write3CE(GR52, (read3CE(GR52) & 0x7C) | 1); + write3CE(GR53, (read3CE(GR53) & 0x7C) | 1); } } else { - out8(0x3C2,0x2B); - write3CE(GR30,8); + out8(0x3C2, 0x2B); + write3CE(GR30, 8); } // // Setup CRxx regs // - write3X4(CR00,htotal & 0xFF); - write3X4(CR01,hdispend & 0xFF); - write3X4(CR02,hblankstart & 0xFF); - write3X4(CR03,hblankend & 0x1F); - write3X4(CR04,hsyncstart & 0xFF); - write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2)); - write3X4(CR06,vtotal & 0xFF); - write3X4(CR07,(vtotal & 0x100) >> 8 | - (vdispend & 0x100) >> 7 | - (vsyncstart & 0x100) >> 6 | - (vblankstart & 0x100) >> 5 | - 0x10 | - (vtotal & 0x200) >> 4 | - (vdispend & 0x200) >> 3 | - (vsyncstart & 0x200) >> 2); - write3X4(CR08,0); - write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!! - ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0)); - write3X4(CR0A,0); // Init to some reasonable default - write3X4(CR0B,0); // Init to some reasonable default - write3X4(CR0C,0); // Offset 0 - write3X4(CR0D,0); // Offset 0 - write3X4(CR0E,0); // Init to some reasonable default - write3X4(CR0F,0); // Init to some reasonable default - write3X4(CR10,vsyncstart & 0xFF); - write3X4(CR11,(vsyncend & 0x0F)); - write3X4(CR12,vdispend & 0xFF); - write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF); - write3X4(CR14,0x40); // double word mode - write3X4(CR15,vblankstart & 0xFF); - write3X4(CR16,vblankend & 0xFF); - write3X4(CR17,0xC3); - write3X4(CR18,0xFF); + write3X4(CR00, htotal & 0xFF); + write3X4(CR01, hdispend & 0xFF); + write3X4(CR02, hblankstart & 0xFF); + write3X4(CR03, hblankend & 0x1F); + write3X4(CR04, hsyncstart & 0xFF); + write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); + write3X4(CR06, vtotal & 0xFF); + write3X4(CR07, (vtotal & 0x100) >> 8 | + (vdispend & 0x100) >> 7 | + (vsyncstart & 0x100) >> 6 | + (vblankstart & 0x100) >> 5 | + 0x10 | + (vtotal & 0x200) >> 4 | + (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2); + write3X4(CR08, 0); + write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!! + ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0)); + write3X4(CR0A, 0); // Init to some reasonable default + write3X4(CR0B, 0); // Init to some reasonable default + write3X4(CR0C, 0); // Offset 0 + write3X4(CR0D, 0); // Offset 0 + write3X4(CR0E, 0); // Init to some reasonable default + write3X4(CR0F, 0); // Init to some reasonable default + write3X4(CR10, vsyncstart & 0xFF); + write3X4(CR11, (vsyncend & 0x0F)); + write3X4(CR12, vdispend & 0xFF); + write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF); + write3X4(CR14, 0x40); // double word mode + write3X4(CR15, vblankstart & 0xFF); + write3X4(CR16, vblankend & 0xFF); + write3X4(CR17, 0xE3); + write3X4(CR18, 0xFF); // CR19: needed for interlaced modes ... ignore it for now - write3X4(CR1A,0x07); // Arbitration Control Counter 1 - write3X4(CR1B,0x07); // Arbitration Control Counter 2 - write3X4(CR1C,0x07); // Arbitration Control Counter 3 - write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-) - write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80); + write3X4(CR1A, 0x07); // Arbitration Control Counter 1 + write3X4(CR1B, 0x07); // Arbitration Control Counter 2 + write3X4(CR1C, 0x07); // Arbitration Control Counter 3 + write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -) + write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80); // CR1F: do not set, contains BIOS info about memsize - write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode - write3X4(CR21,0x20); // enable linear memory access + write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode + write3X4(CR21, 0x20); // enable linear memory access // CR22: RO cpu latch readback // CR23: ??? // CR24: RO AR flag state // CR25: RAMDAC rw timing, pclk buffer tristate control ???? // CR26: ??? - write3X4(CR27,(vdispend & 0x400) >> 6 | - (vsyncstart & 0x400) >> 5 | - (vblankstart & 0x400) >> 4 | - (vtotal & 0x400) >> 3 | - 0x8); + write3X4(CR27, (vdispend & 0x400) >> 6 | + (vsyncstart & 0x400) >> 5 | + (vblankstart & 0x400) >> 4 | + (vtotal & 0x400) >> 3 | + 0x8); // CR28: ??? - write3X4(CR29,(read3X4(CR29) & 0xCF) | - ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4)); - write3X4(CR2A,read3X4(CR2A) | 0x40); - write3X4(CR2B,(htotal & 0x100) >> 8 | - (hdispend & 0x100) >> 7 | - // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ??? - (hsyncstart & 0x100) >> 5 | - (hblankstart & 0x100) >> 4); + write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual * + bpp) / (4 * 16)) & 0x300) >> 4)); + write3X4(CR2A, read3X4(CR2A) | 0x40); + write3X4(CR2B, (htotal & 0x100) >> 8 | + (hdispend & 0x100) >> 7 | + // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ??? + (hsyncstart & 0x100) >> 5 | + (hblankstart & 0x100) >> 4); // CR2C: ??? // CR2D: initialized in cyblafb_setup_GE() - write3X4(CR2F,0x92); // conservative, better signal quality + write3X4(CR2F, 0x92); // conservative, better signal quality // CR30: reserved // CR31: reserved // CR32: reserved @@ -777,96 +929,116 @@ static int cyblafb_set_par(struct fb_info *info) // CR35: disabled in CR36 // CR36: initialized in cyblafb_setup_GE // CR37: i2c, ignore for now - write3X4(CR38,(bpp == 8) ? 0x00 : // - (bpp == 16) ? 0x05 : // highcolor - (bpp == 24) ? 0x29 : // packed 24bit truecolor - (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus - write3X4(CR39,0x01 | // MMIO enable - (pcirb ? 0x02 : 0) | // pci read burst enable - (pciwb ? 0x04 : 0)); // pci write burst enable - write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase - (pcirr ? 0x40 : 0) | // pci read retry enable - (pciwr ? 0x80 : 0)); // pci write retry enable - write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0); - write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0); - write3X4(CR58,0x82); // Bios does this .... don't know more + write3X4(CR38, (bpp == 8) ? 0x00 : // + (bpp == 16) ? 0x05 : // highcolor + (bpp == 24) ? 0x29 : // packed 24bit truecolor + (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus + write3X4(CR39, 0x01 | // MMIO enable + (pcirb ? 0x02 : 0) | // pci read burst enable + (pciwb ? 0x04 : 0)); // pci write burst enable + write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase + (pcirr ? 0x40 : 0) | // pci read retry enable + (pciwr ? 0x80 : 0)); // pci write retry enable + write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2 + : 0); + write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0); + write3X4(CR58, 0x82); // Bios does this .... don't know more // // Setup SRxx regs // - write3C4(SR00,3); - write3C4(SR01,1); //set char clock 8 dots wide - write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode - write3C4(SR03,0); //no character map select - write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4 + write3C4(SR00, 3); + write3C4(SR01, 1); //set char clock 8 dots wide + write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode + write3C4(SR03, 0); //no character map select + write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4 - out8(0x3C4,0x0b); + out8(0x3C4, 0x0b); in8(0x3C5); // Set NEW mode - write3C4(SR0D,0x00); // test ... check + write3C4(SR0D, 0x00); // test ... check - set_vclk(par,(bpp==32 ? 200000000 : 100000000)/ - info->var.pixclock); //SR18,SR19 + set_vclk(par, (bpp == 32 ? 200000000 : 100000000) + / info->var.pixclock); //SR18, SR19 // // Setup GRxx regs // - write3CE(GR00,0x00); // test ... check - write3CE(GR01,0x00); // test ... check - write3CE(GR02,0x00); // test ... check - write3CE(GR03,0x00); // test ... check - write3CE(GR04,0x00); // test ... check - write3CE(GR05,0x40); // no CGA compat,allow 256 col - write3CE(GR06,0x05); // graphics mode - write3CE(GR07,0x0F); // planes? - write3CE(GR08,0xFF); // test ... check - write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4 - write3CE(GR20,0xC0); // test ... check - write3CE(GR2F,0xA0); // PCLK = VCLK, no skew, + write3CE(GR00, 0x00); // test ... check + write3CE(GR01, 0x00); // test ... check + write3CE(GR02, 0x00); // test ... check + write3CE(GR03, 0x00); // test ... check + write3CE(GR04, 0x00); // test ... check + write3CE(GR05, 0x40); // no CGA compat, allow 256 col + write3CE(GR06, 0x05); // graphics mode + write3CE(GR07, 0x0F); // planes? + write3CE(GR08, 0xFF); // test ... check + write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4 + write3CE(GR20, 0xC0); // test ... check + write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew, // // Setup ARxx regs // - for(i = 0;i < 0x10;i++) // set AR00 .. AR0f - write3C0(i,i); - write3C0(AR10,0x41); // graphics mode and support 256 color modes - write3C0(AR12,0x0F); // planes - write3C0(AR13,0); // horizontal pel panning + for (i = 0; i < 0x10; i++) // set AR00 .. AR0f + write3C0(i, i); + write3C0(AR10, 0x41); // graphics mode and support 256 color modes + write3C0(AR12, 0x0F); // planes + write3C0(AR13, 0); // horizontal pel panning in8(0x3DA); // reset internal flag to 3c0 index - out8(0x3C0,0x20); // enable attr + out8(0x3C0, 0x20); // enable attr // // Setup hidden RAMDAC command register // - in8(0x3C8); // these reads are - in8(0x3C6); // necessary to - in8(0x3C6); // unmask the RAMDAC - in8(0x3C6); // command reg, otherwise - in8(0x3C6); // we would write the pixelmask reg! - out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors - (bpp == 15) ? 0x10 : // - (bpp == 16) ? 0x30 : // hicolor - (bpp == 24) ? 0xD0 : // truecolor - (bpp == 32) ? 0xD0 : 0); // truecolor + in8(0x3C8); // these reads are + in8(0x3C6); // necessary to + in8(0x3C6); // unmask the RAMDAC + in8(0x3C6); // command reg, otherwise + in8(0x3C6); // we would write the pixelmask reg! + out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors + (bpp == 15) ? 0x10 : // + (bpp == 16) ? 0x30 : // hicolor + (bpp == 24) ? 0xD0 : // truecolor + (bpp == 32) ? 0xD0 : 0); // truecolor in8(0x3C8); // // GR31 is not mentioned in the datasheet // if (displaytype == DISPLAY_FP) - write3CE(GR31,(read3CE(GR31) & 0x8F) | + write3CE(GR31, (read3CE(GR31) & 0x8F) | ((info->var.yres > 1024) ? 0x50 : - (info->var.yres > 768) ? 0x30 : - (info->var.yres > 600) ? 0x20 : - (info->var.yres > 480) ? 0x10 : 0)); + (info->var.yres > 768) ? 0x30 : + (info->var.yres > 600) ? 0x20 : + (info->var.yres > 480) ? 0x10 : 0)); info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = info->var.xres * (bpp >> 3); - info->cmap.len = (bpp == 8) ? 256: 16; + info->fix.line_length = info->var.xres_virtual * (bpp >> 3); + info->cmap.len = (bpp == 8) ? 256 : 16; // // init acceleration engine // - cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel); + cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel); + + // + // Set/clear flags to allow proper scroll mode selection. + // + if (var->xres == var->xres_virtual) + info->flags &= ~FBINFO_HWACCEL_XPAN; + else + info->flags |= FBINFO_HWACCEL_XPAN; + + if (var->yres == var->yres_virtual) + info->flags &= ~FBINFO_HWACCEL_YPAN; + else + info->flags |= FBINFO_HWACCEL_YPAN; + + if (info->fix.smem_len != + var->xres_virtual * var->yres_virtual * bpp / 8) + info->flags &= ~FBINFO_HWACCEL_YWRAP; + else + info->flags |= FBINFO_HWACCEL_YWRAP; regdump(par); @@ -885,27 +1057,27 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, { int bpp = info->var.bits_per_pixel; + KD_GRAPHICS_RETURN(0); + if (regno >= info->cmap.len) return 1; if (bpp == 8) { - out8(0x3C6,0xFF); - out8(0x3C8,regno); - out8(0x3C9,red>>10); - out8(0x3C9,green>>10); - out8(0x3C9,blue>>10); - - } else if (bpp == 16) // RGB 565 - ((u32*)info->pseudo_palette)[regno] = - (red & 0xF800) | - ((green & 0xFC00) >> 5) | - ((blue & 0xF800) >> 11); - else if (bpp == 32) // ARGB 8888 - ((u32*)info->pseudo_palette)[regno] = - ((transp & 0xFF00) <<16) | - ((red & 0xFF00) << 8) | - ((green & 0xFF00)) | - ((blue & 0xFF00)>>8); + out8(0x3C6, 0xFF); + out8(0x3C8, regno); + out8(0x3C9, red >> 10); + out8(0x3C9, green >> 10); + out8(0x3C9, blue >> 10); + + } else if (bpp == 16) // RGB 565 + ((u32 *) info->pseudo_palette)[regno] = + (red & 0xF800) | + ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); + else if (bpp == 32) // ARGB 8888 + ((u32 *) info->pseudo_palette)[regno] = + ((transp & 0xFF00) << 16) | + ((red & 0xFF00) << 8) | + ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); return 0; } @@ -918,40 +1090,41 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, static int cyblafb_blank(int blank_mode, struct fb_info *info) { - unsigned char PMCont,DPMSCont; + unsigned char PMCont, DPMSCont; + + KD_GRAPHICS_RETURN(0); if (displaytype == DISPLAY_FP) return 0; - out8(0x83C8,0x04); // DPMS Control + out8(0x83C8, 0x04); // DPMS Control PMCont = in8(0x83C6) & 0xFC; DPMSCont = read3CE(GR23) & 0xFC; - switch (blank_mode) - { - case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On - case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On + switch (blank_mode) { + case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On + case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On PMCont |= 0x03; DPMSCont |= 0x00; break; - case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On + case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On PMCont |= 0x02; DPMSCont |= 0x01; break; - case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off + case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off PMCont |= 0x02; DPMSCont |= 0x02; break; - case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off + case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off PMCont |= 0x00; DPMSCont |= 0x03; break; } - write3CE(GR23,DPMSCont); - out8(0x83C8,4); - out8(0x83C6,PMCont); + write3CE(GR23, DPMSCont); + out8(0x83C8, 4); + out8(0x83C6, PMCont); // // let fbcon do a softblank for us // @@ -959,15 +1132,18 @@ static int cyblafb_blank(int blank_mode, struct fb_info *info) } static struct fb_ops cyblafb_ops __devinitdata = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .fb_setcolreg = cyblafb_setcolreg, .fb_pan_display = cyblafb_pan_display, .fb_blank = cyblafb_blank, .fb_check_var = cyblafb_check_var, .fb_set_par = cyblafb_set_par, .fb_fillrect = cyblafb_fillrect, - .fb_copyarea= cyblafb_copyarea, + .fb_copyarea = cyblafb_copyarea, .fb_imageblit = cyblafb_imageblit, + .fb_sync = cyblafb_sync, + .fb_restore_state = cyblafb_restore_state, + .fb_save_state = cyblafb_save_state, }; //========================================================================== @@ -986,74 +1162,89 @@ static struct fb_ops cyblafb_ops __devinitdata = { static int __devinit getstartupmode(struct fb_info *info) { - u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend, - vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend, - cr00,cr01,cr02,cr03,cr04,cr05,cr2b, - cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27, - cr38, - sr0d,sr18,sr19, - gr0f, - fi,pxclkdiv,vclkdiv,tmp,i; + u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend, + vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend, + cr00, cr01, cr02, cr03, cr04, cr05, cr2b, + cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27, + cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i; struct modus { - int xres; int yres; int vyres; int bpp; int pxclk; - int left_margin; int right_margin; int upper_margin; - int lower_margin; int hsync_len; int vsync_len; - } modedb[5] = { - { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0}, - { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3}, - { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11}, - {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3}, - {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3} + int xres; int vxres; int yres; int vyres; + int bpp; int pxclk; + int left_margin; int right_margin; + int upper_margin; int lower_margin; + int hsync_len; int vsync_len; + } modedb[5] = { + { + 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, { + 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, { + 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, { + 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, { + 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3} }; - outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5); - outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5); - outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5); - outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5); - outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5); - outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5); - outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5); - outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5); - outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5); - outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5); - outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf); - - htotal = cr00 | (cr2b & 0x01) << 8; - hdispend = cr01 | (cr2b & 0x02) << 7; + outb(0x00, 0x3d4); cr00 = inb(0x3d5); + outb(0x01, 0x3d4); cr01 = inb(0x3d5); + outb(0x02, 0x3d4); cr02 = inb(0x3d5); + outb(0x03, 0x3d4); cr03 = inb(0x3d5); + outb(0x04, 0x3d4); cr04 = inb(0x3d5); + outb(0x05, 0x3d4); cr05 = inb(0x3d5); + outb(0x06, 0x3d4); cr06 = inb(0x3d5); + outb(0x07, 0x3d4); cr07 = inb(0x3d5); + outb(0x09, 0x3d4); cr09 = inb(0x3d5); + outb(0x10, 0x3d4); cr10 = inb(0x3d5); + outb(0x11, 0x3d4); cr11 = inb(0x3d5); + outb(0x12, 0x3d4); cr12 = inb(0x3d5); + outb(0x15, 0x3d4); cr15 = inb(0x3d5); + outb(0x16, 0x3d4); cr16 = inb(0x3d5); + outb(0x27, 0x3d4); cr27 = inb(0x3d5); + outb(0x2b, 0x3d4); cr2b = inb(0x3d5); + outb(0x38, 0x3d4); cr38 = inb(0x3d5); + + outb(0x0b, 0x3c4); + inb(0x3c5); + + outb(0x0d, 0x3c4); sr0d = inb(0x3c5); + outb(0x18, 0x3c4); sr18 = inb(0x3c5); + outb(0x19, 0x3c4); sr19 = inb(0x3c5); + outb(0x0f, 0x3ce); gr0f = inb(0x3cf); + + htotal = cr00 | (cr2b & 0x01) << 8; + hdispend = cr01 | (cr2b & 0x02) << 7; hblankstart = cr02 | (cr2b & 0x10) << 4; - hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2; - hsyncstart = cr04 | (cr2b & 0x08) << 5; - hsyncend = cr05 & 0x1f; + hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2; + hsyncstart = cr04 | (cr2b & 0x08) << 5; + hsyncend = cr05 & 0x1f; modedb[0].xres = hblankstart * 8; modedb[0].hsync_len = hsyncend * 8; modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres; modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres - - modedb[0].right_margin - modedb[0].hsync_len; - - vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4 - | (cr27 & 0x80) << 3; - vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3 - | (cr27 & 0x10) << 6; - vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2 - | (cr27 & 0x20) << 5; - vsyncend = cr11 & 0x0f; + modedb[0].right_margin - modedb[0].hsync_len; + + vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4 + | (cr27 & 0x80) << 3; + vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3 + | (cr27 & 0x10) << 6; + vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2 + | (cr27 & 0x20) << 5; + vsyncend = cr11 & 0x0f; vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4 - | (cr27 & 0x40) << 4; - vblankend = cr16; + | (cr27 & 0x40) << 4; + vblankend = cr16; - modedb[0].yres = vdispend + 1; - modedb[0].vsync_len = vsyncend; + modedb[0].yres = vdispend + 1; + modedb[0].vsync_len = vsyncend; modedb[0].lower_margin = vsyncstart - modedb[0].yres; modedb[0].upper_margin = vtotal - modedb[0].yres - - modedb[0].lower_margin - modedb[0].vsync_len + 2; + modedb[0].lower_margin - modedb[0].vsync_len + 2; tmp = cr38 & 0x3c; modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 : - tmp == 8 ? 32 : 8; + tmp == 8 ? 32 : 8; - fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12; + fi = ((5864727 * (sr18 + 8)) / + (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12; pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1; tmp = sr0d & 0x06; vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 ! @@ -1062,10 +1253,10 @@ static int __devinit getstartupmode(struct fb_info *info) if (verbosity > 0) output("detected startup mode: " "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n", - modedb[0].xres,modedb[0].yres,modedb[0].xres, - modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin, - modedb[0].right_margin,modedb[0].upper_margin, - modedb[0].lower_margin,modedb[0].hsync_len, + modedb[0].xres, modedb[0].yres, modedb[0].xres, + modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin, + modedb[0].right_margin, modedb[0].upper_margin, + modedb[0].lower_margin, modedb[0].hsync_len, modedb[0].vsync_len); // @@ -1073,36 +1264,39 @@ static int __devinit getstartupmode(struct fb_info *info) // do not want to do it in another way! // - tryagain: + tryagain: i = (mode == NULL) ? 0 : - !strncmp(mode,"640x480",7) ? 1 : - !strncmp(mode,"800x600",7) ? 2 : - !strncmp(mode,"1024x768",8) ? 3 : - !strncmp(mode,"1280x1024",9) ? 4 : 0; + !strncmp(mode, "640x480", 7) ? 1 : + !strncmp(mode, "800x600", 7) ? 2 : + !strncmp(mode, "1024x768", 8) ? 3 : + !strncmp(mode, "1280x1024", 9) ? 4 : 0; ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref; - if(i==0) { + if (i == 0) { info->var.pixclock = modedb[i].pxclk; info->var.bits_per_pixel = modedb[i].bpp; } else { info->var.pixclock = (100000000 / - ((modedb[i].left_margin + modedb[i].xres + - modedb[i].right_margin + modedb[i].hsync_len - ) * ( - modedb[i].upper_margin + modedb[i].yres + - modedb[i].lower_margin + modedb[i].vsync_len - ) * - ref / 10000 - )); + ((modedb[i].left_margin + + modedb[i].xres + + modedb[i].right_margin + + modedb[i].hsync_len) * + (modedb[i].upper_margin + + modedb[i].yres + + modedb[i].lower_margin + + modedb[i].vsync_len) * ref / 10000)); info->var.bits_per_pixel = bpp; } info->var.left_margin = modedb[i].left_margin; info->var.right_margin = modedb[i].right_margin; info->var.xres = modedb[i].xres; - info->var.xres_virtual = modedb[i].xres; + if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32)) + info->var.xres_virtual = modedb[i].vxres; + else + info->var.xres_virtual = modedb[i].xres; info->var.xoffset = 0; info->var.hsync_len = modedb[i].hsync_len; info->var.upper_margin = modedb[i].upper_margin; @@ -1114,33 +1308,32 @@ static int __devinit getstartupmode(struct fb_info *info) info->var.sync = 0; info->var.vmode = FB_VMODE_NONINTERLACED; - if(cyblafb_check_var(&info->var,info)) { - // 640x480-8@75 should really never fail. One case would + if (cyblafb_check_var(&info->var, info)) { + // 640x480 - 8@75 should really never fail. One case would // be fp == 1 and nativex < 640 ... give up then - if(i==1 && bpp == 8 && ref == 75){ + if (i == 1 && bpp == 8 && ref == 75) { output("Can't find a valid mode :-(\n"); return -EINVAL; } // Our detected mode is unlikely to fail. If it does, - // try 640x480-8@75 ... - if(i==0) { - mode="640x480"; - bpp=8; - ref=75; + // try 640x480 - 8@75 ... + if (i == 0) { + mode = "640x480"; + bpp = 8; + ref = 75; output("Detected mode failed check_var! " - "Trying 640x480-8@75\n"); + "Trying 640x480 - 8@75\n"); goto tryagain; } // A specified video mode failed for some reason. // Try the startup mode first output("Specified mode '%s' failed check! " - "Falling back to startup mode.\n",mode); - mode=NULL; + "Falling back to startup mode.\n", mode); + mode = NULL; goto tryagain; } return 0; - } //======================================================== @@ -1160,21 +1353,28 @@ static unsigned int __devinit get_memsize(void) else { tmp = read3X4(CR1F) & 0x0F; switch (tmp) { - case 0x03: k = 1 * Mb; break; - case 0x07: k = 2 * Mb; break; - case 0x0F: k = 4 * Mb; break; - case 0x04: k = 8 * Mb; break; - default: - k = 1 * Mb; - output("Unknown memory size code %x in CR1F." - " We default to 1 Mb for now, please" - " do provide a memsize parameter!\n", - tmp); + case 0x03: + k = 1 * 1024 * 1024; + break; + case 0x07: + k = 2 * 1024 * 1024; + break; + case 0x0F: + k = 4 * 1024 * 1024; + break; + case 0x04: + k = 8 * 1024 * 1024; + break; + default: + k = 1 * 1024 * 1024; + output("Unknown memory size code %x in CR1F." + " We default to 1 Mb for now, please" + " do provide a memsize parameter!\n", tmp); } } if (verbosity > 0) - output("framebuffer size = %d Kb\n",k/Kb); + output("framebuffer size = %d Kb\n", k / Kb); return k; } @@ -1192,7 +1392,7 @@ static unsigned int __devinit get_displaytype(void) return DISPLAY_FP; if (crt) return DISPLAY_CRT; - return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT; + return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT; } //===================================== @@ -1203,7 +1403,7 @@ static unsigned int __devinit get_displaytype(void) static int __devinit get_nativex(void) { - int x,y,tmp; + int x, y, tmp; if (nativex) return nativex; @@ -1211,29 +1411,45 @@ static int __devinit get_nativex(void) tmp = (read3CE(GR52) >> 4) & 3; switch (tmp) { - case 0: x = 1280; y = 1024; break; - case 2: x = 1024; y = 768; break; - case 3: x = 800; y = 600; break; - case 4: x = 1400; y = 1050; break; - case 1: - default: x = 640; y = 480; break; + case 0: x = 1280; y = 1024; + break; + case 2: x = 1024; y = 768; + break; + case 3: x = 800; y = 600; + break; + case 4: x = 1400; y = 1050; + break; + case 1: + default: + x = 640; y = 480; + break; } if (verbosity > 0) - output("%dx%d flat panel found\n",x,y); + output("%dx%d flat panel found\n", x, y); return x; } -static int __devinit cybla_pci_probe(struct pci_dev * dev, - const struct pci_device_id * id) +static int __devinit cybla_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { struct fb_info *info; struct cyblafb_par *par; - info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev); - + info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev); if (!info) - goto errout_alloc; + goto errout_alloc_info; + + info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL); + if (!info->pixmap.addr) { + output("allocation of pixmap buffer failed!\n"); + goto errout_alloc_pixmap; + } + info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4; + info->pixmap.buf_align = 4; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->pixmap.scan_align = 4; par = info->par; par->ops = cyblafb_ops; @@ -1246,26 +1462,31 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev, output("could not enable device!\n"); goto errout_enable; } - // might already be requested by vga console or vesafb, // so we do care about success - request_region(0x3c0,32,"cyblafb"); + if (!request_region(0x3c0, 0x20, "cyblafb")) { + output("region 0x3c0/0x20 already reserved\n"); + vesafb |= 1; + } // // Graphics Engine Registers // - request_region(GEBase,0x100,"cyblafb"); + if (!request_region(GEBase, 0x100, "cyblafb")) { + output("region %#x/0x100 already reserved\n", GEBase); + vesafb |= 2; + } regdump(par); enable_mmio(); // setup MMIO region - info->fix.mmio_start = pci_resource_start(dev,1); + info->fix.mmio_start = pci_resource_start(dev, 1); info->fix.mmio_len = 0x20000; if (!request_mem_region(info->fix.mmio_start, - info->fix.mmio_len,"cyblafb")) { + info->fix.mmio_len, "cyblafb")) { output("request_mem_region failed for mmio region!\n"); goto errout_mmio_reqmem; } @@ -1276,18 +1497,17 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev, output("ioremap failed for mmio region\n"); goto errout_mmio_remap; } - // setup framebuffer memory ... might already be requested // by vesafb. Not to fail in case of an unsuccessful request - // is useful for the development cycle - info->fix.smem_start = pci_resource_start(dev,0); + // is useful if both are loaded. + info->fix.smem_start = pci_resource_start(dev, 0); info->fix.smem_len = get_memsize(); if (!request_mem_region(info->fix.smem_start, - info->fix.smem_len,"cyblafb")) { - output("request_mem_region failed for smem region!\n"); - if (!vesafb) - goto errout_smem_req; + info->fix.smem_len, "cyblafb")) { + output("region %#lx/%#x already reserved\n", + info->fix.smem_start, info->fix.smem_len); + vesafb |= 4; } info->screen_base = ioremap_nocache(info->fix.smem_start, @@ -1300,31 +1520,30 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev, displaytype = get_displaytype(); - if(displaytype == DISPLAY_FP) + if (displaytype == DISPLAY_FP) nativex = get_nativex(); - // - // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?) - // FBINFO_PARTIAL_PAN_OK .... is not ok - // FBINFO_READS_FAST .... is necessary for optimal scrolling - // - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN - | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT - | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST; + info->flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_IMAGEBLIT + | FBINFO_READS_FAST +// | FBINFO_PARTIAL_PAN_OK + | FBINFO_MISC_ALWAYS_SETPAR; info->pseudo_palette = par->pseudo_pal; - if(getstartupmode(info)) + if (getstartupmode(info)) goto errout_findmode; - fb_alloc_cmap(&info->cmap,256,0); + fb_alloc_cmap(&info->cmap, 256, 0); if (register_framebuffer(info)) { output("Could not register CyBla framebuffer\n"); goto errout_register; } - pci_set_drvdata(dev,info); + pci_set_drvdata(dev, info); // // normal exit and error paths @@ -1332,23 +1551,24 @@ static int __devinit cybla_pci_probe(struct pci_dev * dev, return 0; - errout_register: - errout_findmode: + errout_register: + errout_findmode: iounmap(info->screen_base); - errout_smem_remap: - release_mem_region(info->fix.smem_start, - info->fix.smem_len); - errout_smem_req: + errout_smem_remap: + if (!(vesafb & 4)) + release_mem_region(info->fix.smem_start, info->fix.smem_len); iounmap(io_virt); - errout_mmio_remap: - release_mem_region(info->fix.mmio_start, - info->fix.mmio_len); - errout_mmio_reqmem: -// release_region(0x3c0,32); - errout_enable: + errout_mmio_remap: + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); + errout_mmio_reqmem: + if (!(vesafb & 1)) + release_region(0x3c0, 32); + errout_enable: + kfree(info->pixmap.addr); + errout_alloc_pixmap: framebuffer_release(info); - errout_alloc: - output("CyblaFB version %s aborting init.\n",VERSION); + errout_alloc_info: + output("CyblaFB version %s aborting init.\n", VERSION); return -ENODEV; } @@ -1359,35 +1579,41 @@ static void __devexit cybla_pci_remove(struct pci_dev *dev) unregister_framebuffer(info); iounmap(io_virt); iounmap(info->screen_base); - release_mem_region(info->fix.smem_start,info->fix.smem_len); - release_mem_region(info->fix.mmio_start,info->fix.mmio_len); + if (!(vesafb & 4)) + release_mem_region(info->fix.smem_start, info->fix.smem_len); + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); fb_dealloc_cmap(&info->cmap); + if (!(vesafb & 2)) + release_region(GEBase, 0x100); + if (!(vesafb & 1)) + release_region(0x3c0, 32); + kfree(info->pixmap.addr); framebuffer_release(info); - output("CyblaFB version %s normal exit.\n",VERSION); + output("CyblaFB version %s normal exit.\n", VERSION); } // // List of boards that we are trying to support // static struct pci_device_id cybla_devices[] = { - {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} }; -MODULE_DEVICE_TABLE(pci,cybla_devices); +MODULE_DEVICE_TABLE(pci, cybla_devices); static struct pci_driver cyblafb_pci_driver = { - .name = "cyblafb", - .id_table = cybla_devices, - .probe = cybla_pci_probe, - .remove = __devexit_p(cybla_pci_remove) + .name = "cyblafb", + .id_table = cybla_devices, + .probe = cybla_pci_probe, + .remove = __devexit_p(cybla_pci_remove) }; //============================================================= // // kernel command line example: // -// video=cyblafb:1280x1024,bpp=16,ref=50 ... +// video=cyblafb:1280x1024, bpp=16, ref=50 ... // // modprobe command line example: // @@ -1401,45 +1627,44 @@ static int __devinit cyblafb_init(void) char *options = NULL; char *opt; - if (fb_get_options("cyblafb",&options)) + if (fb_get_options("cyblafb", &options)) return -ENODEV; if (options && *options) - while((opt = strsep(&options,",")) != NULL ) { - if (!*opt) continue; - else if (!strncmp(opt,"bpp=",4)) - bpp = simple_strtoul(opt+4,NULL,0); - else if (!strncmp(opt,"ref=",4)) - ref = simple_strtoul(opt+4,NULL,0); - else if (!strncmp(opt,"fp",2)) + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + else if (!strncmp(opt, "bpp=", 4)) + bpp = simple_strtoul(opt + 4, NULL, 0); + else if (!strncmp(opt, "ref=", 4)) + ref = simple_strtoul(opt + 4, NULL, 0); + else if (!strncmp(opt, "fp", 2)) displaytype = DISPLAY_FP; - else if (!strncmp(opt,"crt",3)) + else if (!strncmp(opt, "crt", 3)) displaytype = DISPLAY_CRT; - else if (!strncmp(opt,"nativex=",8)) - nativex = simple_strtoul(opt+8,NULL,0); - else if (!strncmp(opt,"center",6)) + else if (!strncmp(opt, "nativex=", 8)) + nativex = simple_strtoul(opt + 8, NULL, 0); + else if (!strncmp(opt, "center", 6)) center = 1; - else if (!strncmp(opt,"stretch",7)) + else if (!strncmp(opt, "stretch", 7)) stretch = 1; - else if (!strncmp(opt,"pciwb=",6)) - pciwb = simple_strtoul(opt+6,NULL,0); - else if (!strncmp(opt,"pcirb=",6)) - pcirb = simple_strtoul(opt+6,NULL,0); - else if (!strncmp(opt,"pciwr=",6)) - pciwr = simple_strtoul(opt+6,NULL,0); - else if (!strncmp(opt,"pcirr=",6)) - pcirr = simple_strtoul(opt+6,NULL,0); - else if (!strncmp(opt,"memsize=",8)) - memsize = simple_strtoul(opt+8,NULL,0); - else if (!strncmp(opt,"verbosity=",10)) - verbosity = simple_strtoul(opt+10,NULL,0); - else if (!strncmp(opt,"vesafb",6)) - vesafb = 1; + else if (!strncmp(opt, "pciwb=", 6)) + pciwb = simple_strtoul(opt + 6, NULL, 0); + else if (!strncmp(opt, "pcirb=", 6)) + pcirb = simple_strtoul(opt + 6, NULL, 0); + else if (!strncmp(opt, "pciwr=", 6)) + pciwr = simple_strtoul(opt + 6, NULL, 0); + else if (!strncmp(opt, "pcirr=", 6)) + pcirr = simple_strtoul(opt + 6, NULL, 0); + else if (!strncmp(opt, "memsize=", 8)) + memsize = simple_strtoul(opt + 8, NULL, 0); + else if (!strncmp(opt, "verbosity=", 10)) + verbosity = simple_strtoul(opt + 10, NULL, 0); else mode = opt; } #endif - output("CyblaFB version %s initializing\n",VERSION); + output("CyblaFB version %s initializing\n", VERSION); return pci_module_init(&cyblafb_pci_driver); } |